Commit | Line | Data |
---|---|---|
68795e93 NIS |
1 | #define PERL_NO_GET_CONTEXT |
2 | #include "EXTERN.h" | |
3 | #include "perl.h" | |
4 | #include "XSUB.h" | |
5 | ||
73e09c8f JH |
6 | #ifdef USE_ITHREADS |
7 | ||
68795e93 NIS |
8 | #ifdef WIN32 |
9 | #include <windows.h> | |
10 | #include <win32thread.h> | |
11 | #define PERL_THREAD_SETSPECIFIC(k,v) TlsSetValue(k,v) | |
12 | #define PERL_THREAD_GETSPECIFIC(k,v) v = TlsGetValue(k) | |
13 | #define PERL_THREAD_ALLOC_SPECIFIC(k) \ | |
14 | STMT_START {\ | |
15 | if((k = TlsAlloc()) == TLS_OUT_OF_INDEXES) {\ | |
16 | PerlIO_printf(PerlIO_stderr(),"panic threads.h: TlsAlloc");\ | |
17 | exit(1);\ | |
18 | }\ | |
19 | } STMT_END | |
20 | #else | |
5c728af0 IZ |
21 | #ifdef OS2 |
22 | typedef perl_os_thread pthread_t; | |
23 | #else | |
68795e93 | 24 | #include <pthread.h> |
5c728af0 | 25 | #endif |
68795e93 NIS |
26 | #include <thread.h> |
27 | ||
28 | #define PERL_THREAD_SETSPECIFIC(k,v) pthread_setspecific(k,v) | |
29 | #ifdef OLD_PTHREADS_API | |
30 | #define PERL_THREAD_DETACH(t) pthread_detach(&(t)) | |
31 | #define PERL_THREAD_GETSPECIFIC(k,v) pthread_getspecific(k,&v) | |
32 | #define PERL_THREAD_ALLOC_SPECIFIC(k) STMT_START {\ | |
33 | if(pthread_keycreate(&(k),0)) {\ | |
34 | PerlIO_printf(PerlIO_stderr(), "panic threads.h: pthread_key_create");\ | |
35 | exit(1);\ | |
36 | }\ | |
37 | } STMT_END | |
38 | #else | |
39 | #define PERL_THREAD_DETACH(t) pthread_detach((t)) | |
40 | #define PERL_THREAD_GETSPECIFIC(k,v) v = pthread_getspecific(k) | |
41 | #define PERL_THREAD_ALLOC_SPECIFIC(k) STMT_START {\ | |
42 | if(pthread_key_create(&(k),0)) {\ | |
43 | PerlIO_printf(PerlIO_stderr(), "panic threads.h: pthread_key_create");\ | |
44 | exit(1);\ | |
45 | }\ | |
46 | } STMT_END | |
47 | #endif | |
48 | #endif | |
49 | ||
62375a60 NIS |
50 | /* Values for 'state' member */ |
51 | #define PERL_ITHR_JOINABLE 0 | |
52 | #define PERL_ITHR_DETACHED 1 | |
53 | #define PERL_ITHR_FINISHED 4 | |
54 | #define PERL_ITHR_JOINED 2 | |
55 | ||
68795e93 NIS |
56 | typedef struct ithread_s { |
57 | struct ithread_s *next; /* next thread in the list */ | |
58 | struct ithread_s *prev; /* prev thread in the list */ | |
59 | PerlInterpreter *interp; /* The threads interpreter */ | |
60 | I32 tid; /* threads module's thread id */ | |
61 | perl_mutex mutex; /* mutex for updating things in this struct */ | |
62 | I32 count; /* how many SVs have a reference to us */ | |
62375a60 | 63 | signed char state; /* are we detached ? */ |
a446a88f | 64 | int gimme; /* Context of create */ |
68795e93 NIS |
65 | SV* init_function; /* Code to run */ |
66 | SV* params; /* args to pass function */ | |
67 | #ifdef WIN32 | |
68 | DWORD thr; /* OS's idea if thread id */ | |
69 | HANDLE handle; /* OS's waitable handle */ | |
70 | #else | |
71 | pthread_t thr; /* OS's handle for the thread */ | |
72 | #endif | |
73 | } ithread; | |
74 | ||
75 | ithread *threads; | |
76 | ||
77 | /* Macros to supply the aTHX_ in an embed.h like manner */ | |
78 | #define ithread_join(thread) Perl_ithread_join(aTHX_ thread) | |
79 | #define ithread_DESTROY(thread) Perl_ithread_DESTROY(aTHX_ thread) | |
80 | #define ithread_CLONE(thread) Perl_ithread_CLONE(aTHX_ thread) | |
81 | #define ithread_detach(thread) Perl_ithread_detach(aTHX_ thread) | |
82 | #define ithread_tid(thread) ((thread)->tid) | |
f9dff5f5 | 83 | #define ithread_yield(thread) (YIELD); |
68795e93 | 84 | |
58c2ef19 | 85 | static perl_mutex create_destruct_mutex; /* protects the creation and destruction of threads*/ |
68795e93 NIS |
86 | |
87 | I32 tid_counter = 0; | |
62375a60 | 88 | I32 known_threads = 0; |
58c2ef19 | 89 | I32 active_threads = 0; |
68795e93 NIS |
90 | perl_key self_key; |
91 | ||
92 | /* | |
93 | * Clear up after thread is done with | |
94 | */ | |
95 | void | |
62375a60 | 96 | Perl_ithread_destruct (pTHX_ ithread* thread, const char *why) |
68795e93 NIS |
97 | { |
98 | MUTEX_LOCK(&thread->mutex); | |
62375a60 NIS |
99 | if (!thread->next) { |
100 | Perl_croak(aTHX_ "panic: destruct destroyed thread %p (%s)",thread, why); | |
101 | } | |
68795e93 NIS |
102 | if (thread->count != 0) { |
103 | MUTEX_UNLOCK(&thread->mutex); | |
d1400e48 | 104 | return; |
68795e93 | 105 | } |
58c2ef19 | 106 | MUTEX_LOCK(&create_destruct_mutex); |
68795e93 NIS |
107 | /* Remove from circular list of threads */ |
108 | if (thread->next == thread) { | |
109 | /* last one should never get here ? */ | |
110 | threads = NULL; | |
111 | } | |
112 | else { | |
f42ad631 AB |
113 | thread->next->prev = thread->prev; |
114 | thread->prev->next = thread->next; | |
68795e93 NIS |
115 | if (threads == thread) { |
116 | threads = thread->next; | |
117 | } | |
62375a60 NIS |
118 | thread->next = NULL; |
119 | thread->prev = NULL; | |
68795e93 | 120 | } |
62375a60 NIS |
121 | known_threads--; |
122 | assert( known_threads >= 0 ); | |
ba14dd9a | 123 | #if 0 |
62375a60 NIS |
124 | Perl_warn(aTHX_ "destruct %d @ %p by %p now %d", |
125 | thread->tid,thread->interp,aTHX, known_threads); | |
ba14dd9a | 126 | #endif |
62375a60 NIS |
127 | MUTEX_UNLOCK(&create_destruct_mutex); |
128 | /* Thread is now disowned */ | |
c2f2a82b AB |
129 | |
130 | if(thread->interp) { | |
1c3adb19 | 131 | dTHXa(thread->interp); |
c2f2a82b | 132 | ithread* current_thread; |
68795e93 | 133 | PERL_SET_CONTEXT(thread->interp); |
c2f2a82b AB |
134 | PERL_THREAD_GETSPECIFIC(self_key,current_thread); |
135 | PERL_THREAD_SETSPECIFIC(self_key,thread); | |
3b1c3273 AB |
136 | |
137 | ||
138 | ||
1c3adb19 | 139 | SvREFCNT_dec(thread->params); |
3b1c3273 AB |
140 | |
141 | ||
142 | ||
1c3adb19 | 143 | thread->params = Nullsv; |
c2f2a82b AB |
144 | perl_destruct(thread->interp); |
145 | perl_free(thread->interp); | |
68795e93 | 146 | thread->interp = NULL; |
c2f2a82b AB |
147 | PERL_THREAD_SETSPECIFIC(self_key,current_thread); |
148 | ||
68795e93 | 149 | } |
d1400e48 | 150 | MUTEX_UNLOCK(&thread->mutex); |
1c3adb19 AB |
151 | MUTEX_DESTROY(&thread->mutex); |
152 | PerlMemShared_free(thread); | |
1d784c90 | 153 | |
64821230 | 154 | PERL_SET_CONTEXT(aTHX); |
68795e93 NIS |
155 | } |
156 | ||
62375a60 NIS |
157 | int |
158 | Perl_ithread_hook(pTHX) | |
159 | { | |
160 | int veto_cleanup = 0; | |
161 | MUTEX_LOCK(&create_destruct_mutex); | |
162 | if (aTHX == PL_curinterp && active_threads != 1) { | |
3c42a367 | 163 | Perl_warn(aTHX_ "A thread exited while %" IVdf " threads were running", |
436c6dd3 | 164 | (IV)active_threads); |
62375a60 NIS |
165 | veto_cleanup = 1; |
166 | } | |
167 | MUTEX_UNLOCK(&create_destruct_mutex); | |
168 | return veto_cleanup; | |
169 | } | |
170 | ||
171 | void | |
172 | Perl_ithread_detach(pTHX_ ithread *thread) | |
173 | { | |
174 | MUTEX_LOCK(&thread->mutex); | |
175 | if (!(thread->state & (PERL_ITHR_DETACHED|PERL_ITHR_JOINED))) { | |
176 | thread->state |= PERL_ITHR_DETACHED; | |
177 | #ifdef WIN32 | |
178 | CloseHandle(thread->handle); | |
179 | thread->handle = 0; | |
180 | #else | |
181 | PERL_THREAD_DETACH(thread->thr); | |
182 | #endif | |
183 | } | |
184 | if ((thread->state & PERL_ITHR_FINISHED) && | |
185 | (thread->state & PERL_ITHR_DETACHED)) { | |
186 | MUTEX_UNLOCK(&thread->mutex); | |
187 | Perl_ithread_destruct(aTHX_ thread, "detach"); | |
188 | } | |
189 | else { | |
190 | MUTEX_UNLOCK(&thread->mutex); | |
191 | } | |
192 | } | |
68795e93 NIS |
193 | |
194 | /* MAGIC (in mg.h sense) hooks */ | |
195 | ||
196 | int | |
197 | ithread_mg_get(pTHX_ SV *sv, MAGIC *mg) | |
198 | { | |
199 | ithread *thread = (ithread *) mg->mg_ptr; | |
200 | SvIVX(sv) = PTR2IV(thread); | |
201 | SvIOK_on(sv); | |
202 | return 0; | |
203 | } | |
204 | ||
205 | int | |
206 | ithread_mg_free(pTHX_ SV *sv, MAGIC *mg) | |
207 | { | |
208 | ithread *thread = (ithread *) mg->mg_ptr; | |
209 | MUTEX_LOCK(&thread->mutex); | |
68795e93 | 210 | thread->count--; |
62375a60 | 211 | if (thread->count == 0) { |
1c3adb19 AB |
212 | if(thread->state & PERL_ITHR_FINISHED && |
213 | (thread->state & PERL_ITHR_DETACHED || | |
214 | thread->state & PERL_ITHR_JOINED)) | |
215 | { | |
216 | MUTEX_UNLOCK(&thread->mutex); | |
217 | Perl_ithread_destruct(aTHX_ thread, "no reference"); | |
218 | } | |
1ea20f42 AB |
219 | else { |
220 | MUTEX_UNLOCK(&thread->mutex); | |
221 | } | |
62375a60 NIS |
222 | } |
223 | else { | |
224 | MUTEX_UNLOCK(&thread->mutex); | |
225 | } | |
68795e93 NIS |
226 | return 0; |
227 | } | |
228 | ||
229 | int | |
230 | ithread_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) | |
231 | { | |
232 | ithread *thread = (ithread *) mg->mg_ptr; | |
233 | MUTEX_LOCK(&thread->mutex); | |
68795e93 NIS |
234 | thread->count++; |
235 | MUTEX_UNLOCK(&thread->mutex); | |
236 | return 0; | |
237 | } | |
238 | ||
239 | MGVTBL ithread_vtbl = { | |
240 | ithread_mg_get, /* get */ | |
241 | 0, /* set */ | |
242 | 0, /* len */ | |
243 | 0, /* clear */ | |
244 | ithread_mg_free, /* free */ | |
245 | 0, /* copy */ | |
246 | ithread_mg_dup /* dup */ | |
247 | }; | |
248 | ||
47ba8780 | 249 | |
47ba8780 | 250 | /* |
b1edfb69 | 251 | * Starts executing the thread. Needs to clean up memory a tad better. |
68795e93 | 252 | * Passed as the C level function to run in the new thread |
b1edfb69 | 253 | */ |
47ba8780 AB |
254 | |
255 | #ifdef WIN32 | |
68795e93 NIS |
256 | THREAD_RET_TYPE |
257 | Perl_ithread_run(LPVOID arg) { | |
47ba8780 | 258 | #else |
68795e93 NIS |
259 | void* |
260 | Perl_ithread_run(void * arg) { | |
47ba8780 | 261 | #endif |
5b414d21 | 262 | ithread* thread = (ithread*) arg; |
47ba8780 | 263 | dTHXa(thread->interp); |
47ba8780 | 264 | PERL_SET_CONTEXT(thread->interp); |
68795e93 | 265 | PERL_THREAD_SETSPECIFIC(self_key,thread); |
47ba8780 | 266 | |
68795e93 NIS |
267 | #if 0 |
268 | /* Far from clear messing with ->thr child-side is a good idea */ | |
269 | MUTEX_LOCK(&thread->mutex); | |
47ba8780 AB |
270 | #ifdef WIN32 |
271 | thread->thr = GetCurrentThreadId(); | |
272 | #else | |
273 | thread->thr = pthread_self(); | |
274 | #endif | |
68795e93 NIS |
275 | MUTEX_UNLOCK(&thread->mutex); |
276 | #endif | |
47ba8780 | 277 | |
47ba8780 | 278 | PL_perl_destruct_level = 2; |
4f896ddc | 279 | |
47ba8780 | 280 | { |
68795e93 NIS |
281 | AV* params = (AV*) SvRV(thread->params); |
282 | I32 len = av_len(params)+1; | |
47ba8780 AB |
283 | int i; |
284 | dSP; | |
47ba8780 AB |
285 | ENTER; |
286 | SAVETMPS; | |
287 | PUSHMARK(SP); | |
68795e93 NIS |
288 | for(i = 0; i < len; i++) { |
289 | XPUSHs(av_shift(params)); | |
47ba8780 AB |
290 | } |
291 | PUTBACK; | |
a446a88f | 292 | len = call_sv(thread->init_function, thread->gimme|G_EVAL); |
0405e91e | 293 | |
68795e93 | 294 | SPAGAIN; |
a446a88f | 295 | for (i=len-1; i >= 0; i--) { |
e1c44605 AB |
296 | SV *sv = POPs; |
297 | av_store(params, i, SvREFCNT_inc(sv)); | |
a446a88f | 298 | } |
a446a88f | 299 | if (SvTRUE(ERRSV)) { |
6b3c7930 | 300 | Perl_warn(aTHX_ "thread failed to start: %" SVf, ERRSV); |
a446a88f | 301 | } |
47ba8780 AB |
302 | FREETMPS; |
303 | LEAVE; | |
68795e93 | 304 | SvREFCNT_dec(thread->init_function); |
47ba8780 AB |
305 | } |
306 | ||
fd58862f | 307 | PerlIO_flush((PerlIO*)NULL); |
68795e93 | 308 | MUTEX_LOCK(&thread->mutex); |
62375a60 NIS |
309 | thread->state |= PERL_ITHR_FINISHED; |
310 | ||
311 | if (thread->state & PERL_ITHR_DETACHED) { | |
47ba8780 | 312 | MUTEX_UNLOCK(&thread->mutex); |
62375a60 | 313 | Perl_ithread_destruct(aTHX_ thread, "detached finish"); |
47ba8780 | 314 | } else { |
62375a60 NIS |
315 | MUTEX_UNLOCK(&thread->mutex); |
316 | } | |
91604d21 AB |
317 | MUTEX_LOCK(&create_destruct_mutex); |
318 | active_threads--; | |
319 | assert( active_threads >= 0 ); | |
320 | MUTEX_UNLOCK(&create_destruct_mutex); | |
321 | ||
47ba8780 AB |
322 | #ifdef WIN32 |
323 | return (DWORD)0; | |
e8f2bb9a JH |
324 | #else |
325 | return 0; | |
47ba8780 | 326 | #endif |
68795e93 NIS |
327 | } |
328 | ||
329 | SV * | |
330 | ithread_to_SV(pTHX_ SV *obj, ithread *thread, char *classname, bool inc) | |
331 | { | |
332 | SV *sv; | |
333 | MAGIC *mg; | |
334 | if (inc) { | |
335 | MUTEX_LOCK(&thread->mutex); | |
336 | thread->count++; | |
68795e93 NIS |
337 | MUTEX_UNLOCK(&thread->mutex); |
338 | } | |
339 | if (!obj) | |
340 | obj = newSV(0); | |
341 | sv = newSVrv(obj,classname); | |
342 | sv_setiv(sv,PTR2IV(thread)); | |
343 | mg = sv_magicext(sv,Nullsv,PERL_MAGIC_shared_scalar,&ithread_vtbl,(char *)thread,0); | |
344 | mg->mg_flags |= MGf_DUP; | |
345 | SvREADONLY_on(sv); | |
346 | return obj; | |
347 | } | |
47ba8780 | 348 | |
68795e93 NIS |
349 | ithread * |
350 | SV_to_ithread(pTHX_ SV *sv) | |
351 | { | |
352 | ithread *thread; | |
353 | if (SvROK(sv)) | |
354 | { | |
355 | thread = INT2PTR(ithread*, SvIV(SvRV(sv))); | |
356 | } | |
357 | else | |
358 | { | |
359 | PERL_THREAD_GETSPECIFIC(self_key,thread); | |
360 | } | |
361 | return thread; | |
47ba8780 AB |
362 | } |
363 | ||
47ba8780 | 364 | /* |
68795e93 NIS |
365 | * iThread->create(); ( aka iThread->new() ) |
366 | * Called in context of parent thread | |
b1edfb69 | 367 | */ |
47ba8780 | 368 | |
68795e93 NIS |
369 | SV * |
370 | Perl_ithread_create(pTHX_ SV *obj, char* classname, SV* init_function, SV* params) | |
371 | { | |
372 | ithread* thread; | |
373 | CLONE_PARAMS clone_param; | |
1d784c90 | 374 | ithread* current_thread; |
3b1c3273 AB |
375 | |
376 | SV** tmps_tmp = PL_tmps_stack; | |
377 | I32 tmps_ix = PL_tmps_ix; | |
378 | ||
1d784c90 | 379 | PERL_THREAD_GETSPECIFIC(self_key,current_thread); |
58c2ef19 | 380 | MUTEX_LOCK(&create_destruct_mutex); |
68795e93 NIS |
381 | thread = PerlMemShared_malloc(sizeof(ithread)); |
382 | Zero(thread,1,ithread); | |
383 | thread->next = threads; | |
384 | thread->prev = threads->prev; | |
f42ad631 | 385 | threads->prev = thread; |
68795e93 NIS |
386 | thread->prev->next = thread; |
387 | /* Set count to 1 immediately in case thread exits before | |
388 | * we return to caller ! | |
389 | */ | |
390 | thread->count = 1; | |
391 | MUTEX_INIT(&thread->mutex); | |
392 | thread->tid = tid_counter++; | |
a446a88f | 393 | thread->gimme = GIMME_V; |
4f896ddc | 394 | |
68795e93 NIS |
395 | /* "Clone" our interpreter into the thread's interpreter |
396 | * This gives thread access to "static data" and code. | |
397 | */ | |
47ba8780 | 398 | |
68795e93 | 399 | PerlIO_flush((PerlIO*)NULL); |
1d784c90 | 400 | PERL_THREAD_SETSPECIFIC(self_key,thread); |
3b1c3273 AB |
401 | |
402 | ||
403 | ||
47ba8780 | 404 | #ifdef WIN32 |
68795e93 | 405 | thread->interp = perl_clone(aTHX, CLONEf_KEEP_PTR_TABLE | CLONEf_CLONE_HOST); |
47ba8780 | 406 | #else |
68795e93 | 407 | thread->interp = perl_clone(aTHX, CLONEf_KEEP_PTR_TABLE); |
47ba8780 | 408 | #endif |
ba14dd9a | 409 | /* perl_clone leaves us in new interpreter's context. |
c8dae523 | 410 | As it is tricky to spot an implicit aTHX, create a new scope |
a446a88f | 411 | with aTHX matching the context for the duration of |
ba14dd9a NIS |
412 | our work for new interpreter. |
413 | */ | |
414 | { | |
415 | dTHXa(thread->interp); | |
58c2ef19 | 416 | /* Here we remove END blocks since they should only run |
62375a60 | 417 | in the thread they are created |
58c2ef19 NIS |
418 | */ |
419 | SvREFCNT_dec(PL_endav); | |
420 | PL_endav = newAV(); | |
d1400e48 | 421 | clone_param.flags = 0; |
ba14dd9a NIS |
422 | thread->init_function = sv_dup(init_function, &clone_param); |
423 | if (SvREFCNT(thread->init_function) == 0) { | |
424 | SvREFCNT_inc(thread->init_function); | |
d1400e48 | 425 | } |
3b1c3273 AB |
426 | |
427 | ||
ba14dd9a NIS |
428 | |
429 | thread->params = sv_dup(params, &clone_param); | |
430 | SvREFCNT_inc(thread->params); | |
3b1c3273 AB |
431 | |
432 | ||
433 | /* The code below checks that anything living on | |
434 | the tmps stack and has been cloned (so it lives in the | |
435 | ptr_table) has a refcount higher than 0 | |
436 | ||
437 | If the refcount is 0 it means that a something on the | |
438 | stack/context was holding a reference to it and | |
439 | since we init_stacks() in perl_clone that won't get | |
440 | cleaned and we will get a leaked scalar. | |
441 | The reason it was cloned was that it lived on the | |
442 | @_ stack. | |
443 | ||
444 | Example of this can be found in bugreport 15837 | |
445 | where calls in the parameter list end up as a temp | |
446 | ||
447 | One could argue that this fix should be in perl_clone | |
448 | */ | |
449 | ||
450 | ||
451 | while (tmps_ix > 0) { | |
452 | SV* sv = (SV*)ptr_table_fetch(PL_ptr_table, tmps_tmp[tmps_ix]); | |
453 | tmps_ix--; | |
454 | if (sv && SvREFCNT(sv) == 0) { | |
455 | SvREFCNT_inc(sv); | |
456 | SvREFCNT_dec(sv); | |
457 | } | |
458 | } | |
459 | ||
460 | ||
461 | ||
ba14dd9a NIS |
462 | SvTEMP_off(thread->init_function); |
463 | ptr_table_free(PL_ptr_table); | |
464 | PL_ptr_table = NULL; | |
ffb29f90 | 465 | PL_exit_flags |= PERL_EXIT_DESTRUCT_END; |
ba14dd9a | 466 | } |
1d784c90 | 467 | PERL_THREAD_SETSPECIFIC(self_key,current_thread); |
68795e93 | 468 | PERL_SET_CONTEXT(aTHX); |
47ba8780 | 469 | |
68795e93 | 470 | /* Start the thread */ |
47ba8780 AB |
471 | |
472 | #ifdef WIN32 | |
473 | ||
68795e93 | 474 | thread->handle = CreateThread(NULL, 0, Perl_ithread_run, |
47ba8780 AB |
475 | (LPVOID)thread, 0, &thread->thr); |
476 | ||
82c40bf6 | 477 | #else |
fa26028c AB |
478 | { |
479 | static pthread_attr_t attr; | |
480 | static int attr_inited = 0; | |
fa26028c AB |
481 | static int attr_joinable = PTHREAD_CREATE_JOINABLE; |
482 | if (!attr_inited) { | |
483 | attr_inited = 1; | |
484 | pthread_attr_init(&attr); | |
485 | } | |
486 | # ifdef PTHREAD_ATTR_SETDETACHSTATE | |
487 | PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable); | |
488 | # endif | |
3eb37d38 AB |
489 | # ifdef THREAD_CREATE_NEEDS_STACK |
490 | if(pthread_attr_setstacksize(&attr, THREAD_CREATE_NEEDS_STACK)) | |
491 | croak("panic: pthread_attr_setstacksize failed"); | |
492 | # endif | |
493 | ||
3ad0b7d6 | 494 | #ifdef OLD_PTHREADS_API |
68795e93 | 495 | pthread_create( &thread->thr, attr, Perl_ithread_run, (void *)thread); |
47ba8780 | 496 | #else |
68795e93 | 497 | pthread_create( &thread->thr, &attr, Perl_ithread_run, (void *)thread); |
47ba8780 | 498 | #endif |
3ad0b7d6 | 499 | } |
82c40bf6 | 500 | #endif |
62375a60 | 501 | known_threads++; |
58c2ef19 NIS |
502 | active_threads++; |
503 | MUTEX_UNLOCK(&create_destruct_mutex); | |
95393226 | 504 | sv_2mortal(params); |
3b1c3273 | 505 | |
68795e93 NIS |
506 | return ithread_to_SV(aTHX_ obj, thread, classname, FALSE); |
507 | } | |
47ba8780 | 508 | |
68795e93 NIS |
509 | SV* |
510 | Perl_ithread_self (pTHX_ SV *obj, char* Class) | |
511 | { | |
512 | ithread *thread; | |
513 | PERL_THREAD_GETSPECIFIC(self_key,thread); | |
514 | return ithread_to_SV(aTHX_ obj, thread, Class, TRUE); | |
47ba8780 AB |
515 | } |
516 | ||
517 | /* | |
e1c44605 | 518 | * Joins the thread this code needs to take the returnvalue from the |
68795e93 | 519 | * call_sv and send it back |
b1edfb69 | 520 | */ |
47ba8780 | 521 | |
68795e93 NIS |
522 | void |
523 | Perl_ithread_CLONE(pTHX_ SV *obj) | |
524 | { | |
525 | if (SvROK(obj)) | |
526 | { | |
527 | ithread *thread = SV_to_ithread(aTHX_ obj); | |
528 | } | |
529 | else | |
530 | { | |
436c6dd3 | 531 | Perl_warn(aTHX_ "CLONE %" SVf,obj); |
68795e93 | 532 | } |
47ba8780 AB |
533 | } |
534 | ||
62375a60 | 535 | AV* |
68795e93 NIS |
536 | Perl_ithread_join(pTHX_ SV *obj) |
537 | { | |
538 | ithread *thread = SV_to_ithread(aTHX_ obj); | |
539 | MUTEX_LOCK(&thread->mutex); | |
62375a60 | 540 | if (thread->state & PERL_ITHR_DETACHED) { |
a446a88f NIS |
541 | MUTEX_UNLOCK(&thread->mutex); |
542 | Perl_croak(aTHX_ "Cannot join a detached thread"); | |
543 | } | |
62375a60 | 544 | else if (thread->state & PERL_ITHR_JOINED) { |
a446a88f NIS |
545 | MUTEX_UNLOCK(&thread->mutex); |
546 | Perl_croak(aTHX_ "Thread already joined"); | |
547 | } | |
548 | else { | |
e1c44605 | 549 | AV* retparam; |
47ba8780 AB |
550 | #ifdef WIN32 |
551 | DWORD waitcode; | |
47ba8780 AB |
552 | #else |
553 | void *retval; | |
47ba8780 | 554 | #endif |
47ba8780 | 555 | MUTEX_UNLOCK(&thread->mutex); |
68795e93 NIS |
556 | #ifdef WIN32 |
557 | waitcode = WaitForSingleObject(thread->handle, INFINITE); | |
558 | #else | |
559 | pthread_join(thread->thr,&retval); | |
560 | #endif | |
47ba8780 | 561 | MUTEX_LOCK(&thread->mutex); |
e1c44605 | 562 | |
62375a60 | 563 | /* sv_dup over the args */ |
e1c44605 | 564 | { |
1d784c90 | 565 | ithread* current_thread; |
62375a60 | 566 | AV* params = (AV*) SvRV(thread->params); |
e1c44605 | 567 | CLONE_PARAMS clone_params; |
3275ba96 | 568 | clone_params.stashes = newAV(); |
0405e91e | 569 | clone_params.flags |= CLONEf_JOIN_IN; |
e1c44605 | 570 | PL_ptr_table = ptr_table_new(); |
1d784c90 AB |
571 | PERL_THREAD_GETSPECIFIC(self_key,current_thread); |
572 | PERL_THREAD_SETSPECIFIC(self_key,thread); | |
0405e91e | 573 | |
767c1403 | 574 | #if 0 |
0405e91e AB |
575 | { |
576 | I32 len = av_len(params)+1; | |
577 | I32 i; | |
578 | for(i = 0; i < len; i++) { | |
767c1403 | 579 | sv_dump(SvRV(AvARRAY(params)[i])); |
0405e91e AB |
580 | } |
581 | } | |
767c1403 | 582 | #endif |
e1c44605 | 583 | retparam = (AV*) sv_dup((SV*)params, &clone_params); |
b4cb676b | 584 | #if 0 |
0405e91e AB |
585 | { |
586 | I32 len = av_len(retparam)+1; | |
587 | I32 i; | |
588 | for(i = 0; i < len; i++) { | |
b4cb676b | 589 | sv_dump(SvRV(AvARRAY(retparam)[i])); |
0405e91e AB |
590 | } |
591 | } | |
b4cb676b | 592 | #endif |
1d784c90 | 593 | PERL_THREAD_SETSPECIFIC(self_key,current_thread); |
3275ba96 | 594 | SvREFCNT_dec(clone_params.stashes); |
e1c44605 AB |
595 | SvREFCNT_inc(retparam); |
596 | ptr_table_free(PL_ptr_table); | |
597 | PL_ptr_table = NULL; | |
598 | ||
599 | } | |
a446a88f | 600 | /* We have finished with it */ |
62375a60 | 601 | thread->state |= PERL_ITHR_JOINED; |
47ba8780 | 602 | MUTEX_UNLOCK(&thread->mutex); |
9684265f | 603 | sv_unmagic(SvRV(obj),PERL_MAGIC_shared_scalar); |
e1c44605 | 604 | return retparam; |
68795e93 | 605 | } |
e1c44605 | 606 | return (AV*)NULL; |
47ba8780 AB |
607 | } |
608 | ||
68795e93 | 609 | void |
68795e93 NIS |
610 | Perl_ithread_DESTROY(pTHX_ SV *sv) |
611 | { | |
612 | ithread *thread = SV_to_ithread(aTHX_ sv); | |
68795e93 NIS |
613 | sv_unmagic(SvRV(sv),PERL_MAGIC_shared_scalar); |
614 | } | |
8222d950 | 615 | |
73e09c8f | 616 | #endif /* USE_ITHREADS */ |
e1c44605 | 617 | |
68795e93 NIS |
618 | MODULE = threads PACKAGE = threads PREFIX = ithread_ |
619 | PROTOTYPES: DISABLE | |
8222d950 | 620 | |
73e09c8f JH |
621 | #ifdef USE_ITHREADS |
622 | ||
68795e93 NIS |
623 | void |
624 | ithread_new (classname, function_to_call, ...) | |
625 | char * classname | |
626 | SV * function_to_call | |
627 | CODE: | |
628 | { | |
629 | AV* params = newAV(); | |
630 | if (items > 2) { | |
631 | int i; | |
632 | for(i = 2; i < items ; i++) { | |
95393226 | 633 | av_push(params, SvREFCNT_inc(ST(i))); |
68795e93 NIS |
634 | } |
635 | } | |
636 | ST(0) = sv_2mortal(Perl_ithread_create(aTHX_ Nullsv, classname, function_to_call, newRV_noinc((SV*) params))); | |
637 | XSRETURN(1); | |
638 | } | |
8222d950 | 639 | |
68795e93 | 640 | void |
678a9b6c AB |
641 | ithread_list(char *classname) |
642 | PPCODE: | |
643 | { | |
644 | ithread *curr_thread; | |
645 | MUTEX_LOCK(&create_destruct_mutex); | |
646 | curr_thread = threads; | |
5eb9fe8f AB |
647 | if(curr_thread->tid != 0) |
648 | PUSHs( sv_2mortal(ithread_to_SV(aTHX_ NULL, curr_thread, classname, TRUE))); | |
678a9b6c | 649 | while(curr_thread) { |
678a9b6c AB |
650 | curr_thread = curr_thread->next; |
651 | if(curr_thread == threads) | |
652 | break; | |
6794f985 | 653 | if(curr_thread->state & PERL_ITHR_DETACHED || |
5eb9fe8f AB |
654 | curr_thread->state & PERL_ITHR_JOINED) |
655 | continue; | |
656 | PUSHs( sv_2mortal(ithread_to_SV(aTHX_ NULL, curr_thread, classname, TRUE))); | |
678a9b6c AB |
657 | } |
658 | MUTEX_UNLOCK(&create_destruct_mutex); | |
659 | } | |
660 | ||
661 | ||
662 | void | |
68795e93 NIS |
663 | ithread_self(char *classname) |
664 | CODE: | |
665 | { | |
666 | ST(0) = sv_2mortal(Perl_ithread_self(aTHX_ Nullsv,classname)); | |
667 | XSRETURN(1); | |
668 | } | |
47ba8780 AB |
669 | |
670 | int | |
68795e93 | 671 | ithread_tid(ithread *thread) |
47ba8780 AB |
672 | |
673 | void | |
68795e93 | 674 | ithread_join(SV *obj) |
e1c44605 AB |
675 | PPCODE: |
676 | { | |
677 | AV* params = Perl_ithread_join(aTHX_ obj); | |
678 | int i; | |
679 | I32 len = AvFILL(params); | |
680 | for (i = 0; i <= len; i++) { | |
1c3adb19 AB |
681 | SV* tmp = av_shift(params); |
682 | XPUSHs(tmp); | |
683 | sv_2mortal(tmp); | |
e1c44605 AB |
684 | } |
685 | SvREFCNT_dec(params); | |
686 | } | |
687 | ||
f9dff5f5 | 688 | void |
9d7debe1 | 689 | yield(...) |
70f2e746 DM |
690 | CODE: |
691 | { | |
692 | YIELD; | |
693 | } | |
694 | ||
47ba8780 AB |
695 | |
696 | void | |
68795e93 | 697 | ithread_detach(ithread *thread) |
47ba8780 | 698 | |
47ba8780 | 699 | void |
68795e93 NIS |
700 | ithread_DESTROY(SV *thread) |
701 | ||
73e09c8f JH |
702 | #endif /* USE_ITHREADS */ |
703 | ||
68795e93 NIS |
704 | BOOT: |
705 | { | |
73e09c8f | 706 | #ifdef USE_ITHREADS |
68795e93 | 707 | ithread* thread; |
e1c44605 | 708 | PL_perl_destruct_level = 2; |
68795e93 | 709 | PERL_THREAD_ALLOC_SPECIFIC(self_key); |
58c2ef19 NIS |
710 | MUTEX_INIT(&create_destruct_mutex); |
711 | MUTEX_LOCK(&create_destruct_mutex); | |
62375a60 | 712 | PL_threadhook = &Perl_ithread_hook; |
68795e93 NIS |
713 | thread = PerlMemShared_malloc(sizeof(ithread)); |
714 | Zero(thread,1,ithread); | |
715 | PL_perl_destruct_level = 2; | |
716 | MUTEX_INIT(&thread->mutex); | |
717 | threads = thread; | |
718 | thread->next = thread; | |
719 | thread->prev = thread; | |
720 | thread->interp = aTHX; | |
721 | thread->count = 1; /* imortal */ | |
722 | thread->tid = tid_counter++; | |
62375a60 | 723 | known_threads++; |
58c2ef19 | 724 | active_threads++; |
62375a60 | 725 | thread->state = 1; |
68795e93 NIS |
726 | #ifdef WIN32 |
727 | thread->thr = GetCurrentThreadId(); | |
728 | #else | |
729 | thread->thr = pthread_self(); | |
730 | #endif | |
62375a60 | 731 | |
68795e93 | 732 | PERL_THREAD_SETSPECIFIC(self_key,thread); |
58c2ef19 | 733 | MUTEX_UNLOCK(&create_destruct_mutex); |
73e09c8f | 734 | #endif /* USE_ITHREADS */ |
68795e93 NIS |
735 | } |
736 |