1 | #include "xthread.h" |
1 | #include "xthread.h" |
|
|
2 | |
|
|
3 | #include <errno.h> |
2 | |
4 | |
3 | #include "EXTERN.h" |
5 | #include "EXTERN.h" |
4 | #include "perl.h" |
6 | #include "perl.h" |
5 | #include "XSUB.h" |
7 | #include "XSUB.h" |
6 | |
8 | |
… | |
… | |
8 | |
10 | |
9 | #include "EVAPI.h" |
11 | #include "EVAPI.h" |
10 | |
12 | |
11 | /* our userdata */ |
13 | /* our userdata */ |
12 | typedef struct { |
14 | typedef struct { |
13 | mutex_t lock; /* global loop lock */ |
15 | xmutex_t lock; /* global loop lock */ |
14 | void (*signal_func) (void *signal_arg, int value); |
16 | void (*signal_func) (void *signal_arg, int value); |
15 | void *signal_arg; |
17 | void *signal_arg; |
16 | ev_async async_w; |
18 | ev_async async_w; |
17 | thread_t tid; |
19 | xthread_t tid; |
18 | unsigned int max_loops; |
20 | unsigned int max_loops; |
19 | unsigned int count; |
21 | unsigned int count; |
20 | |
22 | |
21 | cond_t invoke_cv; |
23 | xcond_t invoke_cv; |
22 | |
24 | |
23 | SV *interrupt; |
25 | SV *interrupt; |
|
|
26 | #if defined(_WIN32) && defined(USE_ITHREADS) |
|
|
27 | void *thx; |
|
|
28 | #endif |
24 | } udat; |
29 | } udat; |
25 | |
30 | |
26 | static void loop_set_cb (EV_P); |
31 | static void loop_set_cb (EV_P); |
27 | |
32 | |
28 | static void |
33 | static void |
… | |
… | |
52 | /* this is a bit tricky, but we can manage... */ |
57 | /* this is a bit tricky, but we can manage... */ |
53 | u->count = 0; |
58 | u->count = 0; |
54 | |
59 | |
55 | ev_set_invoke_pending_cb (EV_A, fg_invoke_pending); |
60 | ev_set_invoke_pending_cb (EV_A, fg_invoke_pending); |
56 | ev_set_loop_release_cb (EV_A, 0, 0); |
61 | ev_set_loop_release_cb (EV_A, 0, 0); |
57 | ev_loop (EV_A, EVLOOP_NONBLOCK); |
62 | ev_run (EV_A, EVRUN_NOWAIT); |
58 | loop_set_cb (EV_A); |
63 | loop_set_cb (EV_A); |
59 | |
64 | |
60 | if (!u->count) |
65 | if (!u->count) |
61 | break; |
66 | break; |
62 | } |
67 | } |
… | |
… | |
105 | } |
110 | } |
106 | |
111 | |
107 | X_THREAD_PROC(l_run) |
112 | X_THREAD_PROC(l_run) |
108 | { |
113 | { |
109 | 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) |
|
|
116 | udat *u = ev_userdata (EV_A); |
|
|
117 | |
|
|
118 | /* just setting the same context pointer as the other thread is */ |
|
|
119 | /* probably fatal, yet, I have no clue what makes libev crash (malloc?) */ |
|
|
120 | /* as visual c also crashes when it tries to debug the crash */ |
|
|
121 | /* the loser platform is indeed a crashy OS */ |
|
|
122 | PERL_SET_CONTEXT (u->thx); |
|
|
123 | #endif |
110 | |
124 | |
111 | l_acquire (EV_A); |
125 | l_acquire (EV_A); |
112 | |
126 | |
113 | /* yeah */ |
127 | /* yeah */ |
114 | pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); |
128 | pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); |
115 | |
129 | |
116 | ev_ref (EV_A); |
130 | ev_ref (EV_A); |
117 | ev_loop (EV_A, 0); |
131 | ev_run (EV_A, 0); |
118 | ev_unref (EV_A); |
132 | ev_unref (EV_A); |
119 | |
133 | |
120 | l_release (EV_A); |
134 | l_release (EV_A); |
121 | |
135 | |
122 | return 0; |
136 | return 0; |
… | |
… | |
149 | PUSHs (sv_2mortal (newSViv (PTR2IV (c_func)))); |
163 | PUSHs (sv_2mortal (newSViv (PTR2IV (c_func)))); |
150 | PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop))))); |
164 | PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop))))); |
151 | |
165 | |
152 | void |
166 | void |
153 | _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: @ |
154 | CODE: |
169 | CODE: |
155 | { |
170 | { |
156 | pthread_mutexattr_t ma; |
171 | pthread_mutexattr_t ma; |
157 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
172 | struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_)); |
158 | udat *u; |
173 | udat *u; |
159 | |
174 | |
160 | Newz (0, u, 1, udat); |
175 | Newz (0, u, 1, udat); |
161 | u->interrupt = newSVsv (interrupt); |
176 | u->interrupt = newSVsv (interrupt); |
162 | u->signal_func = (void (*)(void *, int))sig_func; |
177 | u->signal_func = (void (*)(void *, int))sig_func; |
163 | 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 |
164 | |
182 | |
165 | ev_async_init (&u->async_w, async_cb); |
183 | ev_async_init (&u->async_w, async_cb); |
166 | ev_async_start (EV_A, &u->async_w); |
184 | ev_async_start (EV_A, &u->async_w); |
167 | |
185 | |
168 | pthread_mutexattr_init (&ma); |
186 | pthread_mutexattr_init (&ma); |
|
|
187 | #ifdef PTHREAD_MUTEX_RECURSIVE |
169 | 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 |
170 | pthread_mutex_init (&u->lock, &ma); |
192 | pthread_mutex_init (&u->lock, &ma); |
171 | pthread_mutexattr_destroy (&ma); |
193 | pthread_mutexattr_destroy (&ma); |
172 | |
194 | |
173 | pthread_cond_init (&u->invoke_cv, 0); |
195 | pthread_cond_init (&u->invoke_cv, 0); |
174 | |
196 | |
… | |
… | |
244 | { |
266 | { |
245 | X_LOCK (u->lock); |
267 | X_LOCK (u->lock); |
246 | ev_async_stop (EV_A, &u->async_w); |
268 | ev_async_stop (EV_A, &u->async_w); |
247 | /* now thread is around blocking call, or in pthread_cond_wait */ |
269 | /* now thread is around blocking call, or in pthread_cond_wait */ |
248 | pthread_cancel (u->tid); |
270 | pthread_cancel (u->tid); |
|
|
271 | X_UNLOCK (u->lock); |
249 | pthread_mutex_destroy (&u->lock); |
272 | pthread_mutex_destroy (&u->lock); |
250 | pthread_cond_destroy (&u->invoke_cv); |
273 | pthread_cond_destroy (&u->invoke_cv); |
251 | SvREFCNT_dec (u->interrupt); |
274 | SvREFCNT_dec (u->interrupt); |
252 | Safefree (u); |
275 | Safefree (u); |
253 | } |
276 | } |