Commit | Line | Data |
d9bb3666 |
1 | #include "EXTERN.h" |
2 | #include "perl.h" |
3 | #include "XSUB.h" |
4 | |
7d901afa |
5 | /* Magic signature for Thread's mg_private is "Th" */ |
6 | #define Thread_MAGIC_SIGNATURE 0x5468 |
7 | |
8 | static U32 threadnum = 0; |
85ced67f |
9 | static int sig_pipe[2]; |
683929b4 |
10 | |
7d901afa |
11 | static void |
12 | remove_thread(t) |
13 | Thread t; |
14 | { |
15 | DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(), |
16 | "%p: remove_thread %p\n", thr, t))); |
17 | MUTEX_LOCK(&threads_mutex); |
0a00ffdb |
18 | MUTEX_DESTROY(&t->mutex); |
7d901afa |
19 | nthreads--; |
20 | t->prev->next = t->next; |
21 | t->next->prev = t->prev; |
22 | COND_BROADCAST(&nthreads_cond); |
23 | MUTEX_UNLOCK(&threads_mutex); |
24 | } |
25 | |
ea0efc06 |
26 | static THREAD_RET_TYPE |
d9bb3666 |
27 | threadstart(arg) |
28 | void *arg; |
29 | { |
783070da |
30 | #ifdef FAKE_THREADS |
31 | Thread savethread = thr; |
32 | LOGOP myop; |
33 | dSP; |
34 | I32 oldscope = scopestack_ix; |
35 | I32 retval; |
50112d62 |
36 | AV *returnav; |
783070da |
37 | int i; |
38 | |
683929b4 |
39 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n", |
40 | thr, SvPEEK(TOPs))); |
783070da |
41 | thr = (Thread) arg; |
42 | savemark = TOPMARK; |
43 | thr->prev = thr->prev_run = savethread; |
44 | thr->next = savethread->next; |
45 | thr->next_run = savethread->next_run; |
46 | savethread->next = savethread->next_run = thr; |
47 | thr->wait_queue = 0; |
48 | thr->private = 0; |
49 | |
50 | /* Now duplicate most of perl_call_sv but with a few twists */ |
51 | op = (OP*)&myop; |
52 | Zero(op, 1, LOGOP); |
53 | myop.op_flags = OPf_STACKED; |
54 | myop.op_next = Nullop; |
55 | myop.op_flags |= OPf_KNOW; |
56 | myop.op_flags |= OPf_WANT_LIST; |
57 | op = pp_entersub(ARGS); |
58 | DEBUG_L(if (!op) |
59 | PerlIO_printf(PerlIO_stderr(), "thread starts at Nullop\n")); |
60 | /* |
61 | * When this thread is next scheduled, we start in the right |
62 | * place. When the thread runs off the end of the sub, perl.c |
63 | * handles things, using savemark to figure out how much of the |
64 | * stack is the return value for any join. |
65 | */ |
66 | thr = savethread; /* back to the old thread */ |
67 | return 0; |
68 | #else |
d9bb3666 |
69 | Thread thr = (Thread) arg; |
70 | LOGOP myop; |
71 | dSP; |
72 | I32 oldmark = TOPMARK; |
73 | I32 oldscope = scopestack_ix; |
74 | I32 retval; |
50112d62 |
75 | AV *returnav; |
14fcddff |
76 | int i, ret; |
783070da |
77 | dJMPENV; |
783070da |
78 | |
79 | /* Don't call *anything* requiring dTHR until after pthread_setspecific */ |
d9bb3666 |
80 | /* |
81 | * Wait until our creator releases us. If we didn't do this, then |
82 | * it would be potentially possible for out thread to carry on and |
83 | * do stuff before our creator fills in our "self" field. For example, |
ea0efc06 |
84 | * if we went and created another thread which tried to JOIN with us, |
85 | * then we'd be in a mess. |
d9bb3666 |
86 | */ |
50112d62 |
87 | MUTEX_LOCK(&thr->mutex); |
88 | MUTEX_UNLOCK(&thr->mutex); |
d9bb3666 |
89 | |
d9bb3666 |
90 | /* |
91 | * It's safe to wait until now to set the thread-specific pointer |
92 | * from our pthread_t structure to our struct thread, since we're |
93 | * the only thread who can get at it anyway. |
94 | */ |
ea0efc06 |
95 | SET_THR(thr); |
d9bb3666 |
96 | |
783070da |
97 | /* Only now can we use SvPEEK (which calls sv_newmortal which does dTHR) */ |
683929b4 |
98 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n", |
99 | thr, SvPEEK(TOPs))); |
783070da |
100 | |
101 | JMPENV_PUSH(ret); |
102 | switch (ret) { |
103 | case 3: |
104 | PerlIO_printf(PerlIO_stderr(), "panic: threadstart\n"); |
d9bb3666 |
105 | /* fall through */ |
783070da |
106 | case 1: |
107 | STATUS_ALL_FAILURE; |
d9bb3666 |
108 | /* fall through */ |
783070da |
109 | case 2: |
110 | /* my_exit() was called */ |
111 | while (scopestack_ix > oldscope) |
112 | LEAVE; |
113 | JMPENV_POP; |
d9bb3666 |
114 | av_store(returnav, 0, newSViv(statusvalue)); |
115 | goto finishoff; |
116 | } |
117 | |
118 | /* Now duplicate most of perl_call_sv but with a few twists */ |
119 | op = (OP*)&myop; |
120 | Zero(op, 1, LOGOP); |
121 | myop.op_flags = OPf_STACKED; |
122 | myop.op_next = Nullop; |
123 | myop.op_flags |= OPf_KNOW; |
783070da |
124 | myop.op_flags |= OPf_WANT_LIST; |
d9bb3666 |
125 | op = pp_entersub(ARGS); |
126 | if (op) |
127 | runops(); |
734689b1 |
128 | SPAGAIN; |
129 | retval = sp - (stack_base + oldmark); |
130 | sp = stack_base + oldmark + 1; |
783070da |
131 | DEBUG_L(for (i = 1; i <= retval; i++) |
132 | PerlIO_printf(PerlIO_stderr(), |
133 | "%p returnav[%d] = %s\n", |
134 | thr, i, SvPEEK(sp[i - 1]));) |
50112d62 |
135 | returnav = newAV(); |
d9bb3666 |
136 | av_store(returnav, 0, newSVpv("", 0)); |
734689b1 |
137 | for (i = 1; i <= retval; i++, sp++) |
138 | sv_setsv(*av_fetch(returnav, i, TRUE), SvREFCNT_inc(*sp)); |
139 | |
d9bb3666 |
140 | finishoff: |
783070da |
141 | #if 0 |
142 | /* removed for debug */ |
143 | SvREFCNT_dec(curstack); |
144 | #endif |
d9bb3666 |
145 | SvREFCNT_dec(cvcache); |
146 | Safefree(markstack); |
147 | Safefree(scopestack); |
148 | Safefree(savestack); |
149 | Safefree(retstack); |
150 | Safefree(cxstack); |
151 | Safefree(tmps_stack); |
152 | |
14fcddff |
153 | MUTEX_LOCK(&thr->mutex); |
50112d62 |
154 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), |
155 | "%p: threadstart finishing: state is %u\n", |
156 | thr, ThrSTATE(thr))); |
14fcddff |
157 | switch (ThrSTATE(thr)) { |
158 | case THRf_R_JOINABLE: |
159 | ThrSETSTATE(thr, THRf_ZOMBIE); |
160 | MUTEX_UNLOCK(&thr->mutex); |
783070da |
161 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), |
14fcddff |
162 | "%p: R_JOINABLE thread finished\n", thr)); |
163 | break; |
164 | case THRf_R_JOINED: |
165 | ThrSETSTATE(thr, THRf_DEAD); |
166 | MUTEX_UNLOCK(&thr->mutex); |
50112d62 |
167 | remove_thread(thr); |
14fcddff |
168 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), |
169 | "%p: R_JOINED thread finished\n", thr)); |
170 | break; |
50112d62 |
171 | case THRf_R_DETACHED: |
683929b4 |
172 | ThrSETSTATE(thr, THRf_DEAD); |
14fcddff |
173 | MUTEX_UNLOCK(&thr->mutex); |
14fcddff |
174 | SvREFCNT_dec(returnav); |
175 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), |
176 | "%p: DETACHED thread finished\n", thr)); |
50112d62 |
177 | remove_thread(thr); /* This might trigger main thread to finish */ |
14fcddff |
178 | break; |
179 | default: |
180 | MUTEX_UNLOCK(&thr->mutex); |
181 | croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr)); |
182 | /* NOTREACHED */ |
734689b1 |
183 | } |
ea0efc06 |
184 | return THREAD_RET_CAST(returnav); /* Available for anyone to join with */ |
185 | /* us unless we're detached, in which */ |
186 | /* case noone sees the value anyway. */ |
783070da |
187 | #endif |
d9bb3666 |
188 | } |
189 | |
683929b4 |
190 | static SV * |
191 | newthread(startsv, initargs, class) |
d9bb3666 |
192 | SV *startsv; |
193 | AV *initargs; |
683929b4 |
194 | char *class; |
d9bb3666 |
195 | { |
196 | dTHR; |
197 | dSP; |
198 | Thread savethread; |
199 | int i; |
683929b4 |
200 | SV *sv; |
ea0efc06 |
201 | int err; |
202 | #ifndef THREAD_CREATE |
f152979c |
203 | sigset_t fullmask, oldmask; |
ea0efc06 |
204 | #endif |
d9bb3666 |
205 | |
206 | savethread = thr; |
683929b4 |
207 | sv = newSVpv("", 0); |
208 | SvGROW(sv, sizeof(struct thread) + 1); |
209 | SvCUR_set(sv, sizeof(struct thread)); |
210 | thr = (Thread) SvPVX(sv); |
50112d62 |
211 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: newthread(%s) = %p)\n", |
7d901afa |
212 | savethread, SvPEEK(startsv), thr)); |
683929b4 |
213 | oursv = sv; |
783070da |
214 | /* If we don't zero these foostack pointers, init_stacks won't init them */ |
215 | markstack = 0; |
216 | scopestack = 0; |
217 | savestack = 0; |
218 | retstack = 0; |
d9bb3666 |
219 | init_stacks(ARGS); |
783070da |
220 | curcop = savethread->Tcurcop; /* XXX As good a guess as any? */ |
d9bb3666 |
221 | SPAGAIN; |
222 | defstash = savethread->Tdefstash; /* XXX maybe these should */ |
223 | curstash = savethread->Tcurstash; /* always be set to main? */ |
d9bb3666 |
224 | /* top_env? */ |
225 | /* runlevel */ |
226 | cvcache = newHV(); |
14fcddff |
227 | thr->flags = THRf_R_JOINABLE; |
228 | MUTEX_INIT(&thr->mutex); |
7d901afa |
229 | thr->tid = ++threadnum; |
230 | /* Insert new thread into the circular linked list and bump nthreads */ |
231 | MUTEX_LOCK(&threads_mutex); |
232 | thr->next = savethread->next; |
233 | thr->prev = savethread; |
234 | savethread->next = thr; |
235 | thr->next->prev = thr; |
236 | nthreads++; |
237 | MUTEX_UNLOCK(&threads_mutex); |
d9bb3666 |
238 | |
50112d62 |
239 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), |
240 | "%p: newthread, tid is %u, preparing stack\n", |
241 | savethread, thr->tid)); |
d9bb3666 |
242 | /* The following pushes the arg list and startsv onto the *new* stack */ |
243 | PUSHMARK(sp); |
244 | /* Could easily speed up the following greatly */ |
734689b1 |
245 | for (i = 0; i <= AvFILL(initargs); i++) |
d9bb3666 |
246 | XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE))); |
247 | XPUSHs(SvREFCNT_inc(startsv)); |
248 | PUTBACK; |
249 | |
ea0efc06 |
250 | #ifdef THREAD_CREATE |
251 | THREAD_CREATE(thr, threadstart); |
783070da |
252 | #else |
d9bb3666 |
253 | /* On your marks... */ |
14fcddff |
254 | MUTEX_LOCK(&thr->mutex); |
ea0efc06 |
255 | /* Get set... */ |
f152979c |
256 | sigfillset(&fullmask); |
257 | if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1) |
258 | croak("panic: sigprocmask"); |
ea0efc06 |
259 | err = pthread_create(&self, pthread_attr_default, threadstart, (void*) thr); |
d9bb3666 |
260 | /* Go */ |
14fcddff |
261 | MUTEX_UNLOCK(&thr->mutex); |
ea0efc06 |
262 | #endif |
263 | if (err) { |
264 | /* Thread creation failed--clean up */ |
265 | SvREFCNT_dec(cvcache); |
266 | remove_thread(thr); |
267 | MUTEX_DESTROY(&thr->mutex); |
268 | for (i = 0; i <= AvFILL(initargs); i++) |
269 | SvREFCNT_dec(*av_fetch(initargs, i, FALSE)); |
270 | SvREFCNT_dec(startsv); |
271 | return NULL; |
272 | } |
273 | #ifdef THREAD_POST_CREATE |
274 | THREAD_POST_CREATE(thr); |
275 | #else |
f152979c |
276 | if (sigprocmask(SIG_SETMASK, &oldmask, 0)) |
277 | croak("panic: sigprocmask"); |
783070da |
278 | #endif |
7d901afa |
279 | sv = newSViv(thr->tid); |
683929b4 |
280 | sv_magic(sv, oursv, '~', 0, 0); |
7d901afa |
281 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE; |
282 | return sv_bless(newRV_noinc(sv), gv_stashpv(class, TRUE)); |
d9bb3666 |
283 | } |
284 | |
f152979c |
285 | static Signal_t |
286 | handle_thread_signal(sig) |
287 | int sig; |
288 | { |
289 | char c = (char) sig; |
290 | write(sig_pipe[0], &c, 1); |
291 | } |
292 | |
d9bb3666 |
293 | MODULE = Thread PACKAGE = Thread |
294 | |
683929b4 |
295 | void |
d9bb3666 |
296 | new(class, startsv, ...) |
683929b4 |
297 | char * class |
d9bb3666 |
298 | SV * startsv |
734689b1 |
299 | AV * av = av_make(items - 2, &ST(2)); |
683929b4 |
300 | PPCODE: |
301 | XPUSHs(sv_2mortal(newthread(startsv, av, class))); |
d9bb3666 |
302 | |
303 | void |
d9bb3666 |
304 | join(t) |
305 | Thread t |
306 | AV * av = NO_INIT |
307 | int i = NO_INIT |
308 | PPCODE: |
7d901afa |
309 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: joining %p (state %u)\n", |
310 | thr, t, ThrSTATE(t));); |
50112d62 |
311 | MUTEX_LOCK(&t->mutex); |
312 | switch (ThrSTATE(t)) { |
14fcddff |
313 | case THRf_R_JOINABLE: |
314 | case THRf_R_JOINED: |
50112d62 |
315 | ThrSETSTATE(t, THRf_R_JOINED); |
316 | MUTEX_UNLOCK(&t->mutex); |
14fcddff |
317 | break; |
318 | case THRf_ZOMBIE: |
50112d62 |
319 | ThrSETSTATE(t, THRf_DEAD); |
320 | MUTEX_UNLOCK(&t->mutex); |
321 | remove_thread(t); |
14fcddff |
322 | break; |
323 | default: |
50112d62 |
324 | MUTEX_UNLOCK(&t->mutex); |
14fcddff |
325 | croak("can't join with thread"); |
326 | /* NOTREACHED */ |
327 | } |
ea0efc06 |
328 | JOIN(t, &av); |
7d901afa |
329 | |
d9bb3666 |
330 | /* Could easily speed up the following if necessary */ |
331 | for (i = 0; i <= AvFILL(av); i++) |
332 | XPUSHs(sv_2mortal(*av_fetch(av, i, FALSE))); |
333 | |
334 | void |
734689b1 |
335 | detach(t) |
d9bb3666 |
336 | Thread t |
337 | CODE: |
7d901afa |
338 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: detaching %p (state %u)\n", |
339 | thr, t, ThrSTATE(t));); |
50112d62 |
340 | MUTEX_LOCK(&t->mutex); |
341 | switch (ThrSTATE(t)) { |
14fcddff |
342 | case THRf_R_JOINABLE: |
50112d62 |
343 | ThrSETSTATE(t, THRf_R_DETACHED); |
14fcddff |
344 | /* fall through */ |
50112d62 |
345 | case THRf_R_DETACHED: |
14fcddff |
346 | DETACH(t); |
50112d62 |
347 | MUTEX_UNLOCK(&t->mutex); |
14fcddff |
348 | break; |
349 | case THRf_ZOMBIE: |
50112d62 |
350 | ThrSETSTATE(t, THRf_DEAD); |
7d901afa |
351 | DETACH(t); |
50112d62 |
352 | MUTEX_UNLOCK(&t->mutex); |
353 | remove_thread(t); |
14fcddff |
354 | break; |
355 | default: |
50112d62 |
356 | MUTEX_UNLOCK(&t->mutex); |
14fcddff |
357 | croak("can't detach thread"); |
358 | /* NOTREACHED */ |
734689b1 |
359 | } |
d9bb3666 |
360 | |
361 | void |
7d901afa |
362 | equal(t1, t2) |
363 | Thread t1 |
364 | Thread t2 |
365 | PPCODE: |
366 | PUSHs((t1 == t2) ? &sv_yes : &sv_no); |
367 | |
368 | void |
369 | flags(t) |
370 | Thread t |
371 | PPCODE: |
372 | PUSHs(sv_2mortal(newSViv(t->flags))); |
373 | |
374 | void |
375 | self(class) |
376 | char * class |
377 | PREINIT: |
378 | SV *sv; |
379 | PPCODE: |
380 | sv = newSViv(thr->tid); |
381 | sv_magic(sv, oursv, '~', 0, 0); |
382 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE; |
383 | PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv), gv_stashpv(class, TRUE)))); |
384 | |
50112d62 |
385 | U32 |
386 | tid(t) |
387 | Thread t |
388 | CODE: |
389 | MUTEX_LOCK(&t->mutex); |
390 | RETVAL = t->tid; |
391 | MUTEX_UNLOCK(&t->mutex); |
392 | OUTPUT: |
393 | RETVAL |
394 | |
395 | void |
396 | DESTROY(t) |
397 | SV * t |
398 | PPCODE: |
399 | PUSHs(&sv_yes); |
400 | |
7d901afa |
401 | void |
734689b1 |
402 | yield() |
d9bb3666 |
403 | CODE: |
ea0efc06 |
404 | YIELD; |
d9bb3666 |
405 | |
406 | void |
734689b1 |
407 | cond_wait(sv) |
408 | SV * sv |
409 | MAGIC * mg = NO_INIT |
410 | CODE: |
2c127b02 |
411 | if (SvROK(sv)) |
734689b1 |
412 | sv = SvRV(sv); |
2c127b02 |
413 | |
734689b1 |
414 | mg = condpair_magic(sv); |
683929b4 |
415 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_wait %p\n", thr, sv)); |
734689b1 |
416 | MUTEX_LOCK(MgMUTEXP(mg)); |
417 | if (MgOWNER(mg) != thr) { |
418 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
419 | croak("cond_wait for lock that we don't own\n"); |
420 | } |
421 | MgOWNER(mg) = 0; |
422 | COND_WAIT(MgCONDP(mg), MgMUTEXP(mg)); |
50112d62 |
423 | while (MgOWNER(mg)) |
424 | COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg)); |
734689b1 |
425 | MgOWNER(mg) = thr; |
426 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
427 | |
428 | void |
429 | cond_signal(sv) |
430 | SV * sv |
431 | MAGIC * mg = NO_INIT |
432 | CODE: |
50112d62 |
433 | if (SvROK(sv)) |
734689b1 |
434 | sv = SvRV(sv); |
50112d62 |
435 | |
734689b1 |
436 | mg = condpair_magic(sv); |
683929b4 |
437 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_signal %p\n",thr,sv)); |
734689b1 |
438 | MUTEX_LOCK(MgMUTEXP(mg)); |
439 | if (MgOWNER(mg) != thr) { |
440 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
441 | croak("cond_signal for lock that we don't own\n"); |
442 | } |
443 | COND_SIGNAL(MgCONDP(mg)); |
444 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
d9bb3666 |
445 | |
734689b1 |
446 | void |
447 | cond_broadcast(sv) |
448 | SV * sv |
449 | MAGIC * mg = NO_INIT |
450 | CODE: |
783070da |
451 | if (SvROK(sv)) |
734689b1 |
452 | sv = SvRV(sv); |
783070da |
453 | |
734689b1 |
454 | mg = condpair_magic(sv); |
683929b4 |
455 | DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_broadcast %p\n", |
456 | thr, sv)); |
734689b1 |
457 | MUTEX_LOCK(MgMUTEXP(mg)); |
458 | if (MgOWNER(mg) != thr) { |
459 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
460 | croak("cond_broadcast for lock that we don't own\n"); |
461 | } |
462 | COND_BROADCAST(MgCONDP(mg)); |
463 | MUTEX_UNLOCK(MgMUTEXP(mg)); |
f152979c |
464 | |
7d901afa |
465 | void |
466 | list(class) |
467 | char * class |
468 | PREINIT: |
469 | Thread t; |
470 | AV * av; |
471 | SV ** svp; |
472 | int n = 0; |
473 | PPCODE: |
474 | av = newAV(); |
475 | /* |
476 | * Iterate until we have enough dynamic storage for all threads. |
477 | * We mustn't do any allocation while holding threads_mutex though. |
478 | */ |
479 | MUTEX_LOCK(&threads_mutex); |
480 | do { |
481 | n = nthreads; |
482 | MUTEX_UNLOCK(&threads_mutex); |
483 | if (AvFILL(av) < n - 1) { |
484 | int i = AvFILL(av); |
485 | for (i = AvFILL(av); i < n - 1; i++) { |
486 | SV *sv = newSViv(0); /* fill in tid later */ |
487 | sv_magic(sv, 0, '~', 0, 0); /* fill in other magic later */ |
488 | av_push(av, sv_bless(newRV_noinc(sv), |
489 | gv_stashpv(class, TRUE))); |
50112d62 |
490 | |
7d901afa |
491 | } |
492 | } |
493 | MUTEX_LOCK(&threads_mutex); |
494 | } while (n < nthreads); |
50112d62 |
495 | n = nthreads; /* Get the final correct value */ |
7d901afa |
496 | |
497 | /* |
498 | * At this point, there's enough room to fill in av. |
499 | * Note that we are holding threads_mutex so the list |
500 | * won't change out from under us but all the remaining |
501 | * processing is "fast" (no blocking, malloc etc.) |
502 | */ |
503 | t = thr; |
504 | svp = AvARRAY(av); |
505 | do { |
0a00ffdb |
506 | SV *sv = (SV*)SvRV(*svp); |
7d901afa |
507 | sv_setiv(sv, t->tid); |
508 | SvMAGIC(sv)->mg_obj = SvREFCNT_inc(t->Toursv); |
509 | SvMAGIC(sv)->mg_flags |= MGf_REFCOUNTED; |
510 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE; |
511 | t = t->next; |
0a00ffdb |
512 | svp++; |
7d901afa |
513 | } while (t != thr); |
50112d62 |
514 | /* */ |
7d901afa |
515 | MUTEX_UNLOCK(&threads_mutex); |
516 | /* Truncate any unneeded slots in av */ |
50112d62 |
517 | av_fill(av, n - 1); |
7d901afa |
518 | /* Finally, push all the new objects onto the stack and drop av */ |
519 | EXTEND(sp, n); |
520 | for (svp = AvARRAY(av); n > 0; n--, svp++) |
521 | PUSHs(*svp); |
522 | (void)sv_2mortal((SV*)av); |
523 | |
524 | |
f152979c |
525 | MODULE = Thread PACKAGE = Thread::Signal |
526 | |
527 | void |
528 | kill_sighandler_thread() |
529 | PPCODE: |
530 | write(sig_pipe[0], "\0", 1); |
531 | PUSHs(&sv_yes); |
532 | |
533 | void |
534 | init_thread_signals() |
535 | PPCODE: |
536 | sighandlerp = handle_thread_signal; |
537 | if (pipe(sig_pipe) == -1) |
538 | XSRETURN_UNDEF; |
539 | PUSHs(&sv_yes); |
540 | |
541 | SV * |
542 | await_signal() |
543 | PREINIT: |
544 | char c; |
ea0efc06 |
545 | SSize_t ret; |
f152979c |
546 | CODE: |
547 | do { |
548 | ret = read(sig_pipe[1], &c, 1); |
549 | } while (ret == -1 && errno == EINTR); |
550 | if (ret == -1) |
551 | croak("panic: await_signal"); |
552 | if (ret == 0) |
553 | XSRETURN_UNDEF; |
554 | RETVAL = c ? psig_ptr[c] : &sv_no; |
555 | OUTPUT: |
556 | RETVAL |