ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-Loop-Async/Async.xs
Revision: 1.13
Committed: Thu Oct 11 05:02:54 2012 UTC (11 years, 7 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +1 -1 lines
Log Message:
xthread_create

File Contents

# User Rev Content
1 root 1.7 #include "xthread.h"
2    
3 root 1.9 #include <errno.h>
4    
5 root 1.1 #include "EXTERN.h"
6     #include "perl.h"
7     #include "XSUB.h"
8    
9     #include <stddef.h>
10    
11     #include "EVAPI.h"
12    
13     /* our userdata */
14     typedef struct {
15 root 1.11 xmutex_t lock; /* global loop lock */
16 root 1.1 void (*signal_func) (void *signal_arg, int value);
17     void *signal_arg;
18     ev_async async_w;
19 root 1.11 xthread_t tid;
20 root 1.8 unsigned int max_loops;
21     unsigned int count;
22 root 1.1
23 root 1.11 xcond_t invoke_cv;
24 root 1.1
25 root 1.2 SV *interrupt;
26 root 1.10 #if defined(_WIN32) && defined(USE_ITHREADS)
27     void *thx;
28     #endif
29 root 1.1 } udat;
30    
31 root 1.8 static void loop_set_cb (EV_P);
32    
33     static void
34     fg_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    
44 root 1.1 static void
45     c_func (pTHX_ void *loop_, int value)
46     {
47     struct ev_loop *loop = (struct ev_loop *)loop_;
48     udat *u = ev_userdata (EV_A);
49 root 1.8 int i;
50    
51 root 1.1 X_LOCK (u->lock);
52 root 1.8 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 root 1.12 ev_run (EV_A, EVRUN_NOWAIT);
63 root 1.8 loop_set_cb (EV_A);
64    
65     if (!u->count)
66     break;
67     }
68    
69 root 1.5 X_COND_SIGNAL (u->invoke_cv);
70 root 1.1 X_UNLOCK (u->lock);
71     }
72    
73     static void
74     async_cb (EV_P_ ev_async *w, int revents)
75     {
76     /* just used for the side effects */
77     }
78    
79     static void
80     l_release (EV_P)
81     {
82     udat *u = ev_userdata (EV_A);
83     X_UNLOCK (u->lock);
84     }
85    
86     static void
87     l_acquire (EV_P)
88     {
89     udat *u = ev_userdata (EV_A);
90     X_LOCK (u->lock);
91     }
92    
93     static void
94     l_invoke (EV_P)
95     {
96     udat *u = ev_userdata (EV_A);
97 root 1.8
98     while (ev_pending_count (EV_A))
99     {
100     u->signal_func (u->signal_arg, 1);
101     X_COND_WAIT (u->invoke_cv, u->lock);
102     }
103     }
104    
105     static void
106     loop_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);
110 root 1.1 }
111    
112     X_THREAD_PROC(l_run)
113     {
114     struct ev_loop *loop = (struct ev_loop *)thr_arg;
115 root 1.10 #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
124 root 1.1
125 root 1.6 l_acquire (EV_A);
126    
127 root 1.5 /* yeah */
128     pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
129    
130 root 1.6 ev_ref (EV_A);
131 root 1.12 ev_run (EV_A, 0);
132 root 1.6 ev_unref (EV_A);
133 root 1.5
134 root 1.6 l_release (EV_A);
135 root 1.5
136     return 0;
137 root 1.1 }
138    
139 root 1.2 static void
140     scope_lock_cb (pTHX_ void *loop_)
141     {
142     struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_);
143 root 1.8 udat *u = ev_userdata (EV_A);
144 root 1.2
145     X_UNLOCK (u->lock);
146     SvREFCNT_dec ((SV *)loop_);
147     }
148    
149 root 1.1 MODULE = EV::Loop::Async PACKAGE = EV::Loop::Async
150    
151     PROTOTYPES: ENABLE
152    
153     BOOT:
154     {
155     I_EV_API ("EV::Loop::Async");
156 root 1.3 CvNODEBUG_on (get_cv ("EV::Loop::Async::scope_lock", 0)); /* otherwise calling scope can be the debugger */
157 root 1.1 }
158    
159     void
160     _c_func (SV *loop)
161     PPCODE:
162     EXTEND (SP, 2);
163     PUSHs (sv_2mortal (newSViv (PTR2IV (c_func))));
164     PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop)))));
165    
166     void
167 root 1.2 _attach (SV *loop_, SV *interrupt, IV sig_func, void *sig_arg)
168 root 1.11 PROTOTYPE: @
169 root 1.1 CODE:
170     {
171     pthread_mutexattr_t ma;
172     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
173     udat *u;
174    
175     Newz (0, u, 1, udat);
176 root 1.2 u->interrupt = newSVsv (interrupt);
177 root 1.1 u->signal_func = (void (*)(void *, int))sig_func;
178     u->signal_arg = sig_arg;
179 root 1.10 #if defined(_WIN32) && defined(USE_ITHREADS)
180     u->thx = PERL_GET_CONTEXT;
181     #endif
182 root 1.1
183     ev_async_init (&u->async_w, async_cb);
184 root 1.8 ev_async_start (EV_A, &u->async_w);
185 root 1.1
186     pthread_mutexattr_init (&ma);
187 root 1.11 #ifdef PTHREAD_MUTEX_RECURSIVE
188 root 1.1 pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE);
189 root 1.11 #else
190     pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE_NP);
191     #endif
192 root 1.1 pthread_mutex_init (&u->lock, &ma);
193     pthread_mutexattr_destroy (&ma);
194    
195     pthread_cond_init (&u->invoke_cv, 0);
196    
197 root 1.8 ev_set_userdata (EV_A, u);
198     loop_set_cb (EV_A);
199 root 1.1
200 root 1.13 xthread_create (&u->tid, l_run, loop);
201 root 1.1 }
202    
203 root 1.2 SV *
204     interrupt (SV *loop_)
205     CODE:
206     {
207     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
208 root 1.8 udat *u = ev_userdata (EV_A);
209 root 1.2
210     RETVAL = newSVsv (u->interrupt);
211     }
212     OUTPUT:
213     RETVAL
214    
215 root 1.1 void
216 root 1.8 set_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     }
224    
225     void
226 root 1.1 lock (SV *loop_)
227     ALIAS:
228     lock = 0
229     unlock = 1
230 root 1.3 notify = 2
231 root 1.1 CODE:
232     {
233     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
234 root 1.8 udat *u = ev_userdata (EV_A);
235 root 1.1
236     switch (ix)
237     {
238     case 0: X_LOCK (u->lock); break;
239     case 1: X_UNLOCK (u->lock); break;
240 root 1.8 case 2: ev_async_send (EV_A, &u->async_w); break;
241 root 1.1 }
242     }
243    
244     void
245 root 1.2 scope_lock (SV *loop_)
246     CODE:
247     {
248     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
249 root 1.8 udat *u = ev_userdata (EV_A);
250 root 1.2
251     X_LOCK (u->lock);
252    
253     LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
254     SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_)));
255     ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
256     }
257    
258     void
259 root 1.1 DESTROY (SV *loop_)
260     CODE:
261     {
262     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
263 root 1.8 udat *u = ev_userdata (EV_A);
264 root 1.1
265     if (u)
266     {
267 root 1.4 X_LOCK (u->lock);
268 root 1.8 ev_async_stop (EV_A, &u->async_w);
269 root 1.5 /* now thread is around blocking call, or in pthread_cond_wait */
270     pthread_cancel (u->tid);
271 root 1.10 X_UNLOCK (u->lock);
272 root 1.1 pthread_mutex_destroy (&u->lock);
273     pthread_cond_destroy (&u->invoke_cv);
274 root 1.3 SvREFCNT_dec (u->interrupt);
275 root 1.1 Safefree (u);
276     }
277     }
278    
279    
280