ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-Loop-Async/Async.xs
(Generate patch)

Comparing EV-Loop-Async/Async.xs (file contents):
Revision 1.2 by root, Tue Jul 14 13:24:34 2009 UTC vs.
Revision 1.12 by root, Mon Nov 1 22:26:53 2010 UTC

1#include "xthread.h"
2
3#include <errno.h>
4
1#include "EXTERN.h" 5#include "EXTERN.h"
2#include "perl.h" 6#include "perl.h"
3#include "XSUB.h" 7#include "XSUB.h"
4 8
5#include <stddef.h> 9#include <stddef.h>
6 10
7#include "EVAPI.h" 11#include "EVAPI.h"
8#include "xthread.h"
9 12
10/* our userdata */ 13/* our userdata */
11typedef struct { 14typedef struct {
12 mutex_t lock; /* global loop lock */ 15 xmutex_t lock; /* global loop lock */
13 void (*signal_func) (void *signal_arg, int value); 16 void (*signal_func) (void *signal_arg, int value);
14 void *signal_arg; 17 void *signal_arg;
15 ev_async async_w; 18 ev_async async_w;
16 thread_t tid; 19 xthread_t tid;
20 unsigned int max_loops;
21 unsigned int count;
17 22
18 cond_t invoke_cv; 23 xcond_t invoke_cv;
19 mutex_t invoke_mutex;
20 24
21 SV *interrupt; 25 SV *interrupt;
26#if defined(_WIN32) && defined(USE_ITHREADS)
27 void *thx;
28#endif
22} udat; 29} udat;
23 30
31static void loop_set_cb (EV_P);
32
33static void
34fg_invoke_pending (EV_P)
35{
36 udat *u = ev_userdata (EV_A);
37
38 u->count = ev_pending_count (EV_A);
39
40 if (u->count)
41 ev_invoke_pending (EV_A);
42}
43
24static void 44static void
25c_func (pTHX_ void *loop_, int value) 45c_func (pTHX_ void *loop_, int value)
26{ 46{
27 struct ev_loop *loop = (struct ev_loop *)loop_; 47 struct ev_loop *loop = (struct ev_loop *)loop_;
28 udat *u = ev_userdata (EV_A); 48 udat *u = ev_userdata (EV_A);
49 int i;
50
29 X_LOCK (u->lock); 51 X_LOCK (u->lock);
30 ev_invoke_pending (loop); 52 ev_invoke_pending (EV_A);
53
54 /* do any additional foreground loop runs */
55 for (i = u->max_loops; i--; )
56 {
57 /* this is a bit tricky, but we can manage... */
58 u->count = 0;
59
60 ev_set_invoke_pending_cb (EV_A, fg_invoke_pending);
61 ev_set_loop_release_cb (EV_A, 0, 0);
62 ev_run (EV_A, EVRUN_NOWAIT);
63 loop_set_cb (EV_A);
64
65 if (!u->count)
66 break;
67 }
68
69 X_COND_SIGNAL (u->invoke_cv);
31 X_UNLOCK (u->lock); 70 X_UNLOCK (u->lock);
32 X_COND_SIGNAL (u->invoke_cv);
33} 71}
34 72
35static void 73static void
36async_cb (EV_P_ ev_async *w, int revents) 74async_cb (EV_P_ ev_async *w, int revents)
37{ 75{
54 92
55static void 93static void
56l_invoke (EV_P) 94l_invoke (EV_P)
57{ 95{
58 udat *u = ev_userdata (EV_A); 96 udat *u = ev_userdata (EV_A);
59 X_UNLOCK (u->lock); 97
98 while (ev_pending_count (EV_A))
99 {
60 u->signal_func (u->signal_arg, 1); 100 u->signal_func (u->signal_arg, 1);
61 X_COND_WAIT (u->invoke_cv, u->invoke_mutex); 101 X_COND_WAIT (u->invoke_cv, u->lock);
62 X_LOCK (u->lock); 102 }
103}
104
105static void
106loop_set_cb (EV_P)
107{
108 ev_set_invoke_pending_cb (EV_A, l_invoke);
109 ev_set_loop_release_cb (EV_A, l_release, l_acquire);
63} 110}
64 111
65X_THREAD_PROC(l_run) 112X_THREAD_PROC(l_run)
66{ 113{
67 struct ev_loop *loop = (struct ev_loop *)thr_arg; 114 struct ev_loop *loop = (struct ev_loop *)thr_arg;
115#if defined(_WIN32) && defined(USE_ITHREADS)
68 udat *u = ev_userdata (loop); 116 udat *u = ev_userdata (EV_A);
69 117
70 X_LOCK (u->invoke_mutex); 118 /* just setting the same context pointer as the other thread is */
71 X_LOCK (u->lock); 119 /* probably fatal, yet, I have no clue what makes libev crash (malloc?) */
72 ev_ref (loop); /* really? */ 120 /* as visual c also crashes when it tries to debug the crash */
73 for (;;) /* really? */ 121 /* the loser platform is indeed a crashy OS */
74 ev_loop (loop, 0); 122 PERL_SET_CONTEXT (u->thx);
75 X_UNLOCK (u->lock); 123#endif
124
125 l_acquire (EV_A);
126
127 /* yeah */
128 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
129
130 ev_ref (EV_A);
131 ev_run (EV_A, 0);
132 ev_unref (EV_A);
133
134 l_release (EV_A);
135
136 return 0;
76} 137}
77 138
78static void 139static void
79scope_lock_cb (pTHX_ void *loop_) 140scope_lock_cb (pTHX_ void *loop_)
80{ 141{
81 struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_); 142 struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_);
82 udat *u = ev_userdata (loop); 143 udat *u = ev_userdata (EV_A);
83 144
84 X_UNLOCK (u->lock); 145 X_UNLOCK (u->lock);
85 SvREFCNT_dec ((SV *)loop_); 146 SvREFCNT_dec ((SV *)loop_);
86} 147}
87 148
90PROTOTYPES: ENABLE 151PROTOTYPES: ENABLE
91 152
92BOOT: 153BOOT:
93{ 154{
94 I_EV_API ("EV::Loop::Async"); 155 I_EV_API ("EV::Loop::Async");
156 CvNODEBUG_on (get_cv ("EV::Loop::Async::scope_lock", 0)); /* otherwise calling scope can be the debugger */
95} 157}
96 158
97void 159void
98_c_func (SV *loop) 160_c_func (SV *loop)
99 PPCODE: 161 PPCODE:
101 PUSHs (sv_2mortal (newSViv (PTR2IV (c_func)))); 163 PUSHs (sv_2mortal (newSViv (PTR2IV (c_func))));
102 PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop))))); 164 PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop)))));
103 165
104void 166void
105_attach (SV *loop_, SV *interrupt, IV sig_func, void *sig_arg) 167_attach (SV *loop_, SV *interrupt, IV sig_func, void *sig_arg)
168 PROTOTYPE: @
106 CODE: 169 CODE:
107{ 170{
108 pthread_mutexattr_t ma; 171 pthread_mutexattr_t ma;
109 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); 172 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
110 udat *u; 173 udat *u;
111 174
112 Newz (0, u, 1, udat); 175 Newz (0, u, 1, udat);
113 u->interrupt = newSVsv (interrupt); 176 u->interrupt = newSVsv (interrupt);
114 u->signal_func = (void (*)(void *, int))sig_func; 177 u->signal_func = (void (*)(void *, int))sig_func;
115 u->signal_arg = sig_arg; 178 u->signal_arg = sig_arg;
179#if defined(_WIN32) && defined(USE_ITHREADS)
180 u->thx = PERL_GET_CONTEXT;
181#endif
116 182
117 ev_async_init (&u->async_w, async_cb); 183 ev_async_init (&u->async_w, async_cb);
118 ev_async_start (loop, &u->async_w); 184 ev_async_start (EV_A, &u->async_w);
119 185
120 pthread_mutexattr_init (&ma); 186 pthread_mutexattr_init (&ma);
187#ifdef PTHREAD_MUTEX_RECURSIVE
121 pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE); 188 pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE);
189#else
190 pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE_NP);
191#endif
122 pthread_mutex_init (&u->lock, &ma); 192 pthread_mutex_init (&u->lock, &ma);
123 pthread_mutex_init (&u->invoke_mutex, &ma);
124 pthread_mutexattr_destroy (&ma); 193 pthread_mutexattr_destroy (&ma);
125 194
126 pthread_cond_init (&u->invoke_cv, 0); 195 pthread_cond_init (&u->invoke_cv, 0);
127 196
128 ev_set_userdata (loop, u); 197 ev_set_userdata (EV_A, u);
129 ev_set_invoke_pending_cb (loop, l_invoke); 198 loop_set_cb (EV_A);
130 ev_set_loop_release_cb (loop, l_release, l_acquire);
131 199
132 thread_create (&u->tid, l_run, (void *)loop); 200 thread_create (&u->tid, l_run, loop);
133} 201}
134 202
135SV * 203SV *
136interrupt (SV *loop_) 204interrupt (SV *loop_)
137 CODE: 205 CODE:
138{ 206{
139 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); 207 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
140 udat *u = ev_userdata (loop); 208 udat *u = ev_userdata (EV_A);
141 209
142 RETVAL = newSVsv (u->interrupt); 210 RETVAL = newSVsv (u->interrupt);
143} 211}
144 OUTPUT: 212 OUTPUT:
145 RETVAL 213 RETVAL
214
215void
216set_max_foreground_loops (SV *loop_, UV max_loops)
217 CODE:
218{
219 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
220 udat *u = ev_userdata (EV_A);
221
222 u->max_loops = max_loops;
223}
146 224
147void 225void
148lock (SV *loop_) 226lock (SV *loop_)
149 ALIAS: 227 ALIAS:
150 lock = 0 228 lock = 0
151 unlock = 1 229 unlock = 1
152 poke = 2 230 notify = 2
153 CODE: 231 CODE:
154{ 232{
155 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); 233 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
156 udat *u = ev_userdata (loop); 234 udat *u = ev_userdata (EV_A);
157 235
158 switch (ix) 236 switch (ix)
159 { 237 {
160 case 0: X_LOCK (u->lock); break; 238 case 0: X_LOCK (u->lock); break;
161 case 1: X_UNLOCK (u->lock); break; 239 case 1: X_UNLOCK (u->lock); break;
162 case 2: ev_async_send (loop, &u->async_w); break; 240 case 2: ev_async_send (EV_A, &u->async_w); break;
163 } 241 }
164} 242}
165 243
166void 244void
167scope_lock (SV *loop_) 245scope_lock (SV *loop_)
168 CODE: 246 CODE:
169{ 247{
170 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); 248 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
171 udat *u = ev_userdata (loop); 249 udat *u = ev_userdata (EV_A);
172 250
173 X_LOCK (u->lock); 251 X_LOCK (u->lock);
174 252
175 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ 253 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
176 SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_))); 254 SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_)));
180void 258void
181DESTROY (SV *loop_) 259DESTROY (SV *loop_)
182 CODE: 260 CODE:
183{ 261{
184 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); 262 struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
185 udat *u = ev_userdata (loop); 263 udat *u = ev_userdata (EV_A);
186 264
187 if (u) 265 if (u)
188 { 266 {
189 X_LOCK (u->lock); 267 X_LOCK (u->lock);
190 ev_async_send (loop, &u->async_w); 268 ev_async_stop (EV_A, &u->async_w);
269 /* now thread is around blocking call, or in pthread_cond_wait */
191 pthread_cancel (u->tid); 270 pthread_cancel (u->tid);
192 ev_async_stop (loop, &u->async_w); 271 X_UNLOCK (u->lock);
193 pthread_mutex_destroy (&u->lock); 272 pthread_mutex_destroy (&u->lock);
194 pthread_cond_destroy (&u->invoke_cv); 273 pthread_cond_destroy (&u->invoke_cv);
195 pthread_mutex_destroy (&u->invoke_mutex); 274 SvREFCNT_dec (u->interrupt);
196 Safefree (u); 275 Safefree (u);
197 SvREFCNT_dec (u->interrupt);
198 } 276 }
199} 277}
200 278
201 279
202 280

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines