ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-Loop-Async/Async.xs
Revision: 1.9
Committed: Fri Jul 17 03:28:57 2009 UTC (17 years, 2 months ago) by root
Branch: MAIN
CVS Tags: rel-0_02
Changes since 1.8: +2 -0 lines
Log Message:
*** empty log message ***

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     mutex_t lock; /* global loop lock */
16     void (*signal_func) (void *signal_arg, int value);
17     void *signal_arg;
18     ev_async async_w;
19     thread_t tid;
20 root 1.8 unsigned int max_loops;
21     unsigned int count;
22 root 1.1
23     cond_t invoke_cv;
24    
25 root 1.2 SV *interrupt;
26 root 1.1 } udat;
27    
28 root 1.8 static void loop_set_cb (EV_P);
29    
30     static void
31     fg_invoke_pending (EV_P)
32     {
33     udat *u = ev_userdata (EV_A);
34    
35     u->count = ev_pending_count (EV_A);
36    
37     if (u->count)
38     ev_invoke_pending (EV_A);
39     }
40    
41 root 1.1 static void
42     c_func (pTHX_ void *loop_, int value)
43     {
44     struct ev_loop *loop = (struct ev_loop *)loop_;
45     udat *u = ev_userdata (EV_A);
46 root 1.8 int i;
47    
48 root 1.1 X_LOCK (u->lock);
49 root 1.8 ev_invoke_pending (EV_A);
50    
51     /* do any additional foreground loop runs */
52     for (i = u->max_loops; i--; )
53     {
54     /* this is a bit tricky, but we can manage... */
55     u->count = 0;
56    
57     ev_set_invoke_pending_cb (EV_A, fg_invoke_pending);
58     ev_set_loop_release_cb (EV_A, 0, 0);
59     ev_loop (EV_A, EVLOOP_NONBLOCK);
60     loop_set_cb (EV_A);
61    
62     if (!u->count)
63     break;
64     }
65    
66 root 1.5 X_COND_SIGNAL (u->invoke_cv);
67 root 1.1 X_UNLOCK (u->lock);
68     }
69    
70     static void
71     async_cb (EV_P_ ev_async *w, int revents)
72     {
73     /* just used for the side effects */
74     }
75    
76     static void
77     l_release (EV_P)
78     {
79     udat *u = ev_userdata (EV_A);
80     X_UNLOCK (u->lock);
81     }
82    
83     static void
84     l_acquire (EV_P)
85     {
86     udat *u = ev_userdata (EV_A);
87     X_LOCK (u->lock);
88     }
89    
90     static void
91     l_invoke (EV_P)
92     {
93     udat *u = ev_userdata (EV_A);
94 root 1.8
95     while (ev_pending_count (EV_A))
96     {
97     u->signal_func (u->signal_arg, 1);
98     X_COND_WAIT (u->invoke_cv, u->lock);
99     }
100     }
101    
102     static void
103     loop_set_cb (EV_P)
104     {
105     ev_set_invoke_pending_cb (EV_A, l_invoke);
106     ev_set_loop_release_cb (EV_A, l_release, l_acquire);
107 root 1.1 }
108    
109     X_THREAD_PROC(l_run)
110     {
111     struct ev_loop *loop = (struct ev_loop *)thr_arg;
112    
113 root 1.6 l_acquire (EV_A);
114    
115 root 1.5 /* yeah */
116     pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
117    
118 root 1.6 ev_ref (EV_A);
119     ev_loop (EV_A, 0);
120     ev_unref (EV_A);
121 root 1.5
122 root 1.6 l_release (EV_A);
123 root 1.5
124     return 0;
125 root 1.1 }
126    
127 root 1.2 static void
128     scope_lock_cb (pTHX_ void *loop_)
129     {
130     struct ev_loop *loop = (struct ev_loop *)SvIVX ((SV *)loop_);
131 root 1.8 udat *u = ev_userdata (EV_A);
132 root 1.2
133     X_UNLOCK (u->lock);
134     SvREFCNT_dec ((SV *)loop_);
135     }
136    
137 root 1.1 MODULE = EV::Loop::Async PACKAGE = EV::Loop::Async
138    
139     PROTOTYPES: ENABLE
140    
141     BOOT:
142     {
143     I_EV_API ("EV::Loop::Async");
144 root 1.3 CvNODEBUG_on (get_cv ("EV::Loop::Async::scope_lock", 0)); /* otherwise calling scope can be the debugger */
145 root 1.1 }
146    
147     void
148     _c_func (SV *loop)
149     PPCODE:
150     EXTEND (SP, 2);
151     PUSHs (sv_2mortal (newSViv (PTR2IV (c_func))));
152     PUSHs (sv_2mortal (newSViv (SvIVX (SvRV (loop)))));
153    
154     void
155 root 1.2 _attach (SV *loop_, SV *interrupt, IV sig_func, void *sig_arg)
156 root 1.1 CODE:
157     {
158     pthread_mutexattr_t ma;
159     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
160     udat *u;
161    
162     Newz (0, u, 1, udat);
163 root 1.2 u->interrupt = newSVsv (interrupt);
164 root 1.1 u->signal_func = (void (*)(void *, int))sig_func;
165     u->signal_arg = sig_arg;
166    
167     ev_async_init (&u->async_w, async_cb);
168 root 1.8 ev_async_start (EV_A, &u->async_w);
169 root 1.1
170     pthread_mutexattr_init (&ma);
171     pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE);
172     pthread_mutex_init (&u->lock, &ma);
173     pthread_mutexattr_destroy (&ma);
174    
175     pthread_cond_init (&u->invoke_cv, 0);
176    
177 root 1.8 ev_set_userdata (EV_A, u);
178     loop_set_cb (EV_A);
179 root 1.1
180 root 1.5 thread_create (&u->tid, l_run, loop);
181 root 1.1 }
182    
183 root 1.2 SV *
184     interrupt (SV *loop_)
185     CODE:
186     {
187     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
188 root 1.8 udat *u = ev_userdata (EV_A);
189 root 1.2
190     RETVAL = newSVsv (u->interrupt);
191     }
192     OUTPUT:
193     RETVAL
194    
195 root 1.1 void
196 root 1.8 set_max_foreground_loops (SV *loop_, UV max_loops)
197     CODE:
198     {
199     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
200     udat *u = ev_userdata (EV_A);
201    
202     u->max_loops = max_loops;
203     }
204    
205     void
206 root 1.1 lock (SV *loop_)
207     ALIAS:
208     lock = 0
209     unlock = 1
210 root 1.3 notify = 2
211 root 1.1 CODE:
212     {
213     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
214 root 1.8 udat *u = ev_userdata (EV_A);
215 root 1.1
216     switch (ix)
217     {
218     case 0: X_LOCK (u->lock); break;
219     case 1: X_UNLOCK (u->lock); break;
220 root 1.8 case 2: ev_async_send (EV_A, &u->async_w); break;
221 root 1.1 }
222     }
223    
224     void
225 root 1.2 scope_lock (SV *loop_)
226     CODE:
227     {
228     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
229 root 1.8 udat *u = ev_userdata (EV_A);
230 root 1.2
231     X_LOCK (u->lock);
232    
233     LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
234     SAVEDESTRUCTOR_X (scope_lock_cb, (void *)SvREFCNT_inc (SvRV (loop_)));
235     ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
236     }
237    
238     void
239 root 1.1 DESTROY (SV *loop_)
240     CODE:
241     {
242     struct ev_loop *loop = (struct ev_loop *)SvIVX (SvRV (loop_));
243 root 1.8 udat *u = ev_userdata (EV_A);
244 root 1.1
245     if (u)
246     {
247 root 1.4 X_LOCK (u->lock);
248 root 1.8 ev_async_stop (EV_A, &u->async_w);
249 root 1.5 /* now thread is around blocking call, or in pthread_cond_wait */
250     pthread_cancel (u->tid);
251 root 1.1 pthread_mutex_destroy (&u->lock);
252     pthread_cond_destroy (&u->invoke_cv);
253 root 1.3 SvREFCNT_dec (u->interrupt);
254 root 1.1 Safefree (u);
255     }
256     }
257    
258    
259