This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate mainline changes into win32 branch. Now would be a good time
[perl5.git] / thread.h
index 466dea5..2b8e636 100644 (file)
--- a/thread.h
+++ b/thread.h
-#ifndef USE_THREADS
-#define MUTEX_LOCK(m)
-#define MUTEX_UNLOCK(m)
-#define MUTEX_INIT(m)
-#define MUTEX_DESTROY(m)
-#define COND_INIT(c)
-#define COND_SIGNAL(c)
-#define COND_BROADCAST(c)
-#define COND_WAIT(c, m)
-#define COND_DESTROY(c)
+#ifdef USE_THREADS
 
-#define THR
-/* Rats: if dTHR is just blank then the subsequent ";" throws an error */
-#define dTHR extern int errno
+#ifdef WIN32
+#  include <win32thread.h>
 #else
-#include <pthread.h>
 
+/* POSIXish threads */
+typedef pthread_t perl_thread;
 #ifdef OLD_PTHREADS_API
-#define pthread_mutexattr_init(a) pthread_mutexattr_create(a)
-#define pthread_mutexattr_settype(a,t) pthread_mutexattr_setkind_np(a,t)
-#define pthread_key_create(k,d) pthread_keycreate(k,(pthread_destructor_t)(d))
+#  define pthread_mutexattr_init(a) pthread_mutexattr_create(a)
+#  define pthread_mutexattr_settype(a,t) pthread_mutexattr_setkind_np(a,t)
+#  define pthread_key_create(k,d) pthread_keycreate(k,(pthread_destructor_t)(d))
+#  define YIELD pthread_yield()
+#  define DETACH(t)                            \
+    STMT_START {                               \
+       if (pthread_detach(&(t)->self)) {       \
+           MUTEX_UNLOCK(&(t)->mutex);          \
+           croak("panic: DETACH");             \
+       }                                       \
+    } STMT_END
 #else
-#define pthread_mutexattr_default NULL
+#  define pthread_mutexattr_default NULL
+#  define pthread_condattr_default NULL
+#  define pthread_attr_default NULL
 #endif /* OLD_PTHREADS_API */
+#endif
 
-#define MUTEX_INIT(m) \
-    if (pthread_mutex_init((m), pthread_mutexattr_default)) \
-       croak("panic: MUTEX_INIT"); \
-    else 1
-#define MUTEX_LOCK(m) \
-    if (pthread_mutex_lock((m))) croak("panic: MUTEX_LOCK"); else 1
-#define MUTEX_UNLOCK(m) \
-    if (pthread_mutex_unlock((m))) croak("panic: MUTEX_UNLOCK"); else 1
-#define MUTEX_DESTROY(m) \
-    if (pthread_mutex_destroy((m))) croak("panic: MUTEX_DESTROY"); else 1
-#define COND_INIT(c) \
-    if (pthread_cond_init((c), NULL)) croak("panic: COND_INIT"); else 1
-#define COND_SIGNAL(c) \
-    if (pthread_cond_signal((c))) croak("panic: COND_SIGNAL"); else 1
-#define COND_BROADCAST(c) \
-    if (pthread_cond_broadcast((c))) croak("panic: COND_BROADCAST"); else 1
-#define COND_WAIT(c, m) \
-    if (pthread_cond_wait((c), (m))) croak("panic: COND_WAIT"); else 1
-#define COND_DESTROY(c) \
-    if (pthread_cond_destroy((c))) croak("panic: COND_DESTROY"); else 1
-/* XXX Add "old" (?) POSIX draft interface too */
-#ifdef OLD_PTHREADS_API
+#ifndef YIELD
+#  define YIELD sched_yield()
+#endif
+
+#ifndef MUTEX_INIT
+#define MUTEX_INIT(m)                                          \
+    STMT_START {                                               \
+       if (pthread_mutex_init((m), pthread_mutexattr_default)) \
+           croak("panic: MUTEX_INIT");                         \
+    } STMT_END
+#define MUTEX_LOCK(m)                          \
+    STMT_START {                               \
+       if (pthread_mutex_lock((m)))            \
+           croak("panic: MUTEX_LOCK");         \
+    } STMT_END
+#define MUTEX_UNLOCK(m)                                \
+    STMT_START {                               \
+       if (pthread_mutex_unlock((m)))          \
+           croak("panic: MUTEX_UNLOCK");       \
+    } STMT_END
+#define MUTEX_DESTROY(m)                       \
+    STMT_START {                               \
+       if (pthread_mutex_destroy((m)))         \
+           croak("panic: MUTEX_DESTROY");      \
+    } STMT_END
+#endif /* MUTEX_INIT */
+
+#ifndef COND_INIT
+#define COND_INIT(c)                                           \
+    STMT_START {                                               \
+       if (pthread_cond_init((c), pthread_condattr_default))   \
+           croak("panic: COND_INIT");                          \
+    } STMT_END
+#define COND_SIGNAL(c)                         \
+    STMT_START {                               \
+       if (pthread_cond_signal((c)))           \
+           croak("panic: COND_SIGNAL");        \
+    } STMT_END
+#define COND_BROADCAST(c)                      \
+    STMT_START {                               \
+       if (pthread_cond_broadcast((c)))        \
+           croak("panic: COND_BROADCAST");     \
+    } STMT_END
+#define COND_WAIT(c, m)                                \
+    STMT_START {                               \
+       if (pthread_cond_wait((c), (m)))        \
+           croak("panic: COND_WAIT");          \
+    } STMT_END
+#define COND_DESTROY(c)                                \
+    STMT_START {                               \
+       if (pthread_cond_destroy((c)))          \
+           croak("panic: COND_DESTROY");       \
+    } STMT_END
+#endif /* COND_INIT */
+
+/* DETACH(t) must only be called while holding t->mutex */
+#ifndef DETACH
+#define DETACH(t)                              \
+    STMT_START {                               \
+       if (pthread_detach((t)->self)) {        \
+           MUTEX_UNLOCK(&(t)->mutex);          \
+           croak("panic: DETACH");             \
+       }                                       \
+    } STMT_END
+#endif /* DETACH */
+
+#ifndef JOIN
+#define JOIN(t, avp)                                   \
+    STMT_START {                                       \
+       if (pthread_join((t)->self, (void**)(avp)))     \
+           croak("panic: pthread_join");               \
+    } STMT_END
+#endif /* JOIN */
+
+#ifndef SET_THR
+#define SET_THR(t)                                     \
+    STMT_START {                                       \
+       if (pthread_setspecific(thr_key, (void *) (t))) \
+           croak("panic: pthread_setspecific");        \
+    } STMT_END
+#endif /* SET_THR */
+
+#ifndef THR
+#  ifdef OLD_PTHREADS_API
 struct thread *getTHR _((void));
-#define THR getTHR()
-#else
-#define THR ((struct thread *) pthread_getspecific(thr_key))
-#endif /* OLD_PTHREADS_API */
-#define dTHR struct thread *thr = THR
+#    define THR getTHR()
+#  else
+#    define THR ((struct thread *) pthread_getspecific(thr_key))
+#  endif /* OLD_PTHREADS_API */
+#endif /* THR */
+
+#ifndef dTHR
+#  define dTHR struct thread *thr = THR
+#endif /* dTHR */
+
+#ifndef INIT_THREADS
+#  ifdef NEED_PTHREAD_INIT
+#    define INIT_THREADS pthread_init()
+#  else
+#    define INIT_THREADS NOOP
+#  endif
+#endif
+
+
+#ifndef THREAD_RET_TYPE
+#  define THREAD_RET_TYPE      void *
+#  define THREAD_RET_CAST(p)   ((void *)(p))
+#endif /* THREAD_RET */
 
 struct thread {
-    pthread_t  Tself;
-
     /* The fields that used to be global */
-    SV **      Tstack_base;
+    /* Important ones in the first cache line (if alignment is done right) */
     SV **      Tstack_sp;
-    SV **      Tstack_max;
-
+#ifdef OP_IN_REGISTER
+    OP *       Topsave;
+#else
     OP *       Top;
+#endif
+    SV **      Tcurpad;
+    SV **      Tstack_base;
+
+    SV **      Tstack_max;
 
     I32 *      Tscopestack;
     I32                Tscopestack_ix;
@@ -78,12 +164,8 @@ struct thread {
     I32 *      Tmarkstack_ptr;
     I32 *      Tmarkstack_max;
 
-    SV **      Tcurpad;
-
     SV *       TSv;
     XPV *      TXpv;
-    char       Tbuf[2048];     /* should be a global locked by a mutex */
-    char       Ttokenbuf[256]; /* should be a global locked by a mutex */
     struct stat        Tstatbuf;
     struct tms Ttimesbuf;
     
@@ -91,12 +173,25 @@ struct thread {
 
     /* Now the fields that used to be "per interpreter" (even when global) */
 
-    /* XXX What about magic variables such as $/, $? and so on? */
+    /* Fields used by magic variables such as $@, $/ and so on */
+    bool       Ttainted;
+    PMOP *     Tcurpm;
+    SV *       Tnrs;
+    SV *       Trs;
+    GV *       Tlast_in_gv;
+    char *     Tofs;
+    STRLEN     Tofslen;
+    GV *       Tdefoutgv;
+    char *     Tchopset;
+    SV *       Tformtarget;
+    SV *       Tbodytarget;
+    SV *       Ttoptarget;
+
+    /* Stashes */
     HV *       Tdefstash;
     HV *       Tcurstash;
-    AV *       Tpad;
-    AV *       Tpadname;
 
+    /* Stacks */
     SV **      Ttmps_stack;
     I32                Ttmps_ix;
     I32                Ttmps_floor;
@@ -107,45 +202,62 @@ struct thread {
     int                Tdelaymagic;
     bool       Tdirty;
     U8         Tlocalizing;
+    COP *      Tcurcop;
 
-    CONTEXT *  Tcxstack;
+    PERL_CONTEXT *     Tcxstack;
     I32                Tcxstack_ix;
     I32                Tcxstack_max;
 
-    AV *       Tstack;
+    AV *       Tcurstack;
     AV *       Tmainstack;
-    Sigjmp_buf Ttop_env;
-    I32                Trunlevel;
+    JMPENV *   Ttop_env;
 
     /* XXX Sort stuff, firstgv, secongv and so on? */
 
-    pthread_mutex_t *  Tthreadstart_mutexp;
-    HV *       Tcvcache;
-    U32                Tthrflags;
+    SV *       oursv;
+    HV *       cvcache;
+    perl_thread        self;                   /* Underlying thread object */
+    U32                flags;
+    AV *       magicals;               /* Per-thread magicals */
+    AV *       specific;               /* Thread-specific user data */
+    SV *       errsv;                  /* Backing SV for $@ */
+    HV *       errhv;                  /* HV for what was %@ in pp_ctl.c */
+    perl_mutex mutex;                  /* For the fields others can change */
+    U32                tid;
+    struct thread *next, *prev;                /* Circular linked list of threads */
+    JMPENV     Tstart_env;             /* Top of top_env longjmp() chain */ 
+#ifdef HAVE_THREAD_INTERN
+    struct thread_intern i;            /* Platform-dependent internals */
+#endif
+    char       trailing_nul;           /* For the sake of thrsv and oursv */
 };
 
 typedef struct thread *Thread;
 
-/* Values and macros for thrflags */
-#define THR_STATE_MASK 3
-#define THR_NORMAL     0
-#define THR_DETACHED   1
-#define THR_JOINED     2
-#define THR_DEAD       3
+/* Values and macros for thr->flags */
+#define THRf_STATE_MASK        7
+#define THRf_R_JOINABLE        0
+#define THRf_R_JOINED  1
+#define THRf_R_DETACHED        2
+#define THRf_ZOMBIE    3
+#define THRf_DEAD      4
+
+#define THRf_DID_DIE   8
 
-#define ThrSTATE(t)    (t->Tthrflags & THR_STATE_MASK)
+/* ThrSTATE(t) and ThrSETSTATE(t) must only be called while holding t->mutex */
+#define ThrSTATE(t) ((t)->flags & THRf_STATE_MASK)
 #define ThrSETSTATE(t, s) STMT_START {         \
-       (t)->Tthrflags &= ~THR_STATE_MASK;      \
-       (t)->Tthrflags |= (s);                  \
-       DEBUG_L(fprintf(stderr, "thread 0x%lx set to state %d\n", \
-                       (unsigned long)(t), (s))); \
+       (t)->flags &= ~THRf_STATE_MASK;         \
+       (t)->flags |= (s);                      \
+       DEBUG_L(PerlIO_printf(PerlIO_stderr(),  \
+                             "thread %p set to state %d\n", (t), (s))); \
     } STMT_END
 
 typedef struct condpair {
-    pthread_mutex_t    mutex;
-    pthread_cond_t     owner_cond;
-    pthread_cond_t     cond;
-    Thread             owner;
+    perl_mutex mutex;          /* Protects all other fields */
+    perl_cond  owner_cond;     /* For when owner changes at all */
+    perl_cond  cond;           /* For cond_signal and cond_broadcast */
+    Thread     owner;          /* Currently owning thread */
 } condpair_t;
 
 #define MgMUTEXP(mg) (&((condpair_t *)(mg->mg_ptr))->mutex)
@@ -156,7 +268,7 @@ typedef struct condpair {
 #undef stack_base
 #undef stack_sp
 #undef stack_max
-#undef stack
+#undef curstack
 #undef mainstack
 #undef markstack
 #undef markstack_ptr
@@ -170,23 +282,53 @@ typedef struct condpair {
 #undef retstack
 #undef retstack_ix
 #undef retstack_max
+#undef curcop
 #undef cxstack
 #undef cxstack_ix
 #undef cxstack_max
+#undef defstash
+#undef curstash
+#undef tmps_stack
+#undef tmps_floor
+#undef tmps_ix
+#undef tmps_max
 #undef curpad
 #undef Sv
 #undef Xpv
-#undef op
+#undef statbuf
+#undef timesbuf
+#undef tainted
+#undef curpm
+#undef nrs
+#undef rs
+#undef last_in_gv
+#undef ofs
+#undef ofslen
+#undef defoutgv
+#undef chopset
+#undef formtarget
+#undef bodytarget
+#undef  start_env
+#undef toptarget
 #undef top_env
-#undef runlevel
 #undef in_eval
+#undef restartop
+#undef delaymagic
+#undef dirty
+#undef localizing
 
-#define self           (thr->Tself)
 #define stack_base     (thr->Tstack_base)
 #define stack_sp       (thr->Tstack_sp)
 #define stack_max      (thr->Tstack_max)
+#ifdef OP_IN_REGISTER
+#define opsave         (thr->Topsave)
+#else
+#undef op
 #define op             (thr->Top)
+#endif
+#define        curcop          (thr->Tcurcop)
 #define        stack           (thr->Tstack)
+#define curstack       (thr->Tcurstack)
 #define        mainstack       (thr->Tmainstack)
 #define        markstack       (thr->Tmarkstack)
 #define        markstack_ptr   (thr->Tmarkstack_ptr)
@@ -210,10 +352,23 @@ typedef struct condpair {
 #define curpad         (thr->Tcurpad)
 #define Sv             (thr->TSv)
 #define Xpv            (thr->TXpv)
+#define statbuf                (thr->Tstatbuf)
+#define timesbuf       (thr->Ttimesbuf)
+#define        tainted         (thr->Ttainted)
+#define        tainted         (thr->Ttainted)
+#define        curpm           (thr->Tcurpm)
+#define        nrs             (thr->Tnrs)
+#define        rs              (thr->Trs)
+#define        last_in_gv      (thr->Tlast_in_gv)
+#define        ofs             (thr->Tofs)
+#define        ofslen          (thr->Tofslen)
+#define        defoutgv        (thr->Tdefoutgv)
+#define        chopset         (thr->Tchopset)
+#define        formtarget      (thr->Tformtarget)
+#define        bodytarget      (thr->Tbodytarget)
+#define        toptarget       (thr->Ttoptarget)
 #define defstash       (thr->Tdefstash)
 #define curstash       (thr->Tcurstash)
-#define pad            (thr->Tpad)
-#define padname                (thr->Tpadname)
 
 #define tmps_stack     (thr->Ttmps_stack)
 #define tmps_ix                (thr->Ttmps_ix)
@@ -227,9 +382,21 @@ typedef struct condpair {
 #define localizing     (thr->Tlocalizing)
 
 #define        top_env         (thr->Ttop_env)
-#define        runlevel        (thr->Trunlevel)
+#define start_env       (thr->Tstart_env)
 
-#define        threadstart_mutexp      (thr->Tthreadstart_mutexp)
-#define        cvcache         (thr->Tcvcache)
-#define        thrflags        (thr->Tthrflags)
+#else
+/* USE_THREADS is not defined */
+#define MUTEX_LOCK(m)
+#define MUTEX_UNLOCK(m)
+#define MUTEX_INIT(m)
+#define MUTEX_DESTROY(m)
+#define COND_INIT(c)
+#define COND_SIGNAL(c)
+#define COND_BROADCAST(c)
+#define COND_WAIT(c, m)
+#define COND_DESTROY(c)
+
+#define THR
+/* Rats: if dTHR is just blank then the subsequent ";" throws an error */
+#define dTHR extern int errno
 #endif /* USE_THREADS */