phase 1 of somewhat major rearrangement of PERL_OBJECT stuff
[p5sagit/p5-mst-13.2.git] / ext / Thread / Thread.xs
index c4e87a3..208daf2 100644 (file)
@@ -2,55 +2,53 @@
 #include "perl.h"
 #include "XSUB.h"
 
-#ifdef WIN32
-#define ssize_t int
-#include <fcntl.h>
-#define THR_RET_TYPE   DWORD
-#define THR_FUNC_TYPE  THR_RET_TYPE WINAPI
-#else
-#define THR_RET_TYPE   void *
-#define THR_FUNC_TYPE  THR_RET_TYPE
-#endif
-
 /* Magic signature for Thread's mg_private is "Th" */ 
 #define Thread_MAGIC_SIGNATURE 0x5468
 
-static U32 threadnum = 0;
+#ifdef __cplusplus
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+#endif
+#include <fcntl.h>
+                        
 static int sig_pipe[2];
-
-static void remove_thread _((Thread t));
-static THR_FUNC_TYPE threadstart _((void *));
+            
+#ifndef THREAD_RET_TYPE
+#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 perl_thread *t)
 {
-    DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(),
+#ifdef USE_THREADS
+    DEBUG_S(WITH_THR(PerlIO_printf(PerlIO_stderr(),
                                   "%p: remove_thread %p\n", thr, t)));
-    MUTEX_LOCK(&threads_mutex);
+    MUTEX_LOCK(&PL_threads_mutex);
     MUTEX_DESTROY(&t->mutex);
-    nthreads--;
+    PL_nthreads--;
     t->prev->next = t->next;
     t->next->prev = t->prev;
-    COND_BROADCAST(&nthreads_cond);
-    MUTEX_UNLOCK(&threads_mutex);
+    COND_BROADCAST(&PL_nthreads_cond);
+    MUTEX_UNLOCK(&PL_threads_mutex);
+#endif
 }
 
-
-static THR_FUNC_TYPE
-threadstart(arg)
-void *arg;
+static THREAD_RET_TYPE
+threadstart(void *arg)
 {
+#ifdef USE_THREADS
 #ifdef FAKE_THREADS
     Thread savethread = thr;
     LOGOP myop;
     dSP;
-    I32 oldscope = scopestack_ix;
+    I32 oldscope = PL_scopestack_ix;
     I32 retval;
-    AV *returnav;
+    AV *av;
     int i;
 
-    DEBUG_L(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n",
+    DEBUG_S(PerlIO_printf(PerlIO_stderr(), "new thread %p starting at %s\n",
                          thr, SvPEEK(TOPs)));
     thr = (Thread) arg;
     savemark = TOPMARK;
@@ -62,14 +60,14 @@ void *arg;
     thr->private = 0;
 
     /* Now duplicate most of perl_call_sv but with a few twists */
-    op = (OP*)&myop;
-    Zero(op, 1, LOGOP);
+    PL_op = (OP*)&myop;
+    Zero(PL_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);
-    DEBUG_L(if (!op)
+    PL_op = pp_entersub(ARGS);
+    DEBUG_S(if (!PL_op)
            PerlIO_printf(PerlIO_stderr(), "thread starts at Nullop\n"));
     /*
      * When this thread is next scheduled, we start in the right
@@ -82,116 +80,125 @@ void *arg;
 #else
     Thread thr = (Thread) arg;
     LOGOP myop;
-    dSP;
+    djSP;
     I32 oldmark = TOPMARK;
-    I32 oldscope = scopestack_ix;
+    I32 oldscope = PL_scopestack_ix;
     I32 retval;
-    AV *returnav;
+    SV *sv;
+    AV *av = newAV();
     int i, ret;
     dJMPENV;
+    DEBUG_S(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
      * 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);
 
     /*
      * 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.
      */
-#ifdef WIN32
-    if (TlsSetValue(thr_key, (void *) thr) == 0)
-#else
-    if (pthread_setspecific(thr_key, (void *) thr))
-#endif
-       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",
+    DEBUG_S(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;
+    sv = POPs;
+    PUTBACK;
+    perl_call_sv(sv, G_ARRAY|G_EVAL);
+    SPAGAIN;
+    retval = SP - (PL_stack_base + oldmark);
+    SP = PL_stack_base + oldmark + 1;
+    if (SvCUR(thr->errsv)) {
+       MUTEX_LOCK(&thr->mutex);
+       thr->flags |= THRf_DID_DIE;
+       MUTEX_UNLOCK(&thr->mutex);
+       av_store(av, 0, &PL_sv_no);
+       av_store(av, 1, newSVsv(thr->errsv));
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p died: %s\n",
+                             thr, SvPV(thr->errsv, PL_na)));
+    } else {
+       DEBUG_S(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, &PL_sv_yes);
+       for (i = 1; i <= retval; i++, SP++)
+           sv_setsv(*av_fetch(av, i, TRUE), SvREFCNT_inc(*SP));
     }
 
-    /* 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();
-    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));
-    
   finishoff:
 #if 0    
     /* removed for debug */
-    SvREFCNT_dec(curstack);
+    SvREFCNT_dec(PL_curstack);
 #endif
-    SvREFCNT_dec(cvcache);
-    Safefree(markstack);
-    Safefree(scopestack);
-    Safefree(savestack);
-    Safefree(retstack);
-    Safefree(cxstack);
-    Safefree(tmps_stack);
+    SvREFCNT_dec(thr->cvcache);
+    SvREFCNT_dec(thr->threadsv);
+    SvREFCNT_dec(thr->specific);
+    SvREFCNT_dec(thr->errsv);
+    SvREFCNT_dec(thr->errhv);
+
+    /*Safefree(cxstack);*/
+    while (PL_curstackinfo->si_next)
+       PL_curstackinfo = PL_curstackinfo->si_next;
+    while (PL_curstackinfo) {
+       PERL_SI *p = PL_curstackinfo->si_prev;
+       SvREFCNT_dec(PL_curstackinfo->si_stack);
+       Safefree(PL_curstackinfo->si_cxstack);
+       Safefree(PL_curstackinfo);
+       PL_curstackinfo = p;
+    }    
+    Safefree(PL_markstack);
+    Safefree(PL_scopestack);
+    Safefree(PL_savestack);
+    Safefree(PL_retstack);
+    Safefree(PL_tmps_stack);
+    Safefree(PL_ofs);
+
+    SvREFCNT_dec(PL_rs);
+    SvREFCNT_dec(PL_nrs);
+    SvREFCNT_dec(PL_statname);
+    Safefree(PL_screamfirst);
+    Safefree(PL_screamnext);
+    Safefree(PL_reg_start_tmp);
+    SvREFCNT_dec(PL_lastscream);
+    /*SvREFCNT_dec(PL_defoutgv);*/
 
     MUTEX_LOCK(&thr->mutex);
-    DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+    DEBUG_S(PerlIO_printf(PerlIO_stderr(),
                          "%p: threadstart finishing: state is %u\n",
                          thr, ThrSTATE(thr)));
     switch (ThrSTATE(thr)) {
     case THRf_R_JOINABLE:
        ThrSETSTATE(thr, THRf_ZOMBIE);
        MUTEX_UNLOCK(&thr->mutex);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(),
                              "%p: R_JOINABLE thread finished\n", thr));
        break;
     case THRf_R_JOINED:
        ThrSETSTATE(thr, THRf_DEAD);
        MUTEX_UNLOCK(&thr->mutex);
        remove_thread(thr);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(),
                              "%p: R_JOINED thread finished\n", thr));
        break;
     case THRf_R_DETACHED:
        ThrSETSTATE(thr, THRf_DEAD);
        MUTEX_UNLOCK(&thr->mutex);
-       SvREFCNT_dec(returnav);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+       SvREFCNT_dec(av);
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(),
                              "%p: DETACHED thread finished\n", thr));
        remove_thread(thr);     /* This might trigger main thread to finish */
        break;
@@ -200,120 +207,125 @@ void *arg;
        croak("panic: illegal state %u at end of threadstart", ThrSTATE(thr));
        /* NOTREACHED */
     }
-    return (THR_RET_TYPE) 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(av);        /* 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 *classname)
 {
-    dTHR;
+#ifdef USE_THREADS
     dSP;
     Thread savethread;
     int i;
     SV *sv;
-#ifndef WIN32
+    int err;
+#ifndef THREAD_CREATE
+    static pthread_attr_t attr;
+    static int attr_inited = 0;
     sigset_t fullmask, oldmask;
-#else
-    DWORD junk;
+    static int attr_joinable = ATTR_JOINABLE;
 #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));
+    DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+                         "%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);
+    PUSHMARK(SP);
     /* Could easily speed up the following greatly */
     for (i = 0; i <= AvFILL(initargs); i++)
        XPUSHs(SvREFCNT_inc(*av_fetch(initargs, i, FALSE)));
     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.
-     */
-#ifndef WIN32
+    /* Get set...  */
     sigfillset(&fullmask);
     if (sigprocmask(SIG_SETMASK, &fullmask, &oldmask) == -1)
        croak("panic: sigprocmask");
-    if (pthread_create(&self, NULL, threadstart, (void*) thr))
-#else
-    if ((self = CreateThread(NULL,0,threadstart,(void*)thr,0,&junk)) == 0)
-#endif
-       return NULL;    /* XXX should clean up first */
+    err = 0;
+    if (!attr_inited) {
+       attr_inited = 1;
+       err = pthread_attr_init(&attr);
+#  ifdef PTHREAD_ATTR_SETDETACHSTATE
+       if (err == 0)
+           err = PTHREAD_ATTR_SETDETACHSTATE(&attr, attr_joinable);
+
+#  else
+       croak("panic: can't pthread_attr_setdetachstate");
+#  endif
+    }
+    if (err == 0)
+       err = PTHREAD_CREATE(&thr->self, attr, threadstart, (void*) thr);
     /* Go */
     MUTEX_UNLOCK(&thr->mutex);
-#ifndef WIN32
+#endif
+    if (err) {
+        DEBUG_S(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);
+       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
-#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(classname, TRUE));
+#else
+    croak("No threads in this perl");
+    return &PL_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);
+    unsigned char c = (unsigned char) sig;
+    /*
+     * We're not really allowed to call fprintf in a signal handler
+     * so don't be surprised if this isn't robust while debugging
+     * with -DL.
+     */
+    DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+           "handle_thread_signal: got signal %d\n", sig););
+    write(sig_pipe[1], &c, 1);
 }
 
 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)
@@ -321,7 +333,8 @@ join(t)
        AV *    av = NO_INIT
        int     i = NO_INIT
     PPCODE:
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: joining %p (state %u)\n",
+#ifdef USE_THREADS
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: joining %p (state %u)\n",
                              thr, t, ThrSTATE(t)););
        MUTEX_LOCK(&t->mutex);
        switch (ThrSTATE(t)) {
@@ -340,23 +353,27 @@ join(t)
            croak("can't join with thread");
            /* NOTREACHED */
        }
-#ifdef WIN32
-       if ((WaitForSingleObject(t->Tself,INFINITE) == WAIT_FAILED)
-           || (GetExitCodeThread(t->Tself,(LPDWORD)&av) == 0))
-#else
-       if (pthread_join(t->Tself, (void **) &av))
+       JOIN(t, &av);
+
+       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), PL_na);
+           DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+                                 "%p: join propagating die message: %s\n",
+                                 thr, mess));
+           croak(mess);
+       }
 #endif
-           croak("pthread_join failed");
-
-       /* Could easily speed up the following if necessary */
-       for (i = 0; i <= AvFILL(av); i++)
-           XPUSHs(sv_2mortal(*av_fetch(av, i, FALSE)));
 
 void
 detach(t)
        Thread  t
     CODE:
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: detaching %p (state %u)\n",
+#ifdef USE_THREADS
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: detaching %p (state %u)\n",
                              thr, t, ThrSTATE(t)););
        MUTEX_LOCK(&t->mutex);
        switch (ThrSTATE(t)) {
@@ -378,38 +395,48 @@ detach(t)
            croak("can't detach thread");
            /* NOTREACHED */
        }
+#endif
 
 void
 equal(t1, t2)
        Thread  t1
        Thread  t2
     PPCODE:
-       PUSHs((t1 == t2) ? &sv_yes : &sv_no);
+       PUSHs((t1 == t2) ? &PL_sv_yes : &PL_sv_no);
 
 void
 flags(t)
        Thread  t
     PPCODE:
+#ifdef USE_THREADS
        PUSHs(sv_2mortal(newSViv(t->flags)));
+#endif
 
 void
-self(class)
-       char *  class
+self(classname)
+       char *  classname
     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(classname, 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
 
@@ -417,55 +444,53 @@ void
 DESTROY(t)
        SV *    t
     PPCODE:
-       PUSHs(&sv_yes);
+       PUSHs(&PL_sv_yes);
 
 void
 yield()
     CODE:
-#ifdef OLD_PTHREADS_API
-       pthread_yield();
-#else
-#ifndef NO_SCHED_YIELD
-#ifdef WIN32
-       Sleep(0);       /* same semantics as POSIX sched_yield() */
-#else
-       sched_yield();
-#endif /* WIN32 */
-#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);
 
        mg = condpair_magic(sv);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_wait %p\n", thr, sv));
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: cond_wait %p\n", thr, sv));
        MUTEX_LOCK(MgMUTEXP(mg));
        if (MgOWNER(mg) != thr) {
            MUTEX_UNLOCK(MgMUTEXP(mg));
            croak("cond_wait for lock that we don't own\n");
        }
        MgOWNER(mg) = 0;
+       COND_SIGNAL(MgOWNERCONDP(mg));
        COND_WAIT(MgCONDP(mg), MgMUTEXP(mg));
        while (MgOWNER(mg))
            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);
 
        mg = condpair_magic(sv);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_signal %p\n",thr,sv));
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: cond_signal %p\n",thr,sv));
        MUTEX_LOCK(MgMUTEXP(mg));
        if (MgOWNER(mg) != thr) {
            MUTEX_UNLOCK(MgMUTEXP(mg));
@@ -473,17 +498,19 @@ 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);
 
        mg = condpair_magic(sv);
-       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "%p: cond_broadcast %p\n",
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(), "%p: cond_broadcast %p\n",
                              thr, sv));
        MUTEX_LOCK(MgMUTEXP(mg));
        if (MgOWNER(mg) != thr) {
@@ -492,38 +519,40 @@ CODE:
        }
        COND_BROADCAST(MgCONDP(mg));
        MUTEX_UNLOCK(MgMUTEXP(mg));
+#endif
 
 void
-list(class)
-       char *  class
+list(classname)
+       char *  classname
     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.
         * We mustn't do any allocation while holding threads_mutex though.
         */
-       MUTEX_LOCK(&threads_mutex);
+       MUTEX_LOCK(&PL_threads_mutex);
        do {
-           n = nthreads;
-           MUTEX_UNLOCK(&threads_mutex);
+           n = PL_nthreads;
+           MUTEX_UNLOCK(&PL_threads_mutex);
            if (AvFILL(av) < n - 1) {
                int i = AvFILL(av);
                for (i = AvFILL(av); i < n - 1; i++) {
                    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)));
        
                }
            }
-           MUTEX_LOCK(&threads_mutex);
-       } while (n < nthreads);
-       n = nthreads;   /* Get the final correct value */
+           MUTEX_LOCK(&PL_threads_mutex);
+       } while (n < PL_nthreads);
+       n = PL_nthreads;        /* Get the final correct value */
 
        /*
         * At this point, there's enough room to fill in av.
@@ -536,21 +565,22 @@ 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;
            svp++;
        } while (t != thr);
        /*  */
-       MUTEX_UNLOCK(&threads_mutex);
+       MUTEX_UNLOCK(&PL_threads_mutex);
        /* Truncate any unneeded slots in av */
        av_fill(av, n - 1);
        /* Finally, push all the new objects onto the stack and drop av */
-       EXTEND(sp, n);
+       EXTEND(SP, n);
        for (svp = AvARRAY(av); n > 0; n--, svp++)
            PUSHs(*svp);
        (void)sv_2mortal((SV*)av);
+#endif
 
 
 MODULE = Thread                PACKAGE = Thread::Signal
@@ -558,30 +588,44 @@ MODULE = Thread           PACKAGE = Thread::Signal
 void
 kill_sighandler_thread()
     PPCODE:
-       write(sig_pipe[0], "\0", 1);
-       PUSHs(&sv_yes);
+       write(sig_pipe[1], "\0", 1);
+       PUSHs(&PL_sv_yes);
 
 void
 init_thread_signals()
     PPCODE:
-       sighandlerp = handle_thread_signal;
+       PL_sighandlerp = handle_thread_signal;
        if (pipe(sig_pipe) == -1)
            XSRETURN_UNDEF;
-       PUSHs(&sv_yes);
+       PUSHs(&PL_sv_yes);
 
-SV *
+void
 await_signal()
     PREINIT:
-       char c;
-       ssize_t ret;
+       unsigned char c;
+       SSize_t ret;
     CODE:
        do {
-           ret = read(sig_pipe[1], &c, 1);
+           ret = read(sig_pipe[0], &c, 1);
        } while (ret == -1 && errno == EINTR);
        if (ret == -1)
            croak("panic: await_signal");
-       if (ret == 0)
-           XSRETURN_UNDEF;
-       RETVAL = c ? psig_ptr[c] : &sv_no;
-    OUTPUT:
-       RETVAL
+       ST(0) = sv_newmortal();
+       if (ret)
+           sv_setsv(ST(0), c ? PL_psig_ptr[c] : &PL_sv_no);
+       DEBUG_S(PerlIO_printf(PerlIO_stderr(),
+                             "await_signal returning %s\n", SvPEEK(ST(0))););
+
+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