Create a struct for all perls globals (as an option)
[p5sagit/p5-mst-13.2.git] / ext / Thread / Thread.xs
index d132394..c5adcb3 100644 (file)
@@ -16,13 +16,12 @@ static U32 threadnum = 0;
 static int sig_pipe[2];
             
 #ifndef THREAD_RET_TYPE
-typedef struct thread *Thread;
 #define THREAD_RET_TYPE void *
 #define THREAD_RET_CAST(x) ((THREAD_RET_TYPE) x)
-#endif;
+#endif
 
 static void
-remove_thread(struct thread *t)
+remove_thread(struct perl_thread *t)
 {
 #ifdef USE_THREADS
     DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(),
@@ -47,7 +46,7 @@ threadstart(void *arg)
     dSP;
     I32 oldscope = scopestack_ix;
     I32 retval;
-    AV *returnav;
+    AV *av;
     int i;
 
     DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n",
@@ -86,11 +85,14 @@ threadstart(void *arg)
     I32 oldmark = TOPMARK;
     I32 oldscope = scopestack_ix;
     I32 retval;
-    AV *returnav;
+    SV *sv;
+    AV *av = newAV();
     int i, ret;
     dJMPENV;
+    DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p waiting to start\n",
+                         thr));
 
-    /* Don't call *anything* requiring dTHR until after pthread_setspecific */
+    /* Don't call *anything* requiring dTHR until after SET_THR() */
     /*
      * Wait until our creator releases us. If we didn't do this, then
      * it would be potentially possible for out thread to carry on and
@@ -103,8 +105,8 @@ threadstart(void *arg)
 
     /*
      * It's safe to wait until now to set the thread-specific pointer
-     * from our pthread_t structure to our struct thread, since we're
-     * the only thread who can get at it anyway.
+     * from our pthread_t structure to our struct perl_thread, since
+     * we're the only thread who can get at it anyway.
      */
     SET_THR(thr);
 
@@ -112,55 +114,42 @@ threadstart(void *arg)
     DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n",
                          thr, SvPEEK(TOPs)));
 
-    JMPENV_PUSH(ret);
-    switch (ret) {
-    case 3:
-        PerlIO_printf(PerlIO_stderr(), "panic: threadstart\n");
-       /* fall through */
-    case 1:
-       STATUS_ALL_FAILURE;
-       /* fall through */
-    case 2:
-       /* my_exit() was called */
-       while (scopestack_ix > oldscope)
-           LEAVE;
-       JMPENV_POP;
-       av_store(returnav, 0, newSViv(statusvalue));
-       goto finishoff;
-    }
-
-    CATCH_SET(TRUE);
-
-    /* Now duplicate most of perl_call_sv but with a few twists */
-    op = (OP*)&myop;
-    Zero(op, 1, LOGOP);
-    myop.op_flags = OPf_STACKED;
-    myop.op_next = Nullop;
-    myop.op_flags |= OPf_KNOW;
-    myop.op_flags |= OPf_WANT_LIST;
-    op = pp_entersub(ARGS);
-    if (op)
-       runops();
+    sv = POPs;
+    PUTBACK;
+    perl_call_sv(sv, G_ARRAY|G_EVAL);
     SPAGAIN;
     retval = sp - (stack_base + oldmark);
     sp = stack_base + oldmark + 1;
-    DEBUG_L(for (i = 1; i <= retval; i++)
-               PerlIO_printf(PerlIO_stderr(),
-                             "%p returnav[%d] = %s\n",
-                             thr, i, SvPEEK(sp[i - 1]));)
-    returnav = newAV();
-    av_store(returnav, 0, newSVpv("", 0));
-    for (i = 1; i <= retval; i++, sp++)
-       sv_setsv(*av_fetch(returnav, i, TRUE), SvREFCNT_inc(*sp));
-    
+    if (SvCUR(thr->errsv)) {
+       MUTEX_LOCK(&thr->mutex);
+       thr->flags |= THRf_DID_DIE;
+       MUTEX_UNLOCK(&thr->mutex);
+       av_store(av, 0, &sv_no);
+       av_store(av, 1, newSVsv(thr->errsv));
+       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p died: %s\n",
+                             SvPV(thr->errsv, na)));
+    } else {
+       DEBUG_L(STMT_START {
+           for (i = 1; i <= retval; i++) {
+               PerlIO_printf(PerlIO_stderr(), "%p return[%d] = %s\n",
+                               thr, i, SvPEEK(sp[i - 1]));
+           }
+       } STMT_END);
+       av_store(av, 0, &sv_yes);
+       for (i = 1; i <= retval; i++, sp++)
+           sv_setsv(*av_fetch(av, i, TRUE), SvREFCNT_inc(*sp));
+    }
+
   finishoff:
 #if 0    
     /* removed for debug */
     SvREFCNT_dec(curstack);
 #endif
     SvREFCNT_dec(thr->cvcache);
-    SvREFCNT_dec(thr->magicals);
+    SvREFCNT_dec(thr->threadsv);
     SvREFCNT_dec(thr->specific);
+    SvREFCNT_dec(thr->errsv);
+    SvREFCNT_dec(thr->errhv);
     Safefree(markstack);
     Safefree(scopestack);
     Safefree(savestack);
@@ -190,7 +179,7 @@ threadstart(void *arg)
     case THRf_R_DETACHED:
        ThrSETSTATE(thr, THRf_DEAD);
        MUTEX_UNLOCK(&thr->mutex);
-       SvREFCNT_dec(returnav);
+       SvREFCNT_dec(av);
        DEBUG_L(PerlIO_printf(PerlIO_stderr(),
                              "%p: DETACHED thread finished\n", thr));
        remove_thread(thr);     /* This might trigger main thread to finish */
@@ -200,7 +189,7 @@ threadstart(void *arg)
        croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr));
        /* NOTREACHED */
     }
-    return THREAD_RET_CAST(returnav);  /* Available for anyone to join with */
+    return THREAD_RET_CAST(av);        /* Available for anyone to join with */
                                        /* us unless we're detached, in which */
                                        /* case noone sees the value anyway. */
 #endif    
@@ -210,7 +199,7 @@ threadstart(void *arg)
 }
 
 static SV *
-newthread (SV *startsv, AV *initargs, char *Class)
+newthread (SV *startsv, AV *initargs, char *classname)
 {
 #ifdef USE_THREADS
     dSP;
@@ -225,26 +214,9 @@ newthread (SV *startsv, AV *initargs, char *Class)
     savethread = thr;
     thr = new_struct_thread(thr);
     SPAGAIN;
-    defstash = savethread->Tdefstash;  /* XXX maybe these should */
-    curstash = savethread->Tcurstash;  /* always be set to main? */
-    /* top_env? */
-    /* runlevel */
-    cvcache = newHV();
-    thr->flags = THRf_R_JOINABLE;
-    MUTEX_INIT(&thr->mutex);
-    thr->tid = ++threadnum;
-    /* Insert new thread into the circular linked list and bump nthreads */
-    MUTEX_LOCK(&threads_mutex);
-    thr->next = savethread->next;
-    thr->prev = savethread;
-    savethread->next = thr;
-    thr->next->prev = thr;
-    nthreads++;
-    MUTEX_UNLOCK(&threads_mutex);
-
     DEBUG_L(PerlIO_printf(PerlIO_stderr(),
-                         "%p: newthread, tid is %u, preparing stack\n",
-                         savethread, thr->tid));
+                         "%p: newthread (%p), tid is %u, preparing stack\n",
+                         savethread, thr, thr->tid));
     /* The following pushes the arg list and startsv onto the *new* stack */
     PUSHMARK(sp);
     /* Could easily speed up the following greatly */
@@ -252,7 +224,6 @@ newthread (SV *startsv, AV *initargs, char *Class)
        XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE)));
     XPUSHs(SvREFCNT_inc(startsv));
     PUTBACK;
-
 #ifdef THREAD_CREATE
     err = THREAD_CREATE(thr, threadstart);
 #else    
@@ -262,12 +233,33 @@ newthread (SV *startsv, AV *initargs, char *Class)
     sigfillset(&fullmask);
     if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1)
        croak("panic: sigprocmask");
+#ifdef PTHREADS_CREATED_JOINABLE
     err = pthread_create(&thr->self, pthread_attr_default,
                         threadstart, (void*) thr);
+#else
+    {
+       pthread_attr_t attr;
+
+       err = pthread_attr_init(&attr);
+       if (err == 0) {
+#ifdef PTHREAD_CREATE_UNDETACHED
+         err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
+#else
+         croak("panic: pthread_attr_setdetachstate");
+#endif
+         if (err == 0) 
+           err = pthread_create(&thr->self, &attr,
+                                threadstart, (void*) thr);
+       }
+       pthread_attr_destroy(&attr);
+    }
+#endif
     /* Go */
     MUTEX_UNLOCK(&thr->mutex);
 #endif
     if (err) {
+        DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+                         "%p: create of %p failed %d\n", savethread, thr, err));
        /* Thread creation failed--clean up */
        SvREFCNT_dec(thr->cvcache);
        remove_thread(thr);
@@ -286,7 +278,7 @@ newthread (SV *startsv, AV *initargs, char *Class)
     sv = newSViv(thr->tid);
     sv_magic(sv, thr->oursv, '~', 0, 0);
     SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
-    return sv_bless(newRV_noinc(sv), gv_stashpv(Class, TRUE));
+    return sv_bless(newRV_noinc(sv), gv_stashpv(classname, TRUE));
 #else
     croak("No threads in this perl");
     return &sv_undef;
@@ -303,14 +295,15 @@ handle_thread_signal(int sig)
 }
 
 MODULE = Thread                PACKAGE = Thread
+PROTOTYPES: DISABLE
 
 void
-new(Class, startsv, ...)
-       char *          Class
+new(classname, startsv, ...)
+       char *          classname
        SV *            startsv
        AV *            av = av_make(items - 2, &ST(2));
     PPCODE:
-       XPUSHs(sv_2mortal(newthread(startsv, av, Class)));
+       XPUSHs(sv_2mortal(newthread(startsv, av, classname)));
 
 void
 join(t)
@@ -340,9 +333,17 @@ join(t)
        }
        JOIN(t, &av);
 
-       /* Could easily speed up the following if necessary */
-       for (i = 0; i <= AvFILL(av); i++)
-           XPUSHs(sv_2mortal(*av_fetch(av, i, FALSE)));
+       if (SvTRUE(*av_fetch(av, 0, FALSE))) {
+           /* Could easily speed up the following if necessary */
+           for (i = 1; i <= AvFILL(av); i++)
+               XPUSHs(sv_2mortal(*av_fetch(av, i, FALSE)));
+       } else {
+           char *mess = SvPV(*av_fetch(av, 1, FALSE), na);
+           DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+                                 "%p: join propagating die message: %s\n",
+                                 thr, mess));
+           croak(mess);
+       }
 #endif
 
 void
@@ -390,8 +391,8 @@ flags(t)
 #endif
 
 void
-self(Class)
-       char *  Class
+self(classname)
+       char *  classname
     PREINIT:
        SV *sv;
     PPCODE:        
@@ -399,7 +400,8 @@ self(Class)
        sv = newSViv(thr->tid);
        sv_magic(sv, thr->oursv, '~', 0, 0);
        SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
-       PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv), gv_stashpv(Class, TRUE))));
+       PUSHs(sv_2mortal(sv_bless(newRV_noinc(sv),
+                                 gv_stashpv(classname, TRUE))));
 #endif
 
 U32
@@ -497,8 +499,8 @@ CODE:
 #endif
 
 void
-list(Class)
-       char *  Class
+list(classname)
+       char *  classname
     PREINIT:
        Thread  t;
        AV *    av;
@@ -521,7 +523,7 @@ list(Class)
                    SV *sv = newSViv(0);        /* fill in tid later */
                    sv_magic(sv, 0, '~', 0, 0); /* fill in other magic later */
                    av_push(av, sv_bless(newRV_noinc(sv),
-                                        gv_stashpv(Class, TRUE)));
+                                        gv_stashpv(classname, TRUE)));
        
                }
            }
@@ -591,3 +593,16 @@ await_signal()
     OUTPUT:
        RETVAL
 
+MODULE = Thread                PACKAGE = Thread::Specific
+
+void
+data(classname = "Thread::Specific")
+       char *  classname
+    PPCODE:
+#ifdef USE_THREADS
+       if (AvFILL(thr->specific) == -1) {
+           GV *gv = gv_fetchpv("Thread::Specific::FIELDS", TRUE, SVt_PVHV);
+           av_store(thr->specific, 0, newRV((SV*)GvHV(gv)));
+       }
+       XPUSHs(sv_bless(newRV((SV*)thr->specific),gv_stashpv(classname,TRUE)));
+#endif