Rework threads destruct call
[p5sagit/p5-mst-13.2.git] / ext / threads / threads.xs
CommitLineData
68795e93 1#define PERL_NO_GET_CONTEXT
2#include "EXTERN.h"
3#include "perl.h"
4#include "XSUB.h"
0f1612a7 5#ifdef HAS_PPPORT_H
6# define NEED_newRV_noinc
7# define NEED_sv_2pv_nolen
8# include "ppport.h"
9# include "threads.h"
10#endif
68795e93 11
73e09c8f 12#ifdef USE_ITHREADS
13
c05ae023 14
68795e93 15#ifdef WIN32
16#include <windows.h>
17#include <win32thread.h>
68795e93 18#else
5c728af0 19#ifdef OS2
20typedef perl_os_thread pthread_t;
21#else
68795e93 22#include <pthread.h>
5c728af0 23#endif
68795e93 24#include <thread.h>
68795e93 25#define PERL_THREAD_SETSPECIFIC(k,v) pthread_setspecific(k,v)
26#ifdef OLD_PTHREADS_API
27#define PERL_THREAD_DETACH(t) pthread_detach(&(t))
68795e93 28#else
29#define PERL_THREAD_DETACH(t) pthread_detach((t))
c05ae023 30#endif /* OLD_PTHREADS_API */
467f3f08 31#endif
68795e93 32
c05ae023 33
34
35
62375a60 36/* Values for 'state' member */
37#define PERL_ITHR_JOINABLE 0
38#define PERL_ITHR_DETACHED 1
39#define PERL_ITHR_FINISHED 4
40#define PERL_ITHR_JOINED 2
41
68795e93 42typedef struct ithread_s {
6dfd2d05 43 struct ithread_s *next; /* Next thread in the list */
44 struct ithread_s *prev; /* Prev thread in the list */
68795e93 45 PerlInterpreter *interp; /* The threads interpreter */
f4cc38af 46 UV tid; /* Threads module's thread id */
6dfd2d05 47 perl_mutex mutex; /* Mutex for updating things in this struct */
f4cc38af 48 IV count; /* How many SVs have a reference to us */
6dfd2d05 49 signed char state; /* Are we detached ? */
a446a88f 50 int gimme; /* Context of create */
68795e93 51 SV* init_function; /* Code to run */
6dfd2d05 52 SV* params; /* Args to pass function */
68795e93 53#ifdef WIN32
54 DWORD thr; /* OS's idea if thread id */
55 HANDLE handle; /* OS's waitable handle */
56#else
57 pthread_t thr; /* OS's handle for the thread */
58#endif
59} ithread;
60
628ab322 61#define MY_CXT_KEY "threads::_guts" XS_VERSION
62
63typedef struct {
64 ithread *thread;
65} my_cxt_t;
66
67START_MY_CXT
68
69
f4cc38af 70static ithread *threads;
68795e93 71
58c2ef19 72static perl_mutex create_destruct_mutex; /* protects the creation and destruction of threads*/
68795e93 73
f4cc38af 74static UV tid_counter = 0;
f4cc38af 75static IV active_threads = 0;
c05ae023 76
77
f4cc38af 78static void
bcd9ca9b 79S_ithread_set (pTHX_ ithread* thread)
c05ae023 80{
628ab322 81 dMY_CXT;
82 MY_CXT.thread = thread;
c05ae023 83}
84
f4cc38af 85static ithread*
bcd9ca9b 86S_ithread_get (pTHX) {
628ab322 87 dMY_CXT;
88 return MY_CXT.thread;
c05ae023 89}
90
91
2e676467 92/* free any data (such as the perl interpreter) attached to an
93 * ithread structure. This is a bit like undef on SVs, where the SV
94 * isn't freed, but the PVX is.
95 * Must be called with thread->mutex already held
96 */
97
98static void
41fc7aad 99S_ithread_clear(pTHX_ ithread* thread)
2e676467 100{
101 PerlInterpreter *interp;
102 assert(thread->state & PERL_ITHR_FINISHED &&
103 (thread->state & PERL_ITHR_DETACHED ||
104 thread->state & PERL_ITHR_JOINED));
105
106 interp = thread->interp;
107 if (interp) {
108 dTHXa(interp);
109 ithread* current_thread;
110#ifdef OEMVS
111 void *ptr;
112#endif
113 PERL_SET_CONTEXT(interp);
bcd9ca9b 114 current_thread = S_ithread_get(aTHX);
115 S_ithread_set(aTHX_ thread);
2e676467 116
117 SvREFCNT_dec(thread->params);
118
119 thread->params = Nullsv;
120 perl_destruct(interp);
121 thread->interp = NULL;
122 }
123 if (interp)
124 perl_free(interp);
125 PERL_SET_CONTEXT(aTHX);
126}
127
68795e93 128
129/*
2e676467 130 * free an ithread structure and any attached data if its count == 0
68795e93 131 */
bcd9ca9b 132static void
385d56e4 133S_ithread_destruct (pTHX_ ithread* thread)
68795e93 134{
385d56e4 135#ifdef WIN32
136 HANDLE handle;
137#endif
138
68795e93 139 MUTEX_LOCK(&thread->mutex);
385d56e4 140
141 /* Thread is still in use */
68795e93 142 if (thread->count != 0) {
143 MUTEX_UNLOCK(&thread->mutex);
d1400e48 144 return;
68795e93 145 }
bcd9ca9b 146
385d56e4 147 /* Remove from circular list of threads */
148 MUTEX_LOCK(&create_destruct_mutex);
149 thread->next->prev = thread->prev;
150 thread->prev->next = thread->next;
151 thread->next = NULL;
152 thread->prev = NULL;
62375a60 153 MUTEX_UNLOCK(&create_destruct_mutex);
c2f2a82b 154
385d56e4 155 /* Thread is now disowned */
41fc7aad 156 S_ithread_clear(aTHX_ thread);
385d56e4 157
158#ifdef WIN32
159 handle = thread->handle;
160 thread->handle = NULL;
161#endif
d1400e48 162 MUTEX_UNLOCK(&thread->mutex);
1c3adb19 163 MUTEX_DESTROY(&thread->mutex);
385d56e4 164
c7667023 165#ifdef WIN32
385d56e4 166 if (handle)
167 CloseHandle(handle);
c7667023 168#endif
385d56e4 169
170 /* Call PerlMemShared_free() in the context of the "first" interpreter
171 * per http://www.nntp.perl.org/group/perl.perl5.porters/110772
172 */
173 aTHX = PL_curinterp;
1c3adb19 174 PerlMemShared_free(thread);
68795e93 175}
176
62375a60 177int
178Perl_ithread_hook(pTHX)
179{
180 int veto_cleanup = 0;
181 MUTEX_LOCK(&create_destruct_mutex);
182 if (aTHX == PL_curinterp && active_threads != 1) {
4447dfc1 183 if (ckWARN_d(WARN_THREADS))
184 Perl_warn(aTHX_ "A thread exited while %" IVdf " threads were running",
f4cc38af 185 active_threads);
62375a60 186 veto_cleanup = 1;
187 }
188 MUTEX_UNLOCK(&create_destruct_mutex);
189 return veto_cleanup;
190}
191
bcd9ca9b 192static void
193S_ithread_detach(pTHX_ ithread *thread)
62375a60 194{
195 MUTEX_LOCK(&thread->mutex);
196 if (!(thread->state & (PERL_ITHR_DETACHED|PERL_ITHR_JOINED))) {
197 thread->state |= PERL_ITHR_DETACHED;
198#ifdef WIN32
199 CloseHandle(thread->handle);
200 thread->handle = 0;
201#else
202 PERL_THREAD_DETACH(thread->thr);
203#endif
204 }
205 if ((thread->state & PERL_ITHR_FINISHED) &&
206 (thread->state & PERL_ITHR_DETACHED)) {
207 MUTEX_UNLOCK(&thread->mutex);
385d56e4 208 S_ithread_destruct(aTHX_ thread);
62375a60 209 }
210 else {
211 MUTEX_UNLOCK(&thread->mutex);
212 }
213}
68795e93 214
215/* MAGIC (in mg.h sense) hooks */
216
217int
218ithread_mg_get(pTHX_ SV *sv, MAGIC *mg)
219{
220 ithread *thread = (ithread *) mg->mg_ptr;
45977657 221 SvIV_set(sv, PTR2IV(thread));
68795e93 222 SvIOK_on(sv);
223 return 0;
224}
225
226int
227ithread_mg_free(pTHX_ SV *sv, MAGIC *mg)
228{
229 ithread *thread = (ithread *) mg->mg_ptr;
230 MUTEX_LOCK(&thread->mutex);
68795e93 231 thread->count--;
62375a60 232 if (thread->count == 0) {
1c3adb19 233 if(thread->state & PERL_ITHR_FINISHED &&
234 (thread->state & PERL_ITHR_DETACHED ||
235 thread->state & PERL_ITHR_JOINED))
236 {
237 MUTEX_UNLOCK(&thread->mutex);
385d56e4 238 S_ithread_destruct(aTHX_ thread);
1c3adb19 239 }
1ea20f42 240 else {
241 MUTEX_UNLOCK(&thread->mutex);
242 }
62375a60 243 }
244 else {
245 MUTEX_UNLOCK(&thread->mutex);
246 }
68795e93 247 return 0;
248}
249
250int
251ithread_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param)
252{
253 ithread *thread = (ithread *) mg->mg_ptr;
254 MUTEX_LOCK(&thread->mutex);
68795e93 255 thread->count++;
256 MUTEX_UNLOCK(&thread->mutex);
257 return 0;
258}
259
260MGVTBL ithread_vtbl = {
261 ithread_mg_get, /* get */
262 0, /* set */
263 0, /* len */
264 0, /* clear */
265 ithread_mg_free, /* free */
266 0, /* copy */
267 ithread_mg_dup /* dup */
268};
269
47ba8780 270
47ba8780 271/*
b1edfb69 272 * Starts executing the thread. Needs to clean up memory a tad better.
68795e93 273 * Passed as the C level function to run in the new thread
b1edfb69 274 */
47ba8780 275
276#ifdef WIN32
f4cc38af 277static THREAD_RET_TYPE
bcd9ca9b 278S_ithread_run(LPVOID arg) {
47ba8780 279#else
f4cc38af 280static void*
bcd9ca9b 281S_ithread_run(void * arg) {
47ba8780 282#endif
5b414d21 283 ithread* thread = (ithread*) arg;
47ba8780 284 dTHXa(thread->interp);
47ba8780 285 PERL_SET_CONTEXT(thread->interp);
bcd9ca9b 286 S_ithread_set(aTHX_ thread);
47ba8780 287
68795e93 288#if 0
289 /* Far from clear messing with ->thr child-side is a good idea */
290 MUTEX_LOCK(&thread->mutex);
47ba8780 291#ifdef WIN32
292 thread->thr = GetCurrentThreadId();
293#else
294 thread->thr = pthread_self();
295#endif
68795e93 296 MUTEX_UNLOCK(&thread->mutex);
297#endif
47ba8780 298
47ba8780 299 PL_perl_destruct_level = 2;
4f896ddc 300
47ba8780 301 {
68795e93 302 AV* params = (AV*) SvRV(thread->params);
f4cc38af 303 int len = (int)av_len(params)+1;
304 int ii;
47ba8780 305 dSP;
47ba8780 306 ENTER;
307 SAVETMPS;
308 PUSHMARK(SP);
f4cc38af 309 for(ii = 0; ii < len; ii++) {
68795e93 310 XPUSHs(av_shift(params));
47ba8780 311 }
312 PUTBACK;
f4cc38af 313 len = (int)call_sv(thread->init_function, thread->gimme|G_EVAL);
0405e91e 314
68795e93 315 SPAGAIN;
f4cc38af 316 for (ii=len-1; ii >= 0; ii--) {
e1c44605 317 SV *sv = POPs;
f4cc38af 318 av_store(params, ii, SvREFCNT_inc(sv));
a446a88f 319 }
4447dfc1 320 if (SvTRUE(ERRSV) && ckWARN_d(WARN_THREADS)) {
6b3c7930 321 Perl_warn(aTHX_ "thread failed to start: %" SVf, ERRSV);
a446a88f 322 }
47ba8780 323 FREETMPS;
324 LEAVE;
68795e93 325 SvREFCNT_dec(thread->init_function);
47ba8780 326 }
327
fd58862f 328 PerlIO_flush((PerlIO*)NULL);
68795e93 329 MUTEX_LOCK(&thread->mutex);
62375a60 330 thread->state |= PERL_ITHR_FINISHED;
331
332 if (thread->state & PERL_ITHR_DETACHED) {
47ba8780 333 MUTEX_UNLOCK(&thread->mutex);
385d56e4 334 S_ithread_destruct(aTHX_ thread);
47ba8780 335 } else {
62375a60 336 MUTEX_UNLOCK(&thread->mutex);
337 }
91604d21 338 MUTEX_LOCK(&create_destruct_mutex);
339 active_threads--;
340 assert( active_threads >= 0 );
341 MUTEX_UNLOCK(&create_destruct_mutex);
342
47ba8780 343#ifdef WIN32
344 return (DWORD)0;
e8f2bb9a 345#else
346 return 0;
47ba8780 347#endif
68795e93 348}
349
f4cc38af 350static SV *
68795e93 351ithread_to_SV(pTHX_ SV *obj, ithread *thread, char *classname, bool inc)
352{
353 SV *sv;
354 MAGIC *mg;
355 if (inc) {
356 MUTEX_LOCK(&thread->mutex);
357 thread->count++;
68795e93 358 MUTEX_UNLOCK(&thread->mutex);
359 }
360 if (!obj)
361 obj = newSV(0);
362 sv = newSVrv(obj,classname);
363 sv_setiv(sv,PTR2IV(thread));
364 mg = sv_magicext(sv,Nullsv,PERL_MAGIC_shared_scalar,&ithread_vtbl,(char *)thread,0);
365 mg->mg_flags |= MGf_DUP;
366 SvREADONLY_on(sv);
367 return obj;
368}
47ba8780 369
f4cc38af 370static ithread *
68795e93 371SV_to_ithread(pTHX_ SV *sv)
372{
68795e93 373 if (SvROK(sv))
374 {
c05ae023 375 return INT2PTR(ithread*, SvIV(SvRV(sv)));
68795e93 376 }
377 else
378 {
bcd9ca9b 379 return S_ithread_get(aTHX);
68795e93 380 }
47ba8780 381}
382
47ba8780 383/*
6dfd2d05 384 * ithread->create(); ( aka ithread->new() )
68795e93 385 * Called in context of parent thread
b1edfb69 386 */
47ba8780 387
f4cc38af 388static SV *
bcd9ca9b 389S_ithread_create(pTHX_ SV *obj, char* classname, SV* init_function, SV* params)
68795e93 390{
391 ithread* thread;
392 CLONE_PARAMS clone_param;
bcd9ca9b 393 ithread* current_thread = S_ithread_get(aTHX);
3b1c3273 394
395 SV** tmps_tmp = PL_tmps_stack;
f4cc38af 396 IV tmps_ix = PL_tmps_ix;
d94006e8 397#ifndef WIN32
398 int failure;
399 const char* panic = NULL;
400#endif
3b1c3273 401
c05ae023 402
58c2ef19 403 MUTEX_LOCK(&create_destruct_mutex);
8f77bfdb 404 thread = (ithread *) PerlMemShared_malloc(sizeof(ithread));
8043fdaf 405 if (!thread) {
406 MUTEX_UNLOCK(&create_destruct_mutex);
407 PerlLIO_write(PerlIO_fileno(Perl_error_log),
408 PL_no_mem, strlen(PL_no_mem));
409 my_exit(1);
410 }
68795e93 411 Zero(thread,1,ithread);
385d56e4 412
413 /* Add to threads list */
68795e93 414 thread->next = threads;
415 thread->prev = threads->prev;
f42ad631 416 threads->prev = thread;
68795e93 417 thread->prev->next = thread;
385d56e4 418
68795e93 419 /* Set count to 1 immediately in case thread exits before
420 * we return to caller !
421 */
422 thread->count = 1;
423 MUTEX_INIT(&thread->mutex);
424 thread->tid = tid_counter++;
a446a88f 425 thread->gimme = GIMME_V;
4f896ddc 426
68795e93 427 /* "Clone" our interpreter into the thread's interpreter
428 * This gives thread access to "static data" and code.
429 */
47ba8780 430
68795e93 431 PerlIO_flush((PerlIO*)NULL);
bcd9ca9b 432 S_ithread_set(aTHX_ thread);
3b1c3273 433
9c98058e 434 SAVEBOOL(PL_srand_called); /* Save this so it becomes the correct
435 value */
436 PL_srand_called = FALSE; /* Set it to false so we can detect
437 if it gets set during the clone */
3b1c3273 438
47ba8780 439#ifdef WIN32
68795e93 440 thread->interp = perl_clone(aTHX, CLONEf_KEEP_PTR_TABLE | CLONEf_CLONE_HOST);
47ba8780 441#else
68795e93 442 thread->interp = perl_clone(aTHX, CLONEf_KEEP_PTR_TABLE);
47ba8780 443#endif
ba14dd9a 444 /* perl_clone leaves us in new interpreter's context.
c8dae523 445 As it is tricky to spot an implicit aTHX, create a new scope
a446a88f 446 with aTHX matching the context for the duration of
ba14dd9a 447 our work for new interpreter.
448 */
449 {
450 dTHXa(thread->interp);
9c98058e 451
628ab322 452 MY_CXT_CLONE;
453
58c2ef19 454 /* Here we remove END blocks since they should only run
62375a60 455 in the thread they are created
58c2ef19 456 */
457 SvREFCNT_dec(PL_endav);
458 PL_endav = newAV();
d1400e48 459 clone_param.flags = 0;
ba14dd9a 460 thread->init_function = sv_dup(init_function, &clone_param);
461 if (SvREFCNT(thread->init_function) == 0) {
462 SvREFCNT_inc(thread->init_function);
d1400e48 463 }
3b1c3273 464
465
ba14dd9a 466
467 thread->params = sv_dup(params, &clone_param);
468 SvREFCNT_inc(thread->params);
3b1c3273 469
470
471 /* The code below checks that anything living on
472 the tmps stack and has been cloned (so it lives in the
473 ptr_table) has a refcount higher than 0
474
475 If the refcount is 0 it means that a something on the
476 stack/context was holding a reference to it and
477 since we init_stacks() in perl_clone that won't get
478 cleaned and we will get a leaked scalar.
479 The reason it was cloned was that it lived on the
480 @_ stack.
481
482 Example of this can be found in bugreport 15837
483 where calls in the parameter list end up as a temp
484
485 One could argue that this fix should be in perl_clone
486 */
487
488
489 while (tmps_ix > 0) {
490 SV* sv = (SV*)ptr_table_fetch(PL_ptr_table, tmps_tmp[tmps_ix]);
491 tmps_ix--;
492 if (sv && SvREFCNT(sv) == 0) {
493 SvREFCNT_inc(sv);
494 SvREFCNT_dec(sv);
495 }
496 }
497
498
499
ba14dd9a 500 SvTEMP_off(thread->init_function);
501 ptr_table_free(PL_ptr_table);
502 PL_ptr_table = NULL;
ffb29f90 503 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
ba14dd9a 504 }
bcd9ca9b 505 S_ithread_set(aTHX_ current_thread);
68795e93 506 PERL_SET_CONTEXT(aTHX);
47ba8780 507
68795e93 508 /* Start the thread */
47ba8780 509
510#ifdef WIN32
bcd9ca9b 511 thread->handle = CreateThread(NULL, 0, S_ithread_run,
47ba8780 512 (LPVOID)thread, 0, &thread->thr);
82c40bf6 513#else
fa26028c 514 {
515 static pthread_attr_t attr;
516 static int attr_inited = 0;
fa26028c 517 static int attr_joinable = PTHREAD_CREATE_JOINABLE;
518 if (!attr_inited) {
519 attr_inited = 1;
520 pthread_attr_init(&attr);
521 }
522# ifdef PTHREAD_ATTR_SETDETACHSTATE
523 PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable);
524# endif
3eb37d38 525# ifdef THREAD_CREATE_NEEDS_STACK
526 if(pthread_attr_setstacksize(&attr, THREAD_CREATE_NEEDS_STACK))
d94006e8 527 panic = "panic: pthread_attr_setstacksize failed";
3eb37d38 528# endif
529
3ad0b7d6 530#ifdef OLD_PTHREADS_API
d94006e8 531 failure
532 = panic ? 1 : pthread_create( &thread->thr, attr,
bcd9ca9b 533 S_ithread_run, (void *)thread);
47ba8780 534#else
58d975c3 535# if defined(HAS_PTHREAD_ATTR_SETSCOPE) && defined(PTHREAD_SCOPE_SYSTEM)
47cb5ff9 536 pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
19a077f6 537# endif
d94006e8 538 failure
539 = panic ? 1 : pthread_create( &thread->thr, &attr,
bcd9ca9b 540 S_ithread_run, (void *)thread);
47ba8780 541#endif
3ad0b7d6 542 }
82c40bf6 543#endif
bcd9ca9b 544
d94006e8 545 if (
546#ifdef WIN32
547 thread->handle == NULL
548#else
549 failure
550#endif
551 ) {
552 MUTEX_UNLOCK(&create_destruct_mutex);
553 sv_2mortal(params);
385d56e4 554 S_ithread_destruct(aTHX_ thread);
d94006e8 555#ifndef WIN32
556 if (panic)
557 Perl_croak(aTHX_ panic);
558#endif
559 return &PL_sv_undef;
560 }
58c2ef19 561 active_threads++;
562 MUTEX_UNLOCK(&create_destruct_mutex);
95393226 563 sv_2mortal(params);
3b1c3273 564
68795e93 565 return ithread_to_SV(aTHX_ obj, thread, classname, FALSE);
566}
47ba8780 567
f4cc38af 568static SV*
bcd9ca9b 569S_ithread_self (pTHX_ SV *obj, char* Class)
68795e93 570{
bcd9ca9b 571 ithread *thread = S_ithread_get(aTHX);
fe53aa5b 572 if (thread)
573 return ithread_to_SV(aTHX_ obj, thread, Class, TRUE);
574 else
575 Perl_croak(aTHX_ "panic: cannot find thread data");
c5661c80 576 return NULL; /* silence compiler warning */
47ba8780 577}
578
47ba8780 579
f4cc38af 580/* Joins the thread.
581 * This code takes the return value from the call_sv and sends it back.
582 */
583static AV*
bcd9ca9b 584S_ithread_join(pTHX_ SV *obj)
68795e93 585{
586 ithread *thread = SV_to_ithread(aTHX_ obj);
587 MUTEX_LOCK(&thread->mutex);
62375a60 588 if (thread->state & PERL_ITHR_DETACHED) {
a446a88f 589 MUTEX_UNLOCK(&thread->mutex);
590 Perl_croak(aTHX_ "Cannot join a detached thread");
591 }
62375a60 592 else if (thread->state & PERL_ITHR_JOINED) {
a446a88f 593 MUTEX_UNLOCK(&thread->mutex);
594 Perl_croak(aTHX_ "Thread already joined");
595 }
596 else {
e1c44605 597 AV* retparam;
47ba8780 598#ifdef WIN32
599 DWORD waitcode;
47ba8780 600#else
601 void *retval;
47ba8780 602#endif
47ba8780 603 MUTEX_UNLOCK(&thread->mutex);
68795e93 604#ifdef WIN32
605 waitcode = WaitForSingleObject(thread->handle, INFINITE);
c7667023 606 CloseHandle(thread->handle);
607 thread->handle = 0;
68795e93 608#else
609 pthread_join(thread->thr,&retval);
610#endif
47ba8780 611 MUTEX_LOCK(&thread->mutex);
e1c44605 612
62375a60 613 /* sv_dup over the args */
e1c44605 614 {
1d784c90 615 ithread* current_thread;
62375a60 616 AV* params = (AV*) SvRV(thread->params);
b23f1a86 617 PerlInterpreter *other_perl = thread->interp;
e1c44605 618 CLONE_PARAMS clone_params;
3275ba96 619 clone_params.stashes = newAV();
3ae345e3 620 clone_params.flags = CLONEf_JOIN_IN;
e1c44605 621 PL_ptr_table = ptr_table_new();
bcd9ca9b 622 current_thread = S_ithread_get(aTHX);
623 S_ithread_set(aTHX_ thread);
b23f1a86 624 /* ensure 'meaningful' addresses retain their meaning */
625 ptr_table_store(PL_ptr_table, &other_perl->Isv_undef, &PL_sv_undef);
626 ptr_table_store(PL_ptr_table, &other_perl->Isv_no, &PL_sv_no);
627 ptr_table_store(PL_ptr_table, &other_perl->Isv_yes, &PL_sv_yes);
0405e91e 628
767c1403 629#if 0
0405e91e 630 {
631 I32 len = av_len(params)+1;
632 I32 i;
633 for(i = 0; i < len; i++) {
767c1403 634 sv_dump(SvRV(AvARRAY(params)[i]));
0405e91e 635 }
636 }
767c1403 637#endif
e1c44605 638 retparam = (AV*) sv_dup((SV*)params, &clone_params);
b4cb676b 639#if 0
0405e91e 640 {
641 I32 len = av_len(retparam)+1;
642 I32 i;
643 for(i = 0; i < len; i++) {
b4cb676b 644 sv_dump(SvRV(AvARRAY(retparam)[i]));
0405e91e 645 }
646 }
b4cb676b 647#endif
bcd9ca9b 648 S_ithread_set(aTHX_ current_thread);
3275ba96 649 SvREFCNT_dec(clone_params.stashes);
e1c44605 650 SvREFCNT_inc(retparam);
651 ptr_table_free(PL_ptr_table);
652 PL_ptr_table = NULL;
653
654 }
6dfd2d05 655 /* We are finished with it */
62375a60 656 thread->state |= PERL_ITHR_JOINED;
41fc7aad 657 S_ithread_clear(aTHX_ thread);
47ba8780 658 MUTEX_UNLOCK(&thread->mutex);
57b48062 659
e1c44605 660 return retparam;
68795e93 661 }
e1c44605 662 return (AV*)NULL;
47ba8780 663}
664
f4cc38af 665static void
bcd9ca9b 666S_ithread_DESTROY(pTHX_ SV *sv)
68795e93 667{
668 ithread *thread = SV_to_ithread(aTHX_ sv);
68795e93 669 sv_unmagic(SvRV(sv),PERL_MAGIC_shared_scalar);
670}
8222d950 671
73e09c8f 672#endif /* USE_ITHREADS */
e1c44605 673
68795e93 674MODULE = threads PACKAGE = threads PREFIX = ithread_
675PROTOTYPES: DISABLE
8222d950 676
73e09c8f 677#ifdef USE_ITHREADS
678
68795e93 679void
f4cc38af 680ithread_create(...)
681 PREINIT:
682 char *classname;
683 SV *function_to_call;
684 AV *params;
685 int ii;
686 CODE:
687 if (items < 2)
688 Perl_croak(aTHX_ "Usage: threads->create(function, ...)");
689
690 classname = (char *)SvPV_nolen(ST(0));
691 function_to_call = ST(1);
692
693 /* Function args */
694 params = newAV();
695 if (items > 2) {
696 for (ii=2; ii < items; ii++) {
697 av_push(params, SvREFCNT_inc(ST(ii)));
698 }
699 }
700
701 /* Create thread */
bcd9ca9b 702 ST(0) = sv_2mortal(S_ithread_create(aTHX_ Nullsv,
f4cc38af 703 classname,
704 function_to_call,
705 newRV_noinc((SV*)params)));
706 /* XSRETURN(1); - implied */
707
8222d950 708
68795e93 709void
f4cc38af 710ithread_list(...)
711 PREINIT:
712 char *classname;
713 ithread *thr;
714 int list_context;
715 IV count = 0;
716 PPCODE:
717 /* Class method only */
718 if (SvROK(ST(0)))
719 Perl_croak(aTHX_ "Usage: threads->list()");
720 classname = (char *)SvPV_nolen(ST(0));
721
722 /* Calling context */
723 list_context = (GIMME_V == G_ARRAY);
724
725 /* Walk through threads list */
726 MUTEX_LOCK(&create_destruct_mutex);
727 for (thr = threads->next;
728 thr != threads;
729 thr = thr->next)
730 {
731 /* Ignore detached or joined threads */
732 if (thr->state & (PERL_ITHR_DETACHED|PERL_ITHR_JOINED)) {
733 continue;
734 }
735 /* Push object on stack if list context */
736 if (list_context) {
737 XPUSHs(sv_2mortal(ithread_to_SV(aTHX_ NULL, thr, classname, TRUE)));
738 }
739 count++;
740 }
741 MUTEX_UNLOCK(&create_destruct_mutex);
742 /* If scalar context, send back count */
743 if (! list_context) {
744 XSRETURN_IV(count);
745 }
678a9b6c 746
747
748void
f4cc38af 749ithread_self(...)
750 PREINIT:
751 char *classname;
752 CODE:
753 /* Class method only */
754 if (SvROK(ST(0)))
755 Perl_croak(aTHX_ "Usage: threads->self()");
756 classname = (char *)SvPV_nolen(ST(0));
757
bcd9ca9b 758 ST(0) = sv_2mortal(S_ithread_self(aTHX_ Nullsv, classname));
f4cc38af 759 /* XSRETURN(1); - implied */
47ba8780 760
47ba8780 761
762void
f4cc38af 763ithread_tid(...)
764 PREINIT:
765 ithread *thread;
766 CODE:
767 thread = SV_to_ithread(aTHX_ ST(0));
768 XST_mUV(0, thread->tid);
769 /* XSRETURN(1); - implied */
770
e1c44605 771
f9dff5f5 772void
f4cc38af 773ithread_join(...)
774 PREINIT:
775 AV *params;
776 int len;
777 int ii;
778 PPCODE:
779 /* Object method only */
780 if (! sv_isobject(ST(0)))
781 Perl_croak(aTHX_ "Usage: $thr->join()");
782
783 /* Join thread and get return values */
bcd9ca9b 784 params = S_ithread_join(aTHX_ ST(0));
f4cc38af 785 if (! params) {
786 XSRETURN_UNDEF;
787 }
788
789 /* Put return values on stack */
790 len = (int)AvFILL(params);
791 for (ii=0; ii <= len; ii++) {
792 SV* param = av_shift(params);
793 XPUSHs(sv_2mortal(param));
794 }
795
796 /* Free return value array */
797 SvREFCNT_dec(params);
798
799
800void
801ithread_yield(...)
802 CODE:
803 YIELD;
804
805
806void
807ithread_detach(...)
808 PREINIT:
809 ithread *thread;
810 CODE:
811 thread = SV_to_ithread(aTHX_ ST(0));
bcd9ca9b 812 S_ithread_detach(aTHX_ thread);
f4cc38af 813
47ba8780 814
815void
f4cc38af 816ithread_DESTROY(...)
817 CODE:
bcd9ca9b 818 S_ithread_DESTROY(aTHX_ ST(0));
f4cc38af 819
820
821void
822ithread_equal(...)
823 CODE:
824 /* Compares TIDs to determine thread equality.
825 * Return 0 on false for backward compatibility.
826 */
827 if (sv_isobject(ST(0)) && sv_isobject(ST(1))) {
828 ithread *thr1 = INT2PTR(ithread *, SvIV(SvRV(ST(0))));
829 ithread *thr2 = INT2PTR(ithread *, SvIV(SvRV(ST(1))));
830 if (thr1->tid == thr2->tid) {
831 XST_mYES(0);
832 } else {
833 XST_mIV(0, 0);
834 }
835 } else {
836 XST_mIV(0, 0);
837 }
838 /* XSRETURN(1); - implied */
839
47ba8780 840
47ba8780 841void
f4cc38af 842ithread_object(...)
843 PREINIT:
844 char *classname;
845 UV tid;
846 ithread *thr;
847 int found = 0;
848 CODE:
849 /* Class method only */
850 if (SvROK(ST(0)))
851 Perl_croak(aTHX_ "Usage: threads->object($tid)");
852 classname = (char *)SvPV_nolen(ST(0));
853
854 if ((items < 2) || ! SvOK(ST(1))) {
855 XSRETURN_UNDEF;
856 }
857
858 tid = SvUV(ST(1));
859
860 /* Walk through threads list */
861 MUTEX_LOCK(&create_destruct_mutex);
862 for (thr = threads->next;
863 thr != threads;
864 thr = thr->next)
865 {
866 /* Look for TID, but ignore detached or joined threads */
867 if ((thr->tid != tid) ||
868 (thr->state & (PERL_ITHR_DETACHED|PERL_ITHR_JOINED)))
869 {
870 continue;
871 }
872 /* Put object on stack */
873 ST(0) = sv_2mortal(ithread_to_SV(aTHX_ NULL, thr, classname, TRUE));
874 found = 1;
875 break;
876 }
877 MUTEX_UNLOCK(&create_destruct_mutex);
878 if (! found) {
879 XSRETURN_UNDEF;
880 }
881 /* XSRETURN(1); - implied */
882
883
884void
885ithread__handle(...);
886 PREINIT:
887 ithread *thread;
888 CODE:
889 thread = SV_to_ithread(aTHX_ ST(0));
890#ifdef WIN32
891 XST_mUV(0, PTR2UV(thread->handle));
892#else
75ba4ae2 893 XST_mUV(0, PTR2UV(&thread->thr));
f4cc38af 894#endif
895 /* XSRETURN(1); - implied */
68795e93 896
73e09c8f 897#endif /* USE_ITHREADS */
898
68795e93 899BOOT:
900{
73e09c8f 901#ifdef USE_ITHREADS
97aff369 902 MY_CXT_INIT;
68795e93 903 ithread* thread;
e1c44605 904 PL_perl_destruct_level = 2;
58c2ef19 905 MUTEX_INIT(&create_destruct_mutex);
906 MUTEX_LOCK(&create_destruct_mutex);
62375a60 907 PL_threadhook = &Perl_ithread_hook;
8f77bfdb 908 thread = (ithread *) PerlMemShared_malloc(sizeof(ithread));
8043fdaf 909 if (!thread) {
910 PerlLIO_write(PerlIO_fileno(Perl_error_log),
911 PL_no_mem, strlen(PL_no_mem));
912 my_exit(1);
913 }
68795e93 914 Zero(thread,1,ithread);
915 PL_perl_destruct_level = 2;
916 MUTEX_INIT(&thread->mutex);
385d56e4 917
918 /* Head of the threads list */
68795e93 919 threads = thread;
920 thread->next = thread;
921 thread->prev = thread;
385d56e4 922
68795e93 923 thread->interp = aTHX;
6dfd2d05 924 thread->count = 1; /* Immortal. */
68795e93 925 thread->tid = tid_counter++;
58c2ef19 926 active_threads++;
1fea7ed3 927 thread->state = PERL_ITHR_DETACHED;
68795e93 928#ifdef WIN32
929 thread->thr = GetCurrentThreadId();
930#else
931 thread->thr = pthread_self();
932#endif
62375a60 933
bcd9ca9b 934 S_ithread_set(aTHX_ thread);
58c2ef19 935 MUTEX_UNLOCK(&create_destruct_mutex);
73e09c8f 936#endif /* USE_ITHREADS */
68795e93 937}
938