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