1 | #define PERL_NO_GET_CONTEXT
|
---|
2 | #include "EXTERN.h"
|
---|
3 | #include "perl.h"
|
---|
4 | #include "XSUB.h"
|
---|
5 |
|
---|
6 | /* Magic signature for Thread's mg_private is "Th" */
|
---|
7 | #define Thread_MAGIC_SIGNATURE 0x5468
|
---|
8 |
|
---|
9 | #ifdef __cplusplus
|
---|
10 | #ifdef I_UNISTD
|
---|
11 | #include <unistd.h>
|
---|
12 | #endif
|
---|
13 | #endif
|
---|
14 | #include <fcntl.h>
|
---|
15 |
|
---|
16 | static int sig_pipe[2];
|
---|
17 |
|
---|
18 | #ifndef THREAD_RET_TYPE
|
---|
19 | #define THREAD_RET_TYPE void *
|
---|
20 | #define THREAD_RET_CAST(x) ((THREAD_RET_TYPE) x)
|
---|
21 | #endif
|
---|
22 |
|
---|
23 | static void
|
---|
24 | remove_thread(pTHX_ Thread t)
|
---|
25 | {
|
---|
26 | #ifdef USE_5005THREADS
|
---|
27 | DEBUG_S(WITH_THR(PerlIO_printf(Perl_debug_log,
|
---|
28 | "%p: remove_thread %p\n", thr, t)));
|
---|
29 | MUTEX_LOCK(&PL_threads_mutex);
|
---|
30 | MUTEX_DESTROY(&t->mutex);
|
---|
31 | PL_nthreads--;
|
---|
32 | t->prev->next = t->next;
|
---|
33 | t->next->prev = t->prev;
|
---|
34 | SvREFCNT_dec(t->oursv);
|
---|
35 | COND_BROADCAST(&PL_nthreads_cond);
|
---|
36 | MUTEX_UNLOCK(&PL_threads_mutex);
|
---|
37 | #endif
|
---|
38 | }
|
---|
39 |
|
---|
40 | static THREAD_RET_TYPE
|
---|
41 | threadstart(void *arg)
|
---|
42 | {
|
---|
43 | #ifdef USE_5005THREADS
|
---|
44 | #ifdef FAKE_THREADS
|
---|
45 | Thread savethread = thr;
|
---|
46 | LOGOP myop;
|
---|
47 | dSP;
|
---|
48 | I32 oldscope = PL_scopestack_ix;
|
---|
49 | I32 retval;
|
---|
50 | AV *av;
|
---|
51 | int i;
|
---|
52 |
|
---|
53 | DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p starting at %s\n",
|
---|
54 | thr, SvPEEK(TOPs)));
|
---|
55 | thr = (Thread) arg;
|
---|
56 | savemark = TOPMARK;
|
---|
57 | thr->prev = thr->prev_run = savethread;
|
---|
58 | thr->next = savethread->next;
|
---|
59 | thr->next_run = savethread->next_run;
|
---|
60 | savethread->next = savethread->next_run = thr;
|
---|
61 | thr->wait_queue = 0;
|
---|
62 | thr->private = 0;
|
---|
63 |
|
---|
64 | /* Now duplicate most of perl_call_sv but with a few twists */
|
---|
65 | PL_op = (OP*)&myop;
|
---|
66 | Zero(PL_op, 1, LOGOP);
|
---|
67 | myop.op_flags = OPf_STACKED;
|
---|
68 | myop.op_next = Nullop;
|
---|
69 | myop.op_flags |= OPf_KNOW;
|
---|
70 | myop.op_flags |= OPf_WANT_LIST;
|
---|
71 | PL_op = pp_entersub(ARGS);
|
---|
72 | DEBUG_S(if (!PL_op)
|
---|
73 | PerlIO_printf(Perl_debug_log, "thread starts at Nullop\n"));
|
---|
74 | /*
|
---|
75 | * When this thread is next scheduled, we start in the right
|
---|
76 | * place. When the thread runs off the end of the sub, perl.c
|
---|
77 | * handles things, using savemark to figure out how much of the
|
---|
78 | * stack is the return value for any join.
|
---|
79 | */
|
---|
80 | thr = savethread; /* back to the old thread */
|
---|
81 | return 0;
|
---|
82 | #else
|
---|
83 | Thread thr = (Thread) arg;
|
---|
84 | dSP;
|
---|
85 | I32 oldmark = TOPMARK;
|
---|
86 | I32 retval;
|
---|
87 | SV *sv;
|
---|
88 | AV *av;
|
---|
89 | int i;
|
---|
90 |
|
---|
91 | #if defined(MULTIPLICITY)
|
---|
92 | PERL_SET_INTERP(thr->interp);
|
---|
93 | #endif
|
---|
94 |
|
---|
95 | DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p waiting to start\n",
|
---|
96 | thr));
|
---|
97 |
|
---|
98 | /*
|
---|
99 | * Wait until our creator releases us. If we didn't do this, then
|
---|
100 | * it would be potentially possible for out thread to carry on and
|
---|
101 | * do stuff before our creator fills in our "self" field. For example,
|
---|
102 | * if we went and created another thread which tried to JOIN with us,
|
---|
103 | * then we'd be in a mess.
|
---|
104 | */
|
---|
105 | MUTEX_LOCK(&thr->mutex);
|
---|
106 | MUTEX_UNLOCK(&thr->mutex);
|
---|
107 |
|
---|
108 | /*
|
---|
109 | * It's safe to wait until now to set the thread-specific pointer
|
---|
110 | * from our pthread_t structure to our struct perl_thread, since
|
---|
111 | * we're the only thread who can get at it anyway.
|
---|
112 | */
|
---|
113 | PERL_SET_THX(thr);
|
---|
114 |
|
---|
115 | DEBUG_S(PerlIO_printf(Perl_debug_log, "new thread %p starting at %s\n",
|
---|
116 | thr, SvPEEK(TOPs)));
|
---|
117 |
|
---|
118 | av = newAV();
|
---|
119 | sv = POPs;
|
---|
120 | PUTBACK;
|
---|
121 | ENTER;
|
---|
122 | SAVETMPS;
|
---|
123 | perl_call_sv(sv, G_ARRAY|G_EVAL);
|
---|
124 | SPAGAIN;
|
---|
125 | retval = SP - (PL_stack_base + oldmark);
|
---|
126 | SP = PL_stack_base + oldmark + 1;
|
---|
127 | if (SvCUR(thr->errsv)) {
|
---|
128 | MUTEX_LOCK(&thr->mutex);
|
---|
129 | thr->flags |= THRf_DID_DIE;
|
---|
130 | MUTEX_UNLOCK(&thr->mutex);
|
---|
131 | av_store(av, 0, &PL_sv_no);
|
---|
132 | av_store(av, 1, newSVsv(thr->errsv));
|
---|
133 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p died: %s\n",
|
---|
134 | thr, SvPV(thr->errsv, PL_na)));
|
---|
135 | }
|
---|
136 | else {
|
---|
137 | DEBUG_S(STMT_START {
|
---|
138 | for (i = 1; i <= retval; i++) {
|
---|
139 | PerlIO_printf(Perl_debug_log, "%p return[%d] = %s\n",
|
---|
140 | thr, i, SvPEEK(SP[i - 1]));
|
---|
141 | }
|
---|
142 | } STMT_END);
|
---|
143 | av_store(av, 0, &PL_sv_yes);
|
---|
144 | for (i = 1; i <= retval; i++, SP++)
|
---|
145 | sv_setsv(*av_fetch(av, i, TRUE), SvREFCNT_inc(*SP));
|
---|
146 | }
|
---|
147 | FREETMPS;
|
---|
148 | LEAVE;
|
---|
149 |
|
---|
150 | #if 0
|
---|
151 | /* removed for debug */
|
---|
152 | SvREFCNT_dec(PL_curstack);
|
---|
153 | #endif
|
---|
154 | SvREFCNT_dec(thr->cvcache);
|
---|
155 | SvREFCNT_dec(thr->threadsv);
|
---|
156 | SvREFCNT_dec(thr->specific);
|
---|
157 | SvREFCNT_dec(thr->errsv);
|
---|
158 |
|
---|
159 | /*Safefree(cxstack);*/
|
---|
160 | while (PL_curstackinfo->si_next)
|
---|
161 | PL_curstackinfo = PL_curstackinfo->si_next;
|
---|
162 | while (PL_curstackinfo) {
|
---|
163 | PERL_SI *p = PL_curstackinfo->si_prev;
|
---|
164 | SvREFCNT_dec(PL_curstackinfo->si_stack);
|
---|
165 | Safefree(PL_curstackinfo->si_cxstack);
|
---|
166 | Safefree(PL_curstackinfo);
|
---|
167 | PL_curstackinfo = p;
|
---|
168 | }
|
---|
169 | Safefree(PL_markstack);
|
---|
170 | Safefree(PL_scopestack);
|
---|
171 | Safefree(PL_savestack);
|
---|
172 | Safefree(PL_retstack);
|
---|
173 | Safefree(PL_tmps_stack);
|
---|
174 | SvREFCNT_dec(PL_ofs_sv);
|
---|
175 |
|
---|
176 | SvREFCNT_dec(PL_rs);
|
---|
177 | SvREFCNT_dec(PL_statname);
|
---|
178 | SvREFCNT_dec(PL_errors);
|
---|
179 | Safefree(PL_screamfirst);
|
---|
180 | Safefree(PL_screamnext);
|
---|
181 | Safefree(PL_reg_start_tmp);
|
---|
182 | SvREFCNT_dec(PL_lastscream);
|
---|
183 | SvREFCNT_dec(PL_defoutgv);
|
---|
184 | Safefree(PL_reg_poscache);
|
---|
185 |
|
---|
186 | MUTEX_LOCK(&thr->mutex);
|
---|
187 | thr->thr_done = 1;
|
---|
188 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
189 | "%p: threadstart finishing: state is %u\n",
|
---|
190 | thr, ThrSTATE(thr)));
|
---|
191 | switch (ThrSTATE(thr)) {
|
---|
192 | case THRf_R_JOINABLE:
|
---|
193 | ThrSETSTATE(thr, THRf_ZOMBIE);
|
---|
194 | MUTEX_UNLOCK(&thr->mutex);
|
---|
195 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
196 | "%p: R_JOINABLE thread finished\n", thr));
|
---|
197 | break;
|
---|
198 | case THRf_R_JOINED:
|
---|
199 | ThrSETSTATE(thr, THRf_DEAD);
|
---|
200 | MUTEX_UNLOCK(&thr->mutex);
|
---|
201 | remove_thread(aTHX_ thr);
|
---|
202 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
203 | "%p: R_JOINED thread finished\n", thr));
|
---|
204 | break;
|
---|
205 | case THRf_R_DETACHED:
|
---|
206 | ThrSETSTATE(thr, THRf_DEAD);
|
---|
207 | MUTEX_UNLOCK(&thr->mutex);
|
---|
208 | SvREFCNT_dec(av);
|
---|
209 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
210 | "%p: DETACHED thread finished\n", thr));
|
---|
211 | remove_thread(aTHX_ thr); /* This might trigger main thread to finish */
|
---|
212 | break;
|
---|
213 | default:
|
---|
214 | MUTEX_UNLOCK(&thr->mutex);
|
---|
215 | croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr));
|
---|
216 | /* NOTREACHED */
|
---|
217 | }
|
---|
218 | return THREAD_RET_CAST(av); /* Available for anyone to join with */
|
---|
219 | /* us unless we're detached, in which */
|
---|
220 | /* case noone sees the value anyway. */
|
---|
221 | #endif
|
---|
222 | #else
|
---|
223 | return THREAD_RET_CAST(NULL);
|
---|
224 | #endif
|
---|
225 | }
|
---|
226 |
|
---|
227 | static SV *
|
---|
228 | newthread (pTHX_ SV *startsv, AV *initargs, char *classname)
|
---|
229 | {
|
---|
230 | #ifdef USE_5005THREADS
|
---|
231 | dSP;
|
---|
232 | Thread savethread;
|
---|
233 | int i;
|
---|
234 | SV *sv;
|
---|
235 | int err;
|
---|
236 | #ifndef THREAD_CREATE
|
---|
237 | static pthread_attr_t attr;
|
---|
238 | static int attr_inited = 0;
|
---|
239 | sigset_t fullmask, oldmask;
|
---|
240 | static int attr_joinable = PTHREAD_CREATE_JOINABLE;
|
---|
241 | #endif
|
---|
242 |
|
---|
243 | if (ckWARN(WARN_DEPRECATED))
|
---|
244 | Perl_warner(aTHX_ packWARN(WARN_DEPRECATED),
|
---|
245 | "5.005 threads are deprecated");
|
---|
246 | savethread = thr;
|
---|
247 | thr = new_struct_thread(thr);
|
---|
248 | /* temporarily pretend to be the child thread in case the
|
---|
249 | * XPUSHs() below want to grow the child's stack. This is
|
---|
250 | * safe, since the other thread is not yet created, and we
|
---|
251 | * are the only ones who know about it */
|
---|
252 | PERL_SET_THX(thr);
|
---|
253 | SPAGAIN;
|
---|
254 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
255 | "%p: newthread (%p), tid is %u, preparing stack\n",
|
---|
256 | savethread, thr, thr->tid));
|
---|
257 | /* The following pushes the arg list and startsv onto the *new* stack */
|
---|
258 | PUSHMARK(SP);
|
---|
259 | /* Could easily speed up the following greatly */
|
---|
260 | for (i = 0; i <= AvFILL(initargs); i++)
|
---|
261 | XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE)));
|
---|
262 | XPUSHs(SvREFCNT_inc(startsv));
|
---|
263 | PUTBACK;
|
---|
264 |
|
---|
265 | /* On your marks... */
|
---|
266 | PERL_SET_THX(savethread);
|
---|
267 | MUTEX_LOCK(&thr->mutex);
|
---|
268 |
|
---|
269 | #ifdef THREAD_CREATE
|
---|
270 | err = THREAD_CREATE(thr, threadstart);
|
---|
271 | #else
|
---|
272 | /* Get set... */
|
---|
273 | sigfillset(&fullmask);
|
---|
274 | if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1)
|
---|
275 | croak("panic: sigprocmask");
|
---|
276 | err = 0;
|
---|
277 | if (!attr_inited) {
|
---|
278 | attr_inited = 1;
|
---|
279 | err = pthread_attr_init(&attr);
|
---|
280 | # ifdef THREAD_CREATE_NEEDS_STACK
|
---|
281 | if (err == 0)
|
---|
282 | err = pthread_attr_setstacksize(&attr, THREAD_CREATE_NEEDS_STACK);
|
---|
283 | if (err)
|
---|
284 | croak("panic: pthread_attr_setstacksize failed");
|
---|
285 | # endif
|
---|
286 | # ifdef PTHREAD_ATTR_SETDETACHSTATE
|
---|
287 | if (err == 0)
|
---|
288 | err = PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable);
|
---|
289 | if (err)
|
---|
290 | croak("panic: pthread_attr_setdetachstate failed");
|
---|
291 | # else
|
---|
292 | croak("panic: can't pthread_attr_setdetachstate");
|
---|
293 | # endif
|
---|
294 | }
|
---|
295 | if (err == 0)
|
---|
296 | err = PTHREAD_CREATE(&thr->self, attr, threadstart, (void*) thr);
|
---|
297 | #endif
|
---|
298 |
|
---|
299 | if (err) {
|
---|
300 | MUTEX_UNLOCK(&thr->mutex);
|
---|
301 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
302 | "%p: create of %p failed %d\n",
|
---|
303 | savethread, thr, err));
|
---|
304 | /* Thread creation failed--clean up */
|
---|
305 | SvREFCNT_dec(thr->cvcache);
|
---|
306 | remove_thread(aTHX_ thr);
|
---|
307 | for (i = 0; i <= AvFILL(initargs); i++)
|
---|
308 | SvREFCNT_dec(*av_fetch(initargs, i, FALSE));
|
---|
309 | SvREFCNT_dec(startsv);
|
---|
310 | return NULL;
|
---|
311 | }
|
---|
312 |
|
---|
313 | #ifdef THREAD_POST_CREATE
|
---|
314 | THREAD_POST_CREATE(thr);
|
---|
315 | #else
|
---|
316 | if (sigprocmask(SIG_SETMASK, &oldmask, 0))
|
---|
317 | croak("panic: sigprocmask");
|
---|
318 | #endif
|
---|
319 |
|
---|
320 | sv = newSViv(thr->tid);
|
---|
321 | sv_magic(sv, thr->oursv, '~', 0, 0);
|
---|
322 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
|
---|
323 | sv = sv_bless(newRV_noinc(sv), gv_stashpv(classname, TRUE));
|
---|
324 |
|
---|
325 | /* Go */
|
---|
326 | MUTEX_UNLOCK(&thr->mutex);
|
---|
327 |
|
---|
328 | return sv;
|
---|
329 | #else
|
---|
330 | # ifdef USE_ITHREADS
|
---|
331 | croak("This perl was built for \"ithreads\", which currently does not support Thread.pm.\n"
|
---|
332 | "Run \"perldoc Thread\" for more information");
|
---|
333 | # else
|
---|
334 | croak("This perl was not built with support for 5.005-style threads.\n"
|
---|
335 | "Run \"perldoc Thread\" for more information");
|
---|
336 | # endif
|
---|
337 | return &PL_sv_undef;
|
---|
338 | #endif
|
---|
339 | }
|
---|
340 |
|
---|
341 | static Signal_t handle_thread_signal (int sig);
|
---|
342 |
|
---|
343 | static Signal_t
|
---|
344 | handle_thread_signal(int sig)
|
---|
345 | {
|
---|
346 | unsigned char c = (unsigned char) sig;
|
---|
347 | dTHX;
|
---|
348 | /*
|
---|
349 | * We're not really allowed to call fprintf in a signal handler
|
---|
350 | * so don't be surprised if this isn't robust while debugging
|
---|
351 | * with -DL.
|
---|
352 | */
|
---|
353 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
354 | "handle_thread_signal: got signal %d\n", sig));
|
---|
355 | write(sig_pipe[1], &c, 1);
|
---|
356 | }
|
---|
357 |
|
---|
358 | MODULE = Thread PACKAGE = Thread
|
---|
359 | PROTOTYPES: DISABLE
|
---|
360 |
|
---|
361 | void
|
---|
362 | new(classname, startsv, ...)
|
---|
363 | char * classname
|
---|
364 | SV * startsv
|
---|
365 | AV * av = av_make(items - 2, &ST(2));
|
---|
366 | PPCODE:
|
---|
367 | XPUSHs(sv_2mortal(newthread(aTHX_ startsv, av, classname)));
|
---|
368 |
|
---|
369 | void
|
---|
370 | join(t)
|
---|
371 | Thread t
|
---|
372 | PREINIT:
|
---|
373 | #ifdef USE_5005THREADS
|
---|
374 | AV * av;
|
---|
375 | int i;
|
---|
376 | #endif
|
---|
377 | PPCODE:
|
---|
378 | #ifdef USE_5005THREADS
|
---|
379 | if (t == thr)
|
---|
380 | croak("Attempt to join self");
|
---|
381 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: joining %p (state %u)\n",
|
---|
382 | thr, t, ThrSTATE(t)));
|
---|
383 | MUTEX_LOCK(&t->mutex);
|
---|
384 | switch (ThrSTATE(t)) {
|
---|
385 | case THRf_R_JOINABLE:
|
---|
386 | case THRf_R_JOINED:
|
---|
387 | ThrSETSTATE(t, THRf_R_JOINED);
|
---|
388 | MUTEX_UNLOCK(&t->mutex);
|
---|
389 | break;
|
---|
390 | case THRf_ZOMBIE:
|
---|
391 | ThrSETSTATE(t, THRf_DEAD);
|
---|
392 | MUTEX_UNLOCK(&t->mutex);
|
---|
393 | remove_thread(aTHX_ t);
|
---|
394 | break;
|
---|
395 | default:
|
---|
396 | MUTEX_UNLOCK(&t->mutex);
|
---|
397 | croak("can't join with thread");
|
---|
398 | /* NOTREACHED */
|
---|
399 | }
|
---|
400 | JOIN(t, &av);
|
---|
401 |
|
---|
402 | sv_2mortal((SV*)av);
|
---|
403 |
|
---|
404 | if (SvTRUE(*av_fetch(av, 0, FALSE))) {
|
---|
405 | /* Could easily speed up the following if necessary */
|
---|
406 | for (i = 1; i <= AvFILL(av); i++)
|
---|
407 | XPUSHs(*av_fetch(av, i, FALSE));
|
---|
408 | }
|
---|
409 | else {
|
---|
410 | STRLEN n_a;
|
---|
411 | char *mess = SvPV(*av_fetch(av, 1, FALSE), n_a);
|
---|
412 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
413 | "%p: join propagating die message: %s\n",
|
---|
414 | thr, mess));
|
---|
415 | croak(mess);
|
---|
416 | }
|
---|
417 | #endif
|
---|
418 |
|
---|
419 | void
|
---|
420 | detach(t)
|
---|
421 | Thread t
|
---|
422 | CODE:
|
---|
423 | #ifdef USE_5005THREADS
|
---|
424 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: detaching %p (state %u)\n",
|
---|
425 | thr, t, ThrSTATE(t)));
|
---|
426 | MUTEX_LOCK(&t->mutex);
|
---|
427 | switch (ThrSTATE(t)) {
|
---|
428 | case THRf_R_JOINABLE:
|
---|
429 | ThrSETSTATE(t, THRf_R_DETACHED);
|
---|
430 | /* fall through */
|
---|
431 | case THRf_R_DETACHED:
|
---|
432 | DETACH(t);
|
---|
433 | MUTEX_UNLOCK(&t->mutex);
|
---|
434 | break;
|
---|
435 | case THRf_ZOMBIE:
|
---|
436 | ThrSETSTATE(t, THRf_DEAD);
|
---|
437 | DETACH(t);
|
---|
438 | MUTEX_UNLOCK(&t->mutex);
|
---|
439 | remove_thread(aTHX_ t);
|
---|
440 | break;
|
---|
441 | default:
|
---|
442 | MUTEX_UNLOCK(&t->mutex);
|
---|
443 | croak("can't detach thread");
|
---|
444 | /* NOTREACHED */
|
---|
445 | }
|
---|
446 | #endif
|
---|
447 |
|
---|
448 | void
|
---|
449 | equal(t1, t2)
|
---|
450 | Thread t1
|
---|
451 | Thread t2
|
---|
452 | PPCODE:
|
---|
453 | PUSHs((t1 == t2) ? &PL_sv_yes : &PL_sv_no);
|
---|
454 |
|
---|
455 | void
|
---|
456 | flags(t)
|
---|
457 | Thread t
|
---|
458 | PPCODE:
|
---|
459 | #ifdef USE_5005THREADS
|
---|
460 | PUSHs(sv_2mortal(newSViv(t->flags)));
|
---|
461 | #endif
|
---|
462 |
|
---|
463 | void
|
---|
464 | done(t)
|
---|
465 | Thread t
|
---|
466 | PPCODE:
|
---|
467 | #ifdef USE_5005THREADS
|
---|
468 | PUSHs(t->thr_done ? &PL_sv_yes : &PL_sv_no);
|
---|
469 | #endif
|
---|
470 |
|
---|
471 | void
|
---|
472 | self(classname)
|
---|
473 | char * classname
|
---|
474 | PREINIT:
|
---|
475 | #ifdef USE_5005THREADS
|
---|
476 | SV *sv;
|
---|
477 | #endif
|
---|
478 | PPCODE:
|
---|
479 | #ifdef USE_5005THREADS
|
---|
480 | sv = newSViv(thr->tid);
|
---|
481 | sv_magic(sv, thr->oursv, '~', 0, 0);
|
---|
482 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
|
---|
483 | PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv),
|
---|
484 | gv_stashpv(classname, TRUE))));
|
---|
485 | #endif
|
---|
486 |
|
---|
487 | U32
|
---|
488 | tid(t)
|
---|
489 | Thread t
|
---|
490 | CODE:
|
---|
491 | #ifdef USE_5005THREADS
|
---|
492 | MUTEX_LOCK(&t->mutex);
|
---|
493 | RETVAL = t->tid;
|
---|
494 | MUTEX_UNLOCK(&t->mutex);
|
---|
495 | #else
|
---|
496 | RETVAL = 0;
|
---|
497 | #endif
|
---|
498 | OUTPUT:
|
---|
499 | RETVAL
|
---|
500 |
|
---|
501 | void
|
---|
502 | DESTROY(t)
|
---|
503 | SV * t
|
---|
504 | PPCODE:
|
---|
505 | PUSHs(t ? &PL_sv_yes : &PL_sv_no);
|
---|
506 |
|
---|
507 | void
|
---|
508 | yield()
|
---|
509 | CODE:
|
---|
510 | {
|
---|
511 | #ifdef USE_5005THREADS
|
---|
512 | YIELD;
|
---|
513 | #endif
|
---|
514 | }
|
---|
515 |
|
---|
516 | void
|
---|
517 | cond_wait(sv)
|
---|
518 | SV * sv
|
---|
519 | PREINIT:
|
---|
520 | #ifdef USE_5005THREADS
|
---|
521 | MAGIC * mg;
|
---|
522 | #endif
|
---|
523 | CODE:
|
---|
524 | #ifdef USE_5005THREADS
|
---|
525 | if (SvROK(sv))
|
---|
526 | sv = SvRV(sv);
|
---|
527 |
|
---|
528 | mg = condpair_magic(sv);
|
---|
529 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: cond_wait %p\n", thr, sv));
|
---|
530 | MUTEX_LOCK(MgMUTEXP(mg));
|
---|
531 | if (MgOWNER(mg) != thr) {
|
---|
532 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
533 | croak("cond_wait for lock that we don't own\n");
|
---|
534 | }
|
---|
535 | MgOWNER(mg) = 0;
|
---|
536 | COND_SIGNAL(MgOWNERCONDP(mg));
|
---|
537 | COND_WAIT(MgCONDP(mg), MgMUTEXP(mg));
|
---|
538 | while (MgOWNER(mg))
|
---|
539 | COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
|
---|
540 | MgOWNER(mg) = thr;
|
---|
541 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
542 | #endif
|
---|
543 |
|
---|
544 | void
|
---|
545 | cond_signal(sv)
|
---|
546 | SV * sv
|
---|
547 | PREINIT:
|
---|
548 | #ifdef USE_5005THREADS
|
---|
549 | MAGIC * mg;
|
---|
550 | #endif
|
---|
551 | CODE:
|
---|
552 | #ifdef USE_5005THREADS
|
---|
553 | if (SvROK(sv))
|
---|
554 | sv = SvRV(sv);
|
---|
555 |
|
---|
556 | mg = condpair_magic(sv);
|
---|
557 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: cond_signal %p\n",thr,sv));
|
---|
558 | MUTEX_LOCK(MgMUTEXP(mg));
|
---|
559 | if (MgOWNER(mg) != thr) {
|
---|
560 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
561 | croak("cond_signal for lock that we don't own\n");
|
---|
562 | }
|
---|
563 | COND_SIGNAL(MgCONDP(mg));
|
---|
564 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
565 | #endif
|
---|
566 |
|
---|
567 | void
|
---|
568 | cond_broadcast(sv)
|
---|
569 | SV * sv
|
---|
570 | PREINIT:
|
---|
571 | #ifdef USE_5005THREADS
|
---|
572 | MAGIC * mg;
|
---|
573 | #endif
|
---|
574 | CODE:
|
---|
575 | #ifdef USE_5005THREADS
|
---|
576 | if (SvROK(sv))
|
---|
577 | sv = SvRV(sv);
|
---|
578 |
|
---|
579 | mg = condpair_magic(sv);
|
---|
580 | DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: cond_broadcast %p\n",
|
---|
581 | thr, sv));
|
---|
582 | MUTEX_LOCK(MgMUTEXP(mg));
|
---|
583 | if (MgOWNER(mg) != thr) {
|
---|
584 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
585 | croak("cond_broadcast for lock that we don't own\n");
|
---|
586 | }
|
---|
587 | COND_BROADCAST(MgCONDP(mg));
|
---|
588 | MUTEX_UNLOCK(MgMUTEXP(mg));
|
---|
589 | #endif
|
---|
590 |
|
---|
591 | void
|
---|
592 | list(classname)
|
---|
593 | char * classname
|
---|
594 | PREINIT:
|
---|
595 | #ifdef USE_5005THREADS
|
---|
596 | Thread t;
|
---|
597 | AV * av;
|
---|
598 | SV ** svp;
|
---|
599 | int n = 0;
|
---|
600 | #endif
|
---|
601 | PPCODE:
|
---|
602 | #ifdef USE_5005THREADS
|
---|
603 | av = newAV();
|
---|
604 | /*
|
---|
605 | * Iterate until we have enough dynamic storage for all threads.
|
---|
606 | * We mustn't do any allocation while holding threads_mutex though.
|
---|
607 | */
|
---|
608 | MUTEX_LOCK(&PL_threads_mutex);
|
---|
609 | do {
|
---|
610 | n = PL_nthreads;
|
---|
611 | MUTEX_UNLOCK(&PL_threads_mutex);
|
---|
612 | if (AvFILL(av) < n - 1) {
|
---|
613 | int i = AvFILL(av);
|
---|
614 | for (i = AvFILL(av); i < n - 1; i++) {
|
---|
615 | SV *sv = newSViv(0); /* fill in tid later */
|
---|
616 | sv_magic(sv, 0, '~', 0, 0); /* fill in other magic later */
|
---|
617 | av_push(av, sv_bless(newRV_noinc(sv),
|
---|
618 | gv_stashpv(classname, TRUE)));
|
---|
619 |
|
---|
620 | }
|
---|
621 | }
|
---|
622 | MUTEX_LOCK(&PL_threads_mutex);
|
---|
623 | } while (n < PL_nthreads);
|
---|
624 | n = PL_nthreads; /* Get the final correct value */
|
---|
625 |
|
---|
626 | /*
|
---|
627 | * At this point, there's enough room to fill in av.
|
---|
628 | * Note that we are holding threads_mutex so the list
|
---|
629 | * won't change out from under us but all the remaining
|
---|
630 | * processing is "fast" (no blocking, malloc etc.)
|
---|
631 | */
|
---|
632 | t = thr;
|
---|
633 | svp = AvARRAY(av);
|
---|
634 | do {
|
---|
635 | SV *sv = (SV*)SvRV(*svp);
|
---|
636 | sv_setiv(sv, t->tid);
|
---|
637 | SvMAGIC(sv)->mg_obj = SvREFCNT_inc(t->oursv);
|
---|
638 | SvMAGIC(sv)->mg_flags |= MGf_REFCOUNTED;
|
---|
639 | SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
|
---|
640 | t = t->next;
|
---|
641 | svp++;
|
---|
642 | } while (t != thr);
|
---|
643 | /* */
|
---|
644 | MUTEX_UNLOCK(&PL_threads_mutex);
|
---|
645 | /* Truncate any unneeded slots in av */
|
---|
646 | av_fill(av, n - 1);
|
---|
647 | /* Finally, push all the new objects onto the stack and drop av */
|
---|
648 | EXTEND(SP, n);
|
---|
649 | for (svp = AvARRAY(av); n > 0; n--, svp++)
|
---|
650 | PUSHs(*svp);
|
---|
651 | (void)sv_2mortal((SV*)av);
|
---|
652 | #endif
|
---|
653 |
|
---|
654 |
|
---|
655 | MODULE = Thread PACKAGE = Thread::Signal
|
---|
656 |
|
---|
657 | void
|
---|
658 | kill_sighandler_thread()
|
---|
659 | PPCODE:
|
---|
660 | write(sig_pipe[1], "\0", 1);
|
---|
661 | PUSHs(&PL_sv_yes);
|
---|
662 |
|
---|
663 | void
|
---|
664 | init_thread_signals()
|
---|
665 | PPCODE:
|
---|
666 | PL_sighandlerp = handle_thread_signal;
|
---|
667 | if (pipe(sig_pipe) == -1)
|
---|
668 | XSRETURN_UNDEF;
|
---|
669 | PUSHs(&PL_sv_yes);
|
---|
670 |
|
---|
671 | void
|
---|
672 | await_signal()
|
---|
673 | PREINIT:
|
---|
674 | unsigned char c;
|
---|
675 | SSize_t ret;
|
---|
676 | CODE:
|
---|
677 | do {
|
---|
678 | ret = read(sig_pipe[0], &c, 1);
|
---|
679 | } while (ret == -1 && errno == EINTR);
|
---|
680 | if (ret == -1)
|
---|
681 | croak("panic: await_signal");
|
---|
682 | ST(0) = sv_newmortal();
|
---|
683 | if (ret)
|
---|
684 | sv_setsv(ST(0), c ? PL_psig_ptr[c] : &PL_sv_no);
|
---|
685 | DEBUG_S(PerlIO_printf(Perl_debug_log,
|
---|
686 | "await_signal returning %s\n", SvPEEK(ST(0))));
|
---|
687 |
|
---|
688 | MODULE = Thread PACKAGE = Thread::Specific
|
---|
689 |
|
---|
690 | void
|
---|
691 | data(classname = "Thread::Specific")
|
---|
692 | char * classname
|
---|
693 | PPCODE:
|
---|
694 | #ifdef USE_5005THREADS
|
---|
695 | if (AvFILL(thr->specific) == -1) {
|
---|
696 | GV *gv = gv_fetchpv("Thread::Specific::FIELDS", TRUE, SVt_PVHV);
|
---|
697 | av_store(thr->specific, 0, newRV((SV*)GvHV(gv)));
|
---|
698 | }
|
---|
699 | XPUSHs(sv_bless(newRV((SV*)thr->specific),gv_stashpv(classname,TRUE)));
|
---|
700 | #endif
|
---|