-#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
-struct thread {
- pthread_t Tself;
+#ifndef THREAD_RET_TYPE
+# define THREAD_RET_TYPE void *
+# define THREAD_RET_CAST(p) ((void *)(p))
+#endif /* THREAD_RET */
+struct thread {
/* 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;
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;
/* XXX What about magic variables such as $/, $? and so on? */
HV * Tdefstash;
HV * Tcurstash;
- AV * Tpad;
- AV * Tpadname;
SV ** Ttmps_stack;
I32 Ttmps_ix;
int Tdelaymagic;
bool Tdirty;
U8 Tlocalizing;
+ COP * Tcurcop;
CONTEXT * Tcxstack;
I32 Tcxstack_ix;
I32 Tcxstack_max;
- AV * Tstack;
+ AV * Tcurstack;
AV * Tmainstack;
JMPENV * Ttop_env;
I32 Trunlevel;
/* XXX Sort stuff, firstgv, secongv and so on? */
- pthread_mutex_t * Tthreadstart_mutexp;
+ SV * Toursv;
HV * Tcvcache;
- U32 Tthrflags;
+ perl_thread self; /* Underlying thread object */
+ U32 flags;
+ perl_mutex mutex; /* For the fields others can change */
+ U32 tid;
+ struct thread *next, *prev; /* Circular linked list of threads */
+
+#ifdef ADD_THREAD_INTERN
+ struct thread_intern i; /* Platform-dependent internals */
+#endif
+ char trailing_nul; /* For the sake of thrsv, t->Toursv */
};
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 ThrSTATE(t) (t->Tthrflags & THR_STATE_MASK)
+#define THRf_DIE_FATAL 8
+
+/* ThrSTATE(t) and ThrSETSTATE(t) must only be called while holding t->mutex */
+#define ThrSTATE(t) ((t)->flags)
#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)
#undef stack_base
#undef stack_sp
#undef stack_max
-#undef stack
+#undef curstack
#undef mainstack
#undef markstack
#undef markstack_ptr
#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 curpad
#undef Sv
#undef Xpv
+#undef statbuf
+#undef timesbuf
#undef top_env
#undef runlevel
#undef in_eval
+#undef restartop
+#undef delaymagic
+#undef dirty
+#undef localizing
-#define self (thr->Tself)
+#define oursv (thr->Toursv)
#define stack_base (thr->Tstack_base)
#define stack_sp (thr->Tstack_sp)
#define stack_max (thr->Tstack_max)
#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)
#define curpad (thr->Tcurpad)
#define Sv (thr->TSv)
#define Xpv (thr->TXpv)
+#define statbuf (thr->Tstatbuf)
+#define timesbuf (thr->Ttimesbuf)
#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)
#define top_env (thr->Ttop_env)
#define runlevel (thr->Trunlevel)
-#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 */