56c046d0c29ac2fa7f07adc896c4f434602ccc7f
[p5sagit/p5-mst-13.2.git] / ext / threads / threads.xs
1 #include "threads.h"
2
3 /*
4  *      Starts executing the thread. Needs to clean up memory a tad better.
5  */
6
7 #ifdef WIN32
8 THREAD_RET_TYPE Perl_thread_run(LPVOID arg) {
9 #else
10 void* Perl_thread_run(void * arg) {
11 #endif
12         ithread* thread = (ithread*) arg;
13         SV* thread_tid_ptr;
14         SV* thread_ptr;
15         dTHXa(thread->interp);
16         PERL_SET_CONTEXT(thread->interp);
17
18 #ifdef WIN32
19         thread->thr = GetCurrentThreadId();
20 #else
21         thread->thr = pthread_self();
22 #endif
23
24         SHAREDSvLOCK(threads);
25         SHAREDSvEDIT(threads);
26         PERL_THREAD_SETSPECIFIC(self_key,INT2PTR(void*,thread->tid));
27         thread_tid_ptr = Perl_newSVuv(PL_sharedsv_space, thread->tid);  
28         thread_ptr = Perl_newSVuv(PL_sharedsv_space, PTR2UV(thread));
29         hv_store_ent((HV*)SHAREDSvGET(threads), thread_tid_ptr, thread_ptr,0);
30         SvREFCNT_dec(thread_tid_ptr);
31         SHAREDSvRELEASE(threads);
32         SHAREDSvUNLOCK(threads);
33         PL_perl_destruct_level = 2;
34
35         {
36
37                 AV* params;
38                 I32 len;
39                 int i;
40                 dSP;
41                 params = (AV*) SvRV(thread->params);
42                 len = av_len(params);
43                 ENTER;
44                 SAVETMPS;
45                 PUSHMARK(SP);
46                 if(len > -1) {
47                         for(i = 0; i < len + 1; i++) {
48                                 XPUSHs(av_shift(params));
49                         }       
50                 }
51                 PUTBACK;
52                 call_sv(thread->init_function, G_DISCARD);
53                 FREETMPS;
54                 LEAVE;
55
56
57         }
58
59         MUTEX_LOCK(&thread->mutex);
60         PerlIO_flush((PerlIO*)NULL);
61         perl_destruct(thread->interp);  
62         perl_free(thread->interp);
63         if(thread->detached == 1) {
64                 MUTEX_UNLOCK(&thread->mutex);
65                 Perl_thread_destruct(thread);
66         } else {
67                 MUTEX_UNLOCK(&thread->mutex);
68         }
69 #ifdef WIN32
70         return (DWORD)0;
71 #else
72         return 0;
73 #endif
74
75 }
76
77 /*
78  * iThread->create();
79  */
80
81 SV* Perl_thread_create(char* class, SV* init_function, SV* params) {
82         ithread* thread = malloc(sizeof(ithread));
83         SV*      obj_ref;
84         SV*      obj;
85         SV*             temp_store;
86         PerlInterpreter *current_perl;
87
88         MUTEX_LOCK(&create_mutex);  
89         obj_ref = newSViv(0);
90         obj = newSVrv(obj_ref, class);
91         sv_setiv(obj, (IV)thread);
92         SvREADONLY_on(obj);
93         PerlIO_flush((PerlIO*)NULL);
94         current_perl = PERL_GET_CONTEXT;        
95
96         /*
97          * here we put the values of params and function to call onto
98          * namespace, this is so perl will properly clone them when we
99          * call perl_clone.
100          */
101
102         temp_store = Perl_get_sv(current_perl, "threads::paramtempstore",
103                                  TRUE | GV_ADDMULTI);
104         Perl_sv_setsv_flags(current_perl, temp_store,params, SV_GMAGIC);
105         params = NULL;
106         temp_store = NULL;
107
108         temp_store = Perl_get_sv(current_perl, "threads::calltempstore",
109                                  TRUE | GV_ADDMULTI);
110         Perl_sv_setsv_flags(current_perl,temp_store, init_function, SV_GMAGIC);
111         init_function = NULL;
112         temp_store = NULL;
113
114 #ifdef WIN32
115         thread->interp = perl_clone(current_perl, 4);
116 #else
117         thread->interp = perl_clone(current_perl, 0);
118 #endif
119
120         thread->init_function = newSVsv(Perl_get_sv(thread->interp,
121                                                     "threads::calltempstore",FALSE));
122         thread->params = newSVsv(Perl_get_sv(thread->interp,
123                                              "threads::paramtempstore",FALSE));
124
125         /*
126          * And here we make sure we clean up the data we put in the
127          * namespace of iThread, both in the new and the calling
128          * inteprreter */
129
130         temp_store = Perl_get_sv(thread->interp, "threads::paramtempstore",FALSE);
131         Perl_sv_setsv_flags(thread->interp,temp_store, &PL_sv_undef, SV_GMAGIC);
132
133         temp_store = Perl_get_sv(thread->interp,"threads::calltempstore",FALSE);
134         Perl_sv_setsv_flags(thread->interp,temp_store, &PL_sv_undef, SV_GMAGIC);
135
136         PERL_SET_CONTEXT(current_perl);
137
138         temp_store = Perl_get_sv(current_perl,"threads::paramtempstore",FALSE);
139         Perl_sv_setsv_flags(current_perl, temp_store, &PL_sv_undef, SV_GMAGIC);
140
141         temp_store = Perl_get_sv(current_perl,"threads::calltempstore",FALSE);
142         Perl_sv_setsv_flags(current_perl, temp_store, &PL_sv_undef, SV_GMAGIC);
143
144         /* let's init the thread */
145
146         MUTEX_INIT(&thread->mutex);
147         thread->tid = tid_counter++;
148         thread->detached = 0;
149         thread->count = 1;
150
151 #ifdef WIN32
152
153         thread->handle = CreateThread(NULL, 0, Perl_thread_run,
154                         (LPVOID)thread, 0, &thread->thr);
155
156
157 #else
158         {
159           static pthread_attr_t attr;
160           static int attr_inited = 0;
161           sigset_t fullmask, oldmask;
162           static int attr_joinable = PTHREAD_CREATE_JOINABLE;
163           if (!attr_inited) {
164             attr_inited = 1;
165             pthread_attr_init(&attr);
166           }
167 #  ifdef PTHREAD_ATTR_SETDETACHSTATE
168             PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable);
169 #  endif
170 #  ifdef THREAD_CREATE_NEEDS_STACK
171             if(pthread_attr_setstacksize(&attr, THREAD_CREATE_NEEDS_STACK))
172               croak("panic: pthread_attr_setstacksize failed");
173 #  endif
174
175 #ifdef OLD_PTHREADS_API
176           pthread_create( &thread->thr, attr, Perl_thread_run, (void *)thread);
177 #else
178           pthread_create( &thread->thr, &attr, Perl_thread_run, (void *)thread);
179 #endif
180         }
181 #endif
182         MUTEX_UNLOCK(&create_mutex);    
183
184         return obj_ref;
185 }
186
187 /*
188  * returns the id of the thread
189  */
190 I32 Perl_thread_tid (SV* obj) {
191         ithread* thread;
192         if(!SvROK(obj)) {
193                 obj = Perl_thread_self(SvPV_nolen(obj));
194                 thread = (ithread*)SvIV(SvRV(obj));     
195                 SvREFCNT_dec(obj);
196         } else {
197                 thread = (ithread*)SvIV(SvRV(obj));     
198         }
199         return thread->tid;
200 }
201
202 SV* Perl_thread_self (char* class) {
203         dTHX;
204         SV*      obj_ref;
205         SV*      obj;
206         SV*     thread_tid_ptr;
207         SV*     thread_ptr;
208         HE*     thread_entry;
209         void*   id;
210         PERL_THREAD_GETSPECIFIC(self_key,id);
211         SHAREDSvLOCK(threads);
212         SHAREDSvEDIT(threads);
213         
214         thread_tid_ptr = Perl_newSVuv(PL_sharedsv_space, PTR2UV(id));   
215
216         thread_entry = Perl_hv_fetch_ent(PL_sharedsv_space,
217                                          (HV*) SHAREDSvGET(threads),
218                                          thread_tid_ptr, 0,0);
219         thread_ptr = HeVAL(thread_entry);
220         SvREFCNT_dec(thread_tid_ptr);   
221         SHAREDSvRELEASE(threads);
222         SHAREDSvUNLOCK(threads);
223
224         obj_ref = newSViv(0);
225         obj = newSVrv(obj_ref, class);
226         sv_setsv(obj, thread_ptr);
227         SvREADONLY_on(obj);
228         return obj_ref;
229 }
230
231 /*
232  * joins the thread this code needs to take the returnvalue from the
233  * call_sv and send it back */
234
235 void Perl_thread_join(SV* obj) {
236         ithread* thread = (ithread*)SvIV(SvRV(obj));
237 #ifdef WIN32
238         DWORD waitcode;
239         waitcode = WaitForSingleObject(thread->handle, INFINITE);
240 #else
241         void *retval;
242         pthread_join(thread->thr,&retval);
243 #endif
244 }
245
246 /* detaches a thread
247  * needs to better clean up memory */
248
249 void Perl_thread_detach(SV* obj) {
250         ithread* thread = (ithread*)SvIV(SvRV(obj));
251         MUTEX_LOCK(&thread->mutex);
252         thread->detached = 1;
253         PERL_THREAD_DETACH(thread->thr);
254         MUTEX_UNLOCK(&thread->mutex);
255 }
256
257 void Perl_thread_DESTROY (SV* obj) {
258         ithread* thread = (ithread*)SvIV(SvRV(obj));
259         
260         MUTEX_LOCK(&thread->mutex);
261         thread->count--;
262         MUTEX_UNLOCK(&thread->mutex);
263         Perl_thread_destruct(thread);
264 }
265
266 void Perl_thread_destruct (ithread* thread) {
267         return;
268         MUTEX_LOCK(&thread->mutex);
269         if(thread->count != 0) {
270                 MUTEX_UNLOCK(&thread->mutex);
271                 return; 
272         }
273         MUTEX_UNLOCK(&thread->mutex);
274         /* it is safe noone is holding a ref to this */
275         /*printf("proper destruction!\n");*/
276 }
277
278 MODULE = threads                PACKAGE = threads               
279 BOOT:
280         Perl_sharedsv_init(aTHX);
281         PERL_THREAD_ALLOC_SPECIFIC(self_key);
282         PL_perl_destruct_level = 2;
283         threads = Perl_sharedsv_new(aTHX);
284         SHAREDSvEDIT(threads);
285         SHAREDSvGET(threads) = (SV *)newHV();
286         SHAREDSvRELEASE(threads);
287         {
288             
289         
290             SV* temp = get_sv("threads::sharedsv_space", TRUE | GV_ADDMULTI);
291             SV* temp2 = newSViv((IV)PL_sharedsv_space );
292             sv_setsv( temp , temp2 );
293         }
294         {
295                 ithread* thread = malloc(sizeof(ithread));
296                 SV* thread_tid_ptr;
297                 SV* thread_ptr;
298                 MUTEX_INIT(&thread->mutex);
299                 thread->tid = 0;
300 #ifdef WIN32
301                 thread->thr = GetCurrentThreadId();
302 #else
303                 thread->thr = pthread_self();
304 #endif
305                 SHAREDSvEDIT(threads);
306                 PERL_THREAD_ALLOC_SPECIFIC(self_key);
307                 PERL_THREAD_SETSPECIFIC(self_key,0);
308                 thread_tid_ptr = Perl_newSVuv(PL_sharedsv_space, 0);
309                 thread_ptr = Perl_newSVuv(PL_sharedsv_space, PTR2UV(thread));
310                 hv_store_ent((HV*) SHAREDSvGET(threads), thread_tid_ptr, thread_ptr,0);
311                 SvREFCNT_dec(thread_tid_ptr);
312                 SHAREDSvRELEASE(threads);
313         }
314         MUTEX_INIT(&create_mutex);
315
316 PROTOTYPES: DISABLE
317
318 SV *
319 create (class, function_to_call, ...)
320         char *  class
321         SV *    function_to_call
322                 CODE:
323                         AV* params = newAV();
324                         if(items > 2) {
325                                 int i;
326                                 for(i = 2; i < items ; i++) {
327                                         av_push(params, ST(i));
328                                 }
329                         }
330                         RETVAL = Perl_thread_create(class, function_to_call, newRV_noinc((SV*) params));
331                         OUTPUT:
332                         RETVAL
333
334 SV *
335 self (class)
336                 char* class
337         CODE:
338                 RETVAL = Perl_thread_self(class);
339         OUTPUT:
340                 RETVAL
341
342 int
343 tid (obj)       
344                 SV *    obj;
345         CODE:
346                 RETVAL = Perl_thread_tid(obj);
347         OUTPUT:
348         RETVAL
349
350 void
351 join (obj)
352         SV *    obj
353         PREINIT:
354         I32* temp;
355         PPCODE:
356         temp = PL_markstack_ptr++;
357         Perl_thread_join(obj);
358         if (PL_markstack_ptr != temp) {
359           /* truly void, because dXSARGS not invoked */
360           PL_markstack_ptr = temp;
361           XSRETURN_EMPTY; /* return empty stack */
362         }
363         /* must have used dXSARGS; list context implied */
364         return; /* assume stack size is correct */
365
366 void
367 detach (obj)
368         SV *    obj
369         PREINIT:
370         I32* temp;
371         PPCODE:
372         temp = PL_markstack_ptr++;
373         Perl_thread_detach(obj);
374         if (PL_markstack_ptr != temp) {
375           /* truly void, because dXSARGS not invoked */
376           PL_markstack_ptr = temp;
377           XSRETURN_EMPTY; /* return empty stack */
378         }
379         /* must have used dXSARGS; list context implied */
380         return; /* assume stack size is correct */
381
382 void
383 DESTROY (obj)
384         SV *    obj
385         PREINIT:
386         I32* temp;
387         PPCODE:
388         temp = PL_markstack_ptr++;
389         Perl_thread_DESTROY(obj);
390         if (PL_markstack_ptr != temp) {
391           /* truly void, because dXSARGS not invoked */
392           PL_markstack_ptr = temp;
393           XSRETURN_EMPTY; /* return empty stack */
394         }
395         /* must have used dXSARGS; list context implied */
396         return; /* assume stack size is correct */
397