Reverse integrate Malcolm's chanes into local
[p5sagit/p5-mst-13.2.git] / ext / Thread / Thread.xs
index 3dc2516..3a204b2 100644 (file)
@@ -5,13 +5,26 @@
 /* Magic signature for Thread's mg_private is "Th" */ 
 #define Thread_MAGIC_SIGNATURE 0x5468
 
+#ifdef __cplusplus
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+#endif
+#include <fcntl.h>
+                        
 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;
 
 static void
-remove_thread(t)
-Thread t;
+remove_thread(struct thread *t)
 {
+#ifdef USE_THREADS
     DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(),
                                   "%p: remove_thread %p\n", thr, t)));
     MUTEX_LOCK(&threads_mutex);
@@ -21,12 +34,13 @@ Thread t;
     t->next->prev = t->prev;
     COND_BROADCAST(&nthreads_cond);
     MUTEX_UNLOCK(&threads_mutex);
+#endif
 }
 
-static void *
-threadstart(arg)
-void *arg;
+static THREAD_RET_TYPE
+threadstart(void *arg)
 {
+#ifdef USE_THREADS
 #ifdef FAKE_THREADS
     Thread savethread = thr;
     LOGOP myop;
@@ -68,7 +82,7 @@ void *arg;
 #else
     Thread thr = (Thread) arg;
     LOGOP myop;
-    dSP;
+    djSP;
     I32 oldmark = TOPMARK;
     I32 oldscope = scopestack_ix;
     I32 retval;
@@ -81,8 +95,8 @@ void *arg;
      * 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
      * do stuff before our creator fills in our "self" field. For example,
-     * if we went and created another thread which tried to pthread_join
-     * with us, then we'd be in a mess.
+     * if we went and created another thread which tried to JOIN with us,
+     * then we'd be in a mess.
      */
     MUTEX_LOCK(&thr->mutex);
     MUTEX_UNLOCK(&thr->mutex);
@@ -92,8 +106,7 @@ void *arg;
      * from our pthread_t structure to our struct thread, since we're
      * the only thread who can get at it anyway.
      */
-    if (pthread_setspecific(thr_key, (void *) thr))
-       croak("panic: pthread_setspecific");
+    SET_THR(thr);
 
     /* Only now can we use SvPEEK (which calls sv_newmortal which does dTHR) */
     DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n",
@@ -116,6 +129,8 @@ void *arg;
        goto finishoff;
     }
 
+    CATCH_SET(TRUE);
+
     /* Now duplicate most of perl_call_sv but with a few twists */
     op = (OP*)&myop;
     Zero(op, 1, LOGOP);
@@ -143,13 +158,16 @@ void *arg;
     /* removed for debug */
     SvREFCNT_dec(curstack);
 #endif
-    SvREFCNT_dec(cvcache);
+    SvREFCNT_dec(thr->cvcache);
+    SvREFCNT_dec(thr->magicals);
+    SvREFCNT_dec(thr->specific);
     Safefree(markstack);
     Safefree(scopestack);
     Safefree(savestack);
     Safefree(retstack);
     Safefree(cxstack);
     Safefree(tmps_stack);
+    Safefree(ofs);
 
     MUTEX_LOCK(&thr->mutex);
     DEBUG_L(PerlIO_printf(PerlIO_stderr(),
@@ -182,58 +200,31 @@ void *arg;
        croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr));
        /* NOTREACHED */
     }
-    return (void *) returnav;  /* Available for anyone to join with us */
-                               /* unless we are detached in which case */
-                               /* noone will see the value anyway. */
+    return THREAD_RET_CAST(returnav);  /* Available for anyone to join with */
+                                       /* us unless we're detached, in which */
+                                       /* case noone sees the value anyway. */
 #endif    
+#else
+    return THREAD_RET_CAST(NULL);
+#endif
 }
 
 static SV *
-newthread(startsv, initargs, class)
-SV *startsv;
-AV *initargs;
-char *class;
+newthread (SV *startsv, AV *initargs, char *Class)
 {
-    dTHR;
+#ifdef USE_THREADS
     dSP;
     Thread savethread;
     int i;
     SV *sv;
+    int err;
+#ifndef THREAD_CREATE
     sigset_t fullmask, oldmask;
+#endif
     
     savethread = thr;
-    sv = newSVpv("", 0);
-    SvGROW(sv, sizeof(struct thread) + 1);
-    SvCUR_set(sv, sizeof(struct thread));
-    thr = (Thread) SvPVX(sv);
-    DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: newthread(%s) = %p)\n",
-                         savethread, SvPEEK(startsv), thr));
-    oursv = sv; 
-    /* If we don't zero these foostack pointers, init_stacks won't init them */
-    markstack = 0;
-    scopestack = 0;
-    savestack = 0;
-    retstack = 0;
-    init_stacks(ARGS);
-    curcop = savethread->Tcurcop;      /* XXX As good a guess as any? */
+    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));
@@ -245,33 +236,50 @@ char *class;
     XPUSHs(SvREFCNT_inc(startsv));
     PUTBACK;
 
-#ifdef FAKE_THREADS
-    threadstart(thr);
+#ifdef THREAD_CREATE
+    err = THREAD_CREATE(thr, threadstart);
 #else    
     /* On your marks... */
     MUTEX_LOCK(&thr->mutex);
-    /* Get set...
-     * Increment the global thread count.
-     */
+    /* Get set...  */
     sigfillset(&fullmask);
     if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1)
        croak("panic: sigprocmask");
-    if (pthread_create(&self, NULL, threadstart, (void*) thr))
-       return NULL;    /* XXX should clean up first */
+    err = pthread_create(&thr->self, pthread_attr_default,
+                        threadstart, (void*) thr);
     /* Go */
     MUTEX_UNLOCK(&thr->mutex);
+#endif
+    if (err) {
+       /* Thread creation failed--clean up */
+       SvREFCNT_dec(thr->cvcache);
+       remove_thread(thr);
+       MUTEX_DESTROY(&thr->mutex);
+       for (i = 0; i <= AvFILL(initargs); i++)
+           SvREFCNT_dec(*av_fetch(initargs, i, FALSE));
+       SvREFCNT_dec(startsv);
+       return NULL;
+    }
+#ifdef THREAD_POST_CREATE
+    THREAD_POST_CREATE(thr);
+#else
     if (sigprocmask(SIG_SETMASK, &oldmask, 0))
        croak("panic: sigprocmask");
 #endif
     sv = newSViv(thr->tid);
-    sv_magic(sv, oursv, '~', 0, 0);
+    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(Class, TRUE));
+#else
+    croak("No threads in this perl");
+    return &sv_undef;
+#endif
 }
 
+static Signal_t handle_thread_signal _((int sig));
+
 static Signal_t
-handle_thread_signal(sig)
-int sig;
+handle_thread_signal(int sig)
 {
     char c = (char) sig;
     write(sig_pipe[0], &c, 1);
@@ -280,12 +288,12 @@ int sig;
 MODULE = Thread                PACKAGE = Thread
 
 void
-new(class, startsv, ...)
-       char *          class
+new(Class, startsv, ...)
+       char *          Class
        SV *            startsv
        AV *            av = av_make(items - 2, &ST(2));
     PPCODE:
-       XPUSHs(sv_2mortal(newthread(startsv, av, class)));
+       XPUSHs(sv_2mortal(newthread(startsv, av, Class)));
 
 void
 join(t)
@@ -293,6 +301,7 @@ join(t)
        AV *    av = NO_INIT
        int     i = NO_INIT
     PPCODE:
+#ifdef USE_THREADS
        DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: joining %p (state %u)\n",
                              thr, t, ThrSTATE(t)););
        MUTEX_LOCK(&t->mutex);
@@ -312,17 +321,18 @@ join(t)
            croak("can't join with thread");
            /* NOTREACHED */
        }
-       if (pthread_join(t->Tself, (void **) &av))
-           croak("pthread_join failed");
+       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)));
+#endif
 
 void
 detach(t)
        Thread  t
     CODE:
+#ifdef USE_THREADS
        DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: detaching %p (state %u)\n",
                              thr, t, ThrSTATE(t)););
        MUTEX_LOCK(&t->mutex);
@@ -345,6 +355,7 @@ detach(t)
            croak("can't detach thread");
            /* NOTREACHED */
        }
+#endif
 
 void
 equal(t1, t2)
@@ -357,26 +368,34 @@ void
 flags(t)
        Thread  t
     PPCODE:
+#ifdef USE_THREADS
        PUSHs(sv_2mortal(newSViv(t->flags)));
+#endif
 
 void
-self(class)
-       char *  class
+self(Class)
+       char *  Class
     PREINIT:
        SV *sv;
-    PPCODE:
+    PPCODE:        
+#ifdef USE_THREADS
        sv = newSViv(thr->tid);
-       sv_magic(sv, oursv, '~', 0, 0);
+       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(Class, TRUE))));
+#endif
 
 U32
 tid(t)
        Thread  t
     CODE:
+#ifdef USE_THREADS
        MUTEX_LOCK(&t->mutex);
        RETVAL = t->tid;
        MUTEX_UNLOCK(&t->mutex);
+#else 
+       RETVAL = 0;
+#endif
     OUTPUT:
        RETVAL
 
@@ -389,19 +408,18 @@ DESTROY(t)
 void
 yield()
     CODE:
-#ifdef OLD_PTHREADS_API
-       pthread_yield();
-#else
-#ifndef NO_SCHED_YIELD
-       sched_yield();
-#endif /* NO_SCHED_YIELD */
-#endif /* OLD_PTHREADS_API */
+{
+#ifdef USE_THREADS
+       YIELD;
+#endif
+}
 
 void
 cond_wait(sv)
        SV *    sv
        MAGIC * mg = NO_INIT
-CODE:
+CODE:                       
+#ifdef USE_THREADS
        if (SvROK(sv))
            sv = SvRV(sv);
 
@@ -418,12 +436,14 @@ CODE:
            COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
        MgOWNER(mg) = thr;
        MUTEX_UNLOCK(MgMUTEXP(mg));
-       
+#endif
+
 void
 cond_signal(sv)
        SV *    sv
        MAGIC * mg = NO_INIT
 CODE:
+#ifdef USE_THREADS
        if (SvROK(sv))
            sv = SvRV(sv);
 
@@ -436,12 +456,14 @@ CODE:
        }
        COND_SIGNAL(MgCONDP(mg));
        MUTEX_UNLOCK(MgMUTEXP(mg));
+#endif
 
 void
 cond_broadcast(sv)
        SV *    sv
        MAGIC * mg = NO_INIT
-CODE:
+CODE: 
+#ifdef USE_THREADS
        if (SvROK(sv))
            sv = SvRV(sv);
 
@@ -455,16 +477,18 @@ CODE:
        }
        COND_BROADCAST(MgCONDP(mg));
        MUTEX_UNLOCK(MgMUTEXP(mg));
+#endif
 
 void
-list(class)
-       char *  class
+list(Class)
+       char *  Class
     PREINIT:
        Thread  t;
        AV *    av;
        SV **   svp;
        int     n = 0;
     PPCODE:
+#ifdef USE_THREADS
        av = newAV();
        /*
         * Iterate until we have enough dynamic storage for all threads.
@@ -480,7 +504,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(Class, TRUE)));
        
                }
            }
@@ -499,7 +523,7 @@ list(class)
        do {
            SV *sv = (SV*)SvRV(*svp);
            sv_setiv(sv, t->tid);
-           SvMAGIC(sv)->mg_obj = SvREFCNT_inc(t->Toursv);
+           SvMAGIC(sv)->mg_obj = SvREFCNT_inc(t->oursv);
            SvMAGIC(sv)->mg_flags |= MGf_REFCOUNTED;
            SvMAGIC(sv)->mg_private = Thread_MAGIC_SIGNATURE;
            t = t->next;
@@ -514,6 +538,7 @@ list(class)
        for (svp = AvARRAY(av); n > 0; n--, svp++)
            PUSHs(*svp);
        (void)sv_2mortal((SV*)av);
+#endif
 
 
 MODULE = Thread                PACKAGE = Thread::Signal
@@ -536,7 +561,7 @@ SV *
 await_signal()
     PREINIT:
        char c;
-       ssize_t ret;
+       SSize_t ret;
     CODE:
        do {
            ret = read(sig_pipe[1], &c, 1);
@@ -548,3 +573,4 @@ await_signal()
        RETVAL = c ? psig_ptr[c] : &sv_no;
     OUTPUT:
        RETVAL
+