… | |
… | |
13 | mutex_t lock; /* global loop lock */ |
13 | mutex_t lock; /* global loop lock */ |
14 | void (*signal_func) (void *signal_arg, int value); |
14 | void (*signal_func) (void *signal_arg, int value); |
15 | void *signal_arg; |
15 | void *signal_arg; |
16 | ev_async async_w; |
16 | ev_async async_w; |
17 | thread_t tid; |
17 | thread_t tid; |
|
|
18 | unsigned int max_loops; |
|
|
19 | unsigned int count; |
18 | |
20 | |
19 | cond_t invoke_cv; |
21 | cond_t invoke_cv; |
20 | |
22 | |
21 | SV *interrupt; |
23 | SV *interrupt; |
22 | } udat; |
24 | } udat; |
23 | |
25 | |
|
|
26 | static void loop_set_cb (EV_P); |
|
|
27 | |
|
|
28 | static void |
|
|
29 | fg_invoke_pending (EV_P) |
|
|
30 | { |
|
|
31 | udat *u = ev_userdata (EV_A); |
|
|
32 | |
|
|
33 | u->count = ev_pending_count (EV_A); |
|
|
34 | |
|
|
35 | if (u->count) |
|
|
36 | ev_invoke_pending (EV_A); |
|
|
37 | } |
|
|
38 | |
24 | static void |
39 | static void |
25 | c_func (pTHX_ void *loop_, int value) |
40 | c_func (pTHX_ void *loop_, int value) |
26 | { |
41 | { |
27 | struct ev_loop *loop = (struct ev_loop *)loop_; |
42 | struct ev_loop *loop = (struct ev_loop *)loop_; |
28 | udat *u = ev_userdata (EV_A); |
43 | udat *u = ev_userdata (EV_A); |
|
|
44 | int i; |
|
|
45 | |
29 | X_LOCK (u->lock); |
46 | X_LOCK (u->lock); |
30 | ev_invoke_pending (loop); |
47 | ev_invoke_pending (EV_A); |
|
|
48 | |
|
|
49 | /* do any additional foreground loop runs */ |
|
|
50 | for (i = u->max_loops; i--; ) |
|
|
51 | { |
|
|
52 | /* this is a bit tricky, but we can manage... */ |
|
|
53 | u->count = 0; |
|
|
54 | |
|
|
55 | ev_set_invoke_pending_cb (EV_A, fg_invoke_pending); |
|
|
56 | ev_set_loop_release_cb (EV_A, 0, 0); |
|
|
57 | ev_loop (EV_A, EVLOOP_NONBLOCK); |
|
|
58 | loop_set_cb (EV_A); |
|
|
59 | |
|
|
60 | if (!u->count) |
|
|
61 | break; |
|
|
62 | } |
|
|
63 | |
31 | X_COND_SIGNAL (u->invoke_cv); |
64 | X_COND_SIGNAL (u->invoke_cv); |
32 | X_UNLOCK (u->lock); |
65 | X_UNLOCK (u->lock); |
33 | } |
66 | } |
34 | |
67 | |
35 | static void |
68 | static void |
… | |
… | |
54 | |
87 | |
55 | static void |
88 | static void |
56 | l_invoke (EV_P) |
89 | l_invoke (EV_P) |
57 | { |
90 | { |
58 | udat *u = ev_userdata (EV_A); |
91 | udat *u = ev_userdata (EV_A); |
|
|
92 | |
|
|
93 | while (ev_pending_count (EV_A)) |
|
|
94 | { |
59 | u->signal_func (u->signal_arg, 1); |
95 | u->signal_func (u->signal_arg, 1); |
60 | X_COND_WAIT (u->invoke_cv, u->lock); |
96 | X_COND_WAIT (u->invoke_cv, u->lock); |
|
|
97 | } |
|
|
98 | } |
|
|
99 | |
|
|
100 | static void |
|
|
101 | loop_set_cb (EV_P) |
|
|
102 | { |
|
|
103 | ev_set_invoke_pending_cb (EV_A, l_invoke); |
|
|
104 | ev_set_loop_release_cb (EV_A, l_release, l_acquire); |
61 | } |
105 | } |
62 | |
106 | |
63 | X_THREAD_PROC(l_run) |
107 | X_THREAD_PROC(l_run) |
64 | { |
108 | { |
65 | struct ev_loop *loop = (struct ev_loop *)thr_arg; |
109 | struct ev_loop *loop = (struct ev_loop *)thr_arg; |
… | |
… | |
80 | |
124 | |
81 | static void |
125 | static void |
82 | scope_lock_cb (pTHX_ void *loop_) |
126 | scope_lock_cb (pTHX_ void *loop_) |
83 | { |
127 | { |
84 | struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_); |
128 | struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_); |
85 | udat *u = ev_userdata (loop); |
129 | udat *u = ev_userdata (EV_A); |
86 | |
130 | |
87 | X_UNLOCK (u->lock); |
131 | X_UNLOCK (u->lock); |
88 | SvREFCNT_dec ((SV *)loop_); |
132 | SvREFCNT_dec ((SV *)loop_); |
89 | } |
133 | } |
90 | |
134 | |
… | |
… | |
117 | u->interrupt = newSVsv (interrupt); |
161 | u->interrupt = newSVsv (interrupt); |
118 | u->signal_func = (void (*)(void *, int))sig_func; |
162 | u->signal_func = (void (*)(void *, int))sig_func; |
119 | u->signal_arg = sig_arg; |
163 | u->signal_arg = sig_arg; |
120 | |
164 | |
121 | ev_async_init (&u->async_w, async_cb); |
165 | ev_async_init (&u->async_w, async_cb); |
122 | ev_async_start (loop, &u->async_w); |
166 | ev_async_start (EV_A, &u->async_w); |
123 | |
167 | |
124 | pthread_mutexattr_init (&ma); |
168 | pthread_mutexattr_init (&ma); |
125 | pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE); |
169 | pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE); |
126 | pthread_mutex_init (&u->lock, &ma); |
170 | pthread_mutex_init (&u->lock, &ma); |
127 | pthread_mutexattr_destroy (&ma); |
171 | pthread_mutexattr_destroy (&ma); |
128 | |
172 | |
129 | pthread_cond_init (&u->invoke_cv, 0); |
173 | pthread_cond_init (&u->invoke_cv, 0); |
130 | |
174 | |
131 | ev_set_userdata (loop, u); |
175 | ev_set_userdata (EV_A, u); |
132 | ev_set_invoke_pending_cb (loop, l_invoke); |
176 | loop_set_cb (EV_A); |
133 | ev_set_loop_release_cb (loop, l_release, l_acquire); |
|
|
134 | |
177 | |
135 | thread_create (&u->tid, l_run, loop); |
178 | thread_create (&u->tid, l_run, loop); |
136 | } |
179 | } |
137 | |
180 | |
138 | SV * |
181 | SV * |
139 | interrupt (SV *loop_) |
182 | interrupt (SV *loop_) |
140 | CODE: |
183 | CODE: |
141 | { |
184 | { |
142 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
185 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
143 | udat *u = ev_userdata (loop); |
186 | udat *u = ev_userdata (EV_A); |
144 | |
187 | |
145 | RETVAL = newSVsv (u->interrupt); |
188 | RETVAL = newSVsv (u->interrupt); |
146 | } |
189 | } |
147 | OUTPUT: |
190 | OUTPUT: |
148 | RETVAL |
191 | RETVAL |
|
|
192 | |
|
|
193 | void |
|
|
194 | set_max_foreground_loops (SV *loop_, UV max_loops) |
|
|
195 | CODE: |
|
|
196 | { |
|
|
197 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
|
|
198 | udat *u = ev_userdata (EV_A); |
|
|
199 | |
|
|
200 | u->max_loops = max_loops; |
|
|
201 | } |
149 | |
202 | |
150 | void |
203 | void |
151 | lock (SV *loop_) |
204 | lock (SV *loop_) |
152 | ALIAS: |
205 | ALIAS: |
153 | lock = 0 |
206 | lock = 0 |
154 | unlock = 1 |
207 | unlock = 1 |
155 | notify = 2 |
208 | notify = 2 |
156 | CODE: |
209 | CODE: |
157 | { |
210 | { |
158 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
211 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
159 | udat *u = ev_userdata (loop); |
212 | udat *u = ev_userdata (EV_A); |
160 | |
213 | |
161 | switch (ix) |
214 | switch (ix) |
162 | { |
215 | { |
163 | case 0: X_LOCK (u->lock); break; |
216 | case 0: X_LOCK (u->lock); break; |
164 | case 1: X_UNLOCK (u->lock); break; |
217 | case 1: X_UNLOCK (u->lock); break; |
165 | case 2: ev_async_send (loop, &u->async_w); break; |
218 | case 2: ev_async_send (EV_A, &u->async_w); break; |
166 | } |
219 | } |
167 | } |
220 | } |
168 | |
221 | |
169 | void |
222 | void |
170 | scope_lock (SV *loop_) |
223 | scope_lock (SV *loop_) |
171 | CODE: |
224 | CODE: |
172 | { |
225 | { |
173 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
226 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
174 | udat *u = ev_userdata (loop); |
227 | udat *u = ev_userdata (EV_A); |
175 | |
228 | |
176 | X_LOCK (u->lock); |
229 | X_LOCK (u->lock); |
177 | |
230 | |
178 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
231 | LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */ |
179 | SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_))); |
232 | SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_))); |
… | |
… | |
183 | void |
236 | void |
184 | DESTROY (SV *loop_) |
237 | DESTROY (SV *loop_) |
185 | CODE: |
238 | CODE: |
186 | { |
239 | { |
187 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
240 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
188 | udat *u = ev_userdata (loop); |
241 | udat *u = ev_userdata (EV_A); |
189 | |
242 | |
190 | if (u) |
243 | if (u) |
191 | { |
244 | { |
192 | X_LOCK (u->lock); |
245 | X_LOCK (u->lock); |
193 | ev_async_stop (loop, &u->async_w); |
246 | ev_async_stop (EV_A, &u->async_w); |
194 | /* now thread is around blocking call, or in pthread_cond_wait */ |
247 | /* now thread is around blocking call, or in pthread_cond_wait */ |
195 | pthread_cancel (u->tid); |
248 | pthread_cancel (u->tid); |
196 | pthread_mutex_destroy (&u->lock); |
249 | pthread_mutex_destroy (&u->lock); |
197 | pthread_cond_destroy (&u->invoke_cv); |
250 | pthread_cond_destroy (&u->invoke_cv); |
198 | SvREFCNT_dec (u->interrupt); |
251 | SvREFCNT_dec (u->interrupt); |