static void my_exit_jump _((void)) __attribute__((noreturn));
static void nuke_stacks _((void));
static void open_script _((char *, bool, SV *));
-#ifdef USE_THREADS
-static void thread_destruct _((void *));
-#endif /* USE_THREADS */
static void usage _((char *));
static void validate_suid _((char *, char*));
Zero(sv_interp, 1, PerlInterpreter);
#endif
- /* Init the real globals? */
+ /* Init the real globals (and main thread)? */
if (!linestr) {
#ifdef USE_THREADS
-#ifdef NEED_PTHREAD_INIT
- pthread_init();
-#endif /* NEED_PTHREAD_INIT */
+ INIT_THREADS;
New(53, thr, 1, struct thread);
MUTEX_INIT(&malloc_mutex);
MUTEX_INIT(&sv_mutex);
MUTEX_INIT(&eval_mutex);
COND_INIT(&eval_cond);
- MUTEX_INIT(&nthreads_mutex);
+ MUTEX_INIT(&threads_mutex);
COND_INIT(&nthreads_cond);
nthreads = 1;
cvcache = newHV();
- thrflags = 0;
curcop = &compiling;
+ thr->flags = THRf_NORMAL;
+ thr->next = thr;
+ thr->prev = thr;
#ifdef FAKE_THREADS
self = thr;
- thr->next = thr->prev = thr->next_run = thr->prev_run = thr;
+ thr->next_run = thr->prev_run = thr;
thr->wait_queue = 0;
thr->private = 0;
+ thr->tid = 0;
#else
self = pthread_self();
- if (pthread_key_create(&thr_key, thread_destruct))
+ if (pthread_key_create(&thr_key, 0))
croak("panic: pthread_key_create");
if (pthread_setspecific(thr_key, (void *) thr))
croak("panic: pthread_setspecific");
ENTER;
}
-#ifdef USE_THREADS
-void
-thread_destruct(arg)
-void *arg;
-{
- struct thread *thr = (struct thread *) arg;
- /*
- * Decrement the global thread count and signal anyone listening.
- * The only official thread listening is the original thread while
- * in perl_destruct. It waits until it's the only thread and then
- * performs END blocks and other process clean-ups.
- */
- DEBUG_L(PerlIO_printf(PerlIO_stderr(), "thread_destruct: 0x%lx\n", (unsigned long) thr));
-
- Safefree(thr);
- MUTEX_LOCK(&nthreads_mutex);
- nthreads--;
- COND_BROADCAST(&nthreads_cond);
- MUTEX_UNLOCK(&nthreads_mutex);
-}
-#endif /* USE_THREADS */
-
void
perl_destruct(sv_interp)
register PerlInterpreter *sv_interp;
int destruct_level; /* 0=none, 1=full, 2=full with checks */
I32 last_sv_count;
HV *hv;
+ Thread t;
if (!(curinterp = sv_interp))
return;
#ifdef USE_THREADS
#ifndef FAKE_THREADS
- /* Wait until all user-created threads go away */
- MUTEX_LOCK(&nthreads_mutex);
+ /* Detach any remaining joinable threads apart from ourself */
+ MUTEX_LOCK(&threads_mutex);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: detaching remaining %d threads\n",
+ nthreads - 1));
+ for (t = thr->next; t != thr; t = t->next) {
+ if (ThrSTATE(t) == THRf_NORMAL) {
+ DETACH(t);
+ ThrSETSTATE(t, THRf_DETACHED);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(), "...detached %p\n", t));
+ }
+ }
+ /* Now wait for the thread count nthreads to drop to one */
while (nthreads > 1)
{
- DEBUG_L(PerlIO_printf(PerlIO_stderr(), "perl_destruct: waiting for %d threads\n",
- nthreads - 1));
- COND_WAIT(&nthreads_cond, &nthreads_mutex);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(),
+ "perl_destruct: waiting for %d threads\n",
+ nthreads - 1));
+ COND_WAIT(&nthreads_cond, &threads_mutex);
}
/* At this point, we're the last thread */
- MUTEX_UNLOCK(&nthreads_mutex);
+ MUTEX_UNLOCK(&threads_mutex);
DEBUG_L(PerlIO_printf(PerlIO_stderr(), "perl_destruct: armageddon has arrived\n"));
- MUTEX_DESTROY(&nthreads_mutex);
+ MUTEX_DESTROY(&threads_mutex);
COND_DESTROY(&nthreads_cond);
#endif /* !defined(FAKE_THREADS) */
#endif /* USE_THREADS */
SCHEDULE(); \
} STMT_END
#define COND_DESTROY(c)
-
#else
/* POSIXish threads */
typedef pthread_t perl_thread;
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
+
+#define DETACH(t) \
+ if (pthread_detach((t)->Tself)) croak("panic: DETACH"); else 1
+
/* XXX Add "old" (?) POSIX draft interface too */
#ifdef OLD_PTHREADS_API
struct thread *getTHR _((void));
#define dTHR struct thread *thr = THR
#endif /* FAKE_THREADS */
-struct thread {
- perl_thread Tself;
- SV * Toursv;
+#ifndef INIT_THREADS
+# ifdef NEED_PTHREAD_INIT
+# define INIT_THREADS pthread_init()
+# else
+# define INIT_THREADS NOOP
+# endif
+#endif
+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;
struct stat Tstatbuf;
/* XXX Sort stuff, firstgv, secongv and so on? */
+ perl_thread Tself;
+ SV * Toursv;
perl_mutex *Tthreadstart_mutexp;
HV * Tcvcache;
- U32 Tthrflags;
+ U32 flags;
+ U32 tid;
+ struct thread *next, *prev; /* Circular linked list of threads */
#ifdef FAKE_THREADS
- perl_thread next, prev; /* Linked list of all threads */
perl_thread next_run, prev_run; /* Linked list of runnable threads */
perl_cond wait_queue; /* Wait queue that we are waiting on */
IV private; /* Holds data across time slices */
typedef struct thread *Thread;
-/* Values and macros for thrflags */
+/* Values and macros for thr->flags */
#define THRf_STATE_MASK 3
#define THRf_NORMAL 0
#define THRf_DETACHED 1
#define THRf_DIE_FATAL 4
-#define ThrSTATE(t) (t->Tthrflags & THRf_STATE_MASK)
+#define ThrSTATE(t) (t->flags & THRf_STATE_MASK)
#define ThrSETSTATE(t, s) STMT_START { \
- (t)->Tthrflags &= ~THRf_STATE_MASK; \
- (t)->Tthrflags |= (s); \
+ (t)->flags &= ~THRf_STATE_MASK; \
+ (t)->flags |= (s); \
DEBUG_L(fprintf(stderr, "thread 0x%lx set to state %d\n", \
(unsigned long)(t), (s))); \
} STMT_END
#define threadstart_mutexp (thr->Tthreadstart_mutexp)
#define cvcache (thr->Tcvcache)
-#define thrflags (thr->Tthrflags)
#endif /* USE_THREADS */