summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordeischen <deischen@FreeBSD.org>2000-11-09 05:08:26 +0000
committerdeischen <deischen@FreeBSD.org>2000-11-09 05:08:26 +0000
commit69c0393f8e4b9bd522c1e9afe2f481e040dcbac3 (patch)
treea9d526e7ccca466ce303b1c6202f807942d274db
parente1d8dafb1c246b5ecfd3bf52b6e9ff947e171314 (diff)
downloadFreeBSD-src-69c0393f8e4b9bd522c1e9afe2f481e040dcbac3.zip
FreeBSD-src-69c0393f8e4b9bd522c1e9afe2f481e040dcbac3.tar.gz
Don't needlessly poll file descriptors when there are no
file descriptors needing to be polled (Doh!). Reported by Dan Nelson <dnelson@emsphone.com>. Don't install and start the scheduling timer until the first thread is created. This prevents the overhead of having a periodic scheduling signal in a single threaded program. Reported by Dan Nelson <dnelson@emsphone.com>. Allow builtin longjmps out of application installed signal handlers without the need perform any post-handler cleanup: o Change signal handling to save the threads interrupted context on the stack. The threads current context is now always stored in the same place (in the pthread). If and when a signal handler returns, the interrupted context is copied back to the storage area in the pthread. o Before calling invoking a signal handler for a thread, back the thread out of any internal waiting queues (mutex, CV, join, etc) to which it belongs. Rework uthread_info.c a bit to make it easier to change the format of a thread dump. Use an alternal signal stack for the thread library's signal handler. This allows us to fiddle with the main threads stack without fear of it being in use. Reviewed by: jasone
-rw-r--r--lib/libc_r/uthread/pthread_private.h69
-rw-r--r--lib/libc_r/uthread/uthread_cond.c145
-rw-r--r--lib/libc_r/uthread/uthread_create.c45
-rw-r--r--lib/libc_r/uthread/uthread_detach.c7
-rw-r--r--lib/libc_r/uthread/uthread_exit.c35
-rw-r--r--lib/libc_r/uthread/uthread_info.c225
-rw-r--r--lib/libc_r/uthread/uthread_init.c54
-rw-r--r--lib/libc_r/uthread/uthread_jmp.c157
-rw-r--r--lib/libc_r/uthread/uthread_join.c104
-rw-r--r--lib/libc_r/uthread/uthread_kern.c87
-rw-r--r--lib/libc_r/uthread/uthread_mutex.c35
-rw-r--r--lib/libc_r/uthread/uthread_sig.c443
-rw-r--r--lib/libc_r/uthread/uthread_sigaction.c2
-rw-r--r--lib/libc_r/uthread/uthread_sigmask.c3
-rw-r--r--lib/libkse/thread/thr_cond.c145
-rw-r--r--lib/libkse/thread/thr_create.c45
-rw-r--r--lib/libkse/thread/thr_detach.c7
-rw-r--r--lib/libkse/thread/thr_exit.c35
-rw-r--r--lib/libkse/thread/thr_info.c225
-rw-r--r--lib/libkse/thread/thr_init.c54
-rw-r--r--lib/libkse/thread/thr_join.c104
-rw-r--r--lib/libkse/thread/thr_kern.c87
-rw-r--r--lib/libkse/thread/thr_mutex.c35
-rw-r--r--lib/libkse/thread/thr_private.h69
-rw-r--r--lib/libkse/thread/thr_sig.c443
-rw-r--r--lib/libkse/thread/thr_sigaction.c2
-rw-r--r--lib/libkse/thread/thr_sigmask.c3
-rw-r--r--lib/libpthread/thread/thr_cond.c145
-rw-r--r--lib/libpthread/thread/thr_create.c45
-rw-r--r--lib/libpthread/thread/thr_detach.c7
-rw-r--r--lib/libpthread/thread/thr_exit.c35
-rw-r--r--lib/libpthread/thread/thr_info.c225
-rw-r--r--lib/libpthread/thread/thr_init.c54
-rw-r--r--lib/libpthread/thread/thr_join.c104
-rw-r--r--lib/libpthread/thread/thr_kern.c87
-rw-r--r--lib/libpthread/thread/thr_mutex.c35
-rw-r--r--lib/libpthread/thread/thr_private.h69
-rw-r--r--lib/libpthread/thread/thr_sig.c443
-rw-r--r--lib/libpthread/thread/thr_sigaction.c2
-rw-r--r--lib/libpthread/thread/thr_sigmask.c3
40 files changed, 1815 insertions, 2104 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h
index 5076510..e8fff12 100644
--- a/lib/libc_r/uthread/pthread_private.h
+++ b/lib/libc_r/uthread/pthread_private.h
@@ -327,6 +327,7 @@ struct pthread_cond {
pthread_mutex_t c_mutex;
void *c_data;
long c_flags;
+ int c_seqno;
/*
* Lock for accesses to this structure.
@@ -351,7 +352,7 @@ struct pthread_cond_attr {
*/
#define PTHREAD_COND_STATIC_INITIALIZER \
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
- 0, _SPINLOCK_INITIALIZER }
+ 0, 0, _SPINLOCK_INITIALIZER }
/*
* Semaphore definitions.
@@ -424,6 +425,9 @@ enum pthread_susp {
*/
#define PTHREAD_STACK_INITIAL 0x100000
+/* Size of the scheduler stack: */
+#define SCHED_STACK_SIZE PAGE_SIZE
+
/*
* Define the different priority ranges. All applications have thread
* priorities constrained within 0-31. The threads library raises the
@@ -574,13 +578,20 @@ union pthread_wait_data {
*/
typedef void (*thread_continuation_t) (void *);
+struct pthread_signal_frame;
+
struct pthread_state_data {
- int psd_interrupted;
+ struct pthread_signal_frame *psd_curframe;
sigset_t psd_sigmask;
- enum pthread_state psd_state;
- int psd_flags;
struct timespec psd_wakeup_time;
union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_longjmp_val;
+ int psd_sigmask_seqno;
+ int psd_signo;
+ int psd_sig_defer_count;
/* XXX - What about thread->timeout and/or thread->error? */
};
@@ -620,9 +631,6 @@ struct pthread_signal_frame {
*/
struct pthread_state_data saved_state;
- /* Beginning (bottom) of threads stack frame for this signal. */
- unsigned long stackp;
-
/*
* Threads return context; ctxtype identifies the type of context.
* For signal frame 0, these point to the context storage area
@@ -637,18 +645,10 @@ struct pthread_signal_frame {
} ctx;
thread_context_t ctxtype;
int longjmp_val;
-
- /* Threads "jump out of signal handler" destination frame. */
- int dst_frame;
-
- /*
- * Used to return back to the signal handling frame in case
- * the application tries to change contexts from the handler.
- */
- jmp_buf *sig_jb;
-
int signo; /* signal, arg 1 to sighandler */
int sig_has_args; /* use signal args if true */
+ ucontext_t uc;
+ siginfo_t siginfo;
};
/*
@@ -685,18 +685,20 @@ struct pthread {
struct pthread_attr attr;
/*
- * Used for tracking delivery of nested signal handlers.
- * Signal frame 0 is used for normal context (when no
- * signal handlers are active for the thread). Frame
- * 1 is used as the context for the first signal, and
- * frames 2 .. NSIG-1 are used when additional signals
- * arrive interrupting already active signal handlers.
+ * Threads return context; ctxtype identifies the type of context.
+ */
+ union {
+ jmp_buf jb;
+ sigjmp_buf sigjb;
+ ucontext_t uc;
+ } ctx;
+ thread_context_t ctxtype;
+ int longjmp_val;
+
+ /*
+ * Used for tracking delivery of signal handlers.
*/
- struct pthread_signal_frame *sigframes[NSIG];
- struct pthread_signal_frame sigframe0;
struct pthread_signal_frame *curframe;
- int sigframe_count;
- int sigframe_done;
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -716,6 +718,7 @@ struct pthread {
*/
sigset_t sigmask;
sigset_t sigpend;
+ int sigmask_seqno;
int check_pending;
/* Thread state: */
@@ -1078,7 +1081,11 @@ SCLASS int _thread_dfl_count[NSIG];
* Pending signals and mask for this process:
*/
SCLASS sigset_t _process_sigpending;
-SCLASS sigset_t _process_sigmask;
+SCLASS sigset_t _process_sigmask
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { {0, 0, 0, 0} }
+#endif
+;
/*
* Scheduling queues:
@@ -1222,7 +1229,6 @@ void _waitq_clearactive(void);
#endif
void _thread_exit(char *, int, char *);
void _thread_exit_cleanup(void);
-void _thread_exit_finish(void);
void _thread_fd_unlock(int, int);
void _thread_fd_unlock_debug(int, int, char *, int);
void _thread_fd_unlock_owned(pthread_t);
@@ -1232,7 +1238,7 @@ void _thread_dump_info(void);
void _thread_init(void);
void _thread_kern_sched(ucontext_t *);
void _thread_kern_scheduler(void);
-void _thread_kern_sched_frame(int frame);
+void _thread_kern_sched_frame(struct pthread_signal_frame *psf);
void _thread_kern_sched_sig(void);
void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno);
void _thread_kern_sched_state_unlock(enum pthread_state state,
@@ -1245,7 +1251,7 @@ void _thread_sig_check_pending(pthread_t pthread);
void _thread_sig_handle_pending(void);
void _thread_sig_send(pthread_t pthread, int sig);
void _thread_sig_wrapper(void);
-int _thread_sigframe_find(pthread_t pthread, void *stackp);
+void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
void _thread_start(void);
void _thread_seterrno(pthread_t, int);
int _thread_fd_table_init(int fd);
@@ -1262,6 +1268,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
+int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);
diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c
index 50cf927..5ff0967 100644
--- a/lib/libc_r/uthread/uthread_cond.c
+++ b/lib/libc_r/uthread/uthread_cond.c
@@ -47,7 +47,7 @@ static inline void cond_queue_enq(pthread_cond_t, pthread_t);
/* Reinitialize a condition variable to defaults. */
int
-_cond_reinit(pthread_cond_t * cond)
+_cond_reinit(pthread_cond_t *cond)
{
int ret = 0;
@@ -63,13 +63,14 @@ _cond_reinit(pthread_cond_t * cond)
(*cond)->c_flags = COND_FLAGS_INITED;
(*cond)->c_type = COND_TYPE_FAST;
(*cond)->c_mutex = NULL;
+ (*cond)->c_seqno = 0;
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
}
return (ret);
}
int
-pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
+pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
{
enum pthread_cond_type type;
pthread_cond_t pcond;
@@ -118,6 +119,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
memset(&pcond->lock,0,sizeof(pcond->lock));
*cond = pcond;
}
@@ -128,7 +130,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
}
int
-pthread_cond_destroy(pthread_cond_t * cond)
+pthread_cond_destroy(pthread_cond_t *cond)
{
int rval = 0;
@@ -155,22 +157,37 @@ pthread_cond_destroy(pthread_cond_t * cond)
}
int
-pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
+pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (cond == NULL)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized,
* perform the dynamic initialization:
*/
- else if (*cond != NULL ||
- (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -205,14 +222,16 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Wait forever: */
_thread_run->wakeup_time.tv_sec = -1;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -230,19 +249,23 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
- if (_thread_run->interrupted != 0) {
- /*
- * Remember that this thread
- * was interrupted:
- */
- interrupted = 1;
+ done = (seqno != (*cond)->c_seqno);
+ if ((_thread_run->flags &
+ PTHREAD_FLAGS_IN_CONDQ) != 0) {
/*
* Lock the condition variable
* while removing the thread.
@@ -260,6 +283,12 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
/*
+ * Save the interrupted flag; locking
+ * the mutex will destroy it.
+ */
+ interrupted = _thread_run->interrupted;
+
+ /*
* Note that even though this thread may have
* been canceled, POSIX requires that the mutex
* be reaquired prior to cancellation.
@@ -279,11 +308,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -296,18 +323,33 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
const struct timespec * abstime)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized, perform dynamic
* initialization.
*/
- else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -348,11 +390,13 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -368,35 +412,39 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
_SPINUNLOCK(&(*cond)->lock);
} else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
+ done = (seqno != (*cond)->c_seqno);
+
/*
- * Check if the wait timedout or was
- * interrupted (canceled):
+ * Check if the wait timedout, was
+ * interrupted (canceled), or needs to
+ * be resumed after handling a signal.
*/
if ((_thread_run->timeout == 0) &&
- (_thread_run->interrupted == 0)) {
+ (_thread_run->interrupted == 0) &&
+ (done != 0)) {
/* Lock the mutex: */
rval = _mutex_cv_lock(mutex);
-
} else {
- /*
- * Remember if this thread was
- * interrupted:
- */
- interrupted = _thread_run->interrupted;
-
- /* Lock the condition variable structure: */
+ /* Lock the CV structure: */
_SPINLOCK(&(*cond)->lock);
/*
* The wait timed out; remove
* the thread from the condition
- * variable queue:
+ * variable queue:
*/
cond_queue_remove(*cond,
_thread_run);
@@ -405,11 +453,18 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
- /* Unock the condition variable structure: */
+ /* Unock the CV structure: */
_SPINUNLOCK(&(*cond)->lock);
/* Return a timeout error: */
- rval = ETIMEDOUT;
+ if (_thread_run->timeout != 0)
+ rval = ETIMEDOUT;
+ /*
+ * Save the interrupted flag;
+ * locking the mutex will
+ * destroy it.
+ */
+ interrupted = _thread_run->interrupted;
/*
* Lock the mutex and ignore any
@@ -435,11 +490,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -473,6 +526,9 @@ pthread_cond_signal(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
if ((pthread = cond_queue_deq(*cond)) != NULL) {
/*
* Unless the thread is currently suspended,
@@ -538,6 +594,9 @@ pthread_cond_broadcast(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
/*
* Enter a loop to bring all threads off the
* condition queue:
diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c
index 0390f1b..430869e 100644
--- a/lib/libc_r/uthread/uthread_create.c
+++ b/lib/libc_r/uthread/uthread_create.c
@@ -49,16 +49,13 @@
static u_int64_t next_uniqueid = 1;
#define OFF(f) offsetof(struct pthread, f)
-#define SIGFRAME_OFF(f) offsetof(struct pthread_signal_frame, f)
int _thread_next_offset = OFF(tle.tqe_next);
int _thread_uniqueid_offset = OFF(uniqueid);
int _thread_state_offset = OFF(state);
int _thread_name_offset = OFF(name);
-int _thread_curframe_offset = OFF(curframe);
-int _thread_sigframe_ctx_offset = SIGFRAME_OFF(ctx);
-int _thread_sigframe_ctxtype_offset = SIGFRAME_OFF(ctxtype);
+int _thread_ctxtype_offset = OFF(ctxtype);
+int _thread_ctx_offset = OFF(ctx);
#undef OFF
-#undef SIGFRAME_OFF
int _thread_PS_RUNNING_value = PS_RUNNING;
int _thread_PS_DEAD_value = PS_DEAD;
@@ -66,12 +63,12 @@ int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG;
int _thread_CTX_JB_value = CTX_JB;
int _thread_CTX_SJB_value = CTX_SJB;
int _thread_CTX_UC_value = CTX_UC;
-int _thread_sigframe_size_value = sizeof(struct pthread_signal_frame);
int
pthread_create(pthread_t * thread, const pthread_attr_t * attr,
void *(*start_routine) (void *), void *arg)
{
+ struct itimerval itimer;
int f_gc = 0;
int ret = 0;
pthread_t gc_thread;
@@ -127,7 +124,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
-
+
/*
* Even if stack allocation fails, we don't want
* to try to use this location again, so
@@ -184,40 +181,35 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Initialise the thread for signals: */
new_thread->sigmask = _thread_run->sigmask;
+ new_thread->sigmask_seqno = 0;
- /* Initialize the first signal frame: */
- new_thread->sigframes[0] = &new_thread->sigframe0;
- new_thread->curframe = &new_thread->sigframe0;
+ /* Initialize the signal frame: */
+ new_thread->curframe = NULL;
/* Initialise the jump buffer: */
- _setjmp(new_thread->curframe->ctx.jb);
+ _setjmp(new_thread->ctx.jb);
/*
* Set up new stack frame so that it looks like it
* returned from a longjmp() to the beginning of
* _thread_start().
*/
- SET_RETURN_ADDR_JB(new_thread->curframe->ctx.jb,
- _thread_start);
+ SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
/* The stack starts high and builds down: */
- SET_STACK_JB(new_thread->curframe->ctx.jb,
+ SET_STACK_JB(new_thread->ctx.jb,
(long)new_thread->stack + pattr->stacksize_attr
- sizeof(double));
/* Initialize the rest of the frame: */
- new_thread->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- new_thread->curframe->stackp =
- GET_STACK_JB(new_thread->curframe->ctx.jb);
- new_thread->sigframe_count = 0;
+ new_thread->ctxtype = CTX_JB_NOSIG;
/* Copy the thread attributes: */
memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
/*
* Check if this thread is to inherit the scheduling
- * attributes from its parent:
+ * attributes from its parent:
*/
if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
/* Copy the scheduling attributes: */
@@ -233,7 +225,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/*
* Use just the thread priority, leaving the
* other scheduling attributes as their
- * default values:
+ * default values:
*/
new_thread->base_priority =
new_thread->attr.prio;
@@ -292,8 +284,19 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Return a pointer to the thread structure: */
(*thread) = new_thread;
+ if (f_gc != 0) {
+ /* Install the scheduling timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = _clock_res_usec;
+ itimer.it_value = itimer.it_interval;
+ if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
+ NULL) != 0)
+ PANIC("Cannot set interval timer");
+ }
+
/* Schedule the new user thread: */
_thread_kern_sched(NULL);
+
/*
* Start a garbage collector thread
* if necessary.
diff --git a/lib/libc_r/uthread/uthread_detach.c b/lib/libc_r/uthread/uthread_detach.c
index 3bade9d..6dd762a 100644
--- a/lib/libc_r/uthread/uthread_detach.c
+++ b/lib/libc_r/uthread/uthread_detach.c
@@ -65,7 +65,12 @@ pthread_detach(pthread_t pthread)
pthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
/* Make the thread runnable: */
- PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
+ PTHREAD_NEW_STATE(next_thread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ next_thread->error = ESRCH;
}
/*
diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c
index 7fbeb65..aef12fe 100644
--- a/lib/libc_r/uthread/uthread_exit.c
+++ b/lib/libc_r/uthread/uthread_exit.c
@@ -141,7 +141,7 @@ _thread_exit_cleanup(void)
void
pthread_exit(void *status)
{
- int frame;
+ pthread_t pthread;
/* Check if this thread is already in the process of exiting: */
if ((_thread_run->flags & PTHREAD_EXITING) != 0) {
@@ -159,7 +159,6 @@ pthread_exit(void *status)
while (_thread_run->cleanup != NULL) {
pthread_cleanup_pop(1);
}
-
if (_thread_run->attr.cleanup_attr != NULL) {
_thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr);
}
@@ -175,25 +174,6 @@ pthread_exit(void *status)
_thread_run->poll_data.fds = NULL;
}
- if ((frame = _thread_run->sigframe_count) == 0)
- _thread_exit_finish();
- else {
- /*
- * Jump back and unwind the signal frames to gracefully
- * cleanup.
- */
- ___longjmp(*_thread_run->sigframes[frame]->sig_jb, 1);
- }
-
- /* This point should not be reached. */
- PANIC("Dead thread has resumed");
-}
-
-void
-_thread_exit_finish(void)
-{
- pthread_t pthread;
-
/*
* Lock the garbage collector mutex to ensure that the garbage
* collector is not using the dead thread list.
@@ -233,6 +213,16 @@ _thread_exit_finish(void)
* detach this thread:
*/
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ if ((_thread_run->attr.flags & PTHREAD_DETACHED) != 0)
+ pthread->error = ESRCH;
+ else {
+ pthread->ret = _thread_run->ret;
+ pthread->error = 0;
+ }
}
/* Remove this thread from the thread list: */
@@ -240,5 +230,8 @@ _thread_exit_finish(void)
/* This thread will never be re-scheduled. */
_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
}
#endif
diff --git a/lib/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c
index ca91512..956ae7c 100644
--- a/lib/libc_r/uthread/uthread_info.c
+++ b/lib/libc_r/uthread/uthread_info.c
@@ -41,6 +41,13 @@
#include <errno.h>
#include "pthread_private.h"
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+
struct s_thread_info {
enum pthread_state state;
char *name;
@@ -77,12 +84,11 @@ _thread_dump_info(void)
char s[512];
int fd;
int i;
- int j;
pthread_t pthread;
char tmpfile[128];
pq_list_t *pq_list;
- for (i = 0; i < 100000; i++) {
+ for (i = 0; i < 100000; i++) {
snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i",
getpid(), i);
/* Open the dump file for append and create it if necessary: */
@@ -112,70 +118,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the global list: */
TAILQ_FOREACH(pthread, &_thread_list, tle) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
-
- /* Check if this is the running thread: */
- if (pthread == _thread_run) {
- /* Output a record for the running thread: */
- strcpy(s, "This is the running thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Check if this is the initial thread: */
- if (pthread == _thread_initial) {
- /* Output a record for the initial thread: */
- strcpy(s, "This is the initial thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Process according to thread state: */
- switch (pthread->state) {
- /* File descriptor read lock wait: */
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- /* Write the lock details: */
- snprintf(s, sizeof(s), "fd %d[%s:%d]",
- pthread->data.fd.fd,
- pthread->data.fd.fname,
- pthread->data.fd.branch);
- _thread_sys_write(fd, s, strlen(s));
- snprintf(s, sizeof(s), "owner %pr/%pw\n",
- _thread_fd_table[pthread->data.fd.fd]->r_owner,
- _thread_fd_table[pthread->data.fd.fd]->w_owner);
- _thread_sys_write(fd, s, strlen(s));
- break;
- case PS_SIGWAIT:
- snprintf(s, sizeof(s), "sigmask (hi)");
- _thread_sys_write(fd, s, strlen(s));
- for (i = _SIG_WORDS - 1; i >= 0; i--) {
- snprintf(s, sizeof(s), "%08x\n",
- pthread->sigmask.__bits[i]);
- _thread_sys_write(fd, s, strlen(s));
- }
- snprintf(s, sizeof(s), "(lo)\n");
- _thread_sys_write(fd, s, strlen(s));
- break;
-
- /*
- * Trap other states that are not explicitly
- * coded to dump information:
- */
- default:
- /* Nothing to do here. */
- break;
- }
+ dump_thread(fd, pthread, /*long_verson*/ 1);
}
/* Output a header for ready threads: */
@@ -185,19 +128,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the ready queue: */
TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) {
TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
@@ -207,19 +138,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_waitingq, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Output a header for threads in the work queue: */
@@ -228,19 +147,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_workq, qe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Check if there are no dead threads: */
@@ -255,42 +162,38 @@ _thread_dump_info(void)
/*
* Enter a loop to report each thread in the global
- * dead thread list:
+ * dead thread list:
*/
TAILQ_FOREACH(pthread, &_dead_list, dle) {
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "Thread %p prio %3d [%s:%d]\n",
- pthread, pthread->base_priority,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
/* Output a header for file descriptors: */
- snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize);
+ snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR "
+ "TABLE (table size %d)\n\n", _thread_dtablesize);
_thread_sys_write(fd, s, strlen(s));
/* Enter a loop to report file descriptor lock usage: */
for (i = 0; i < _thread_dtablesize; i++) {
/*
* Check if memory is allocated for this file
- * descriptor:
+ * descriptor:
*/
if (_thread_fd_table[i] != NULL) {
/* Report the file descriptor lock status: */
snprintf(s, sizeof(s),
- "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n",
- i,
- _thread_fd_table[i]->r_owner,
- _thread_fd_table[i]->r_lockcount,
- _thread_fd_table[i]->r_fname,
- _thread_fd_table[i]->r_lineno,
- _thread_fd_table[i]->w_owner,
- _thread_fd_table[i]->w_lockcount,
- _thread_fd_table[i]->w_fname,
- _thread_fd_table[i]->w_lineno);
- _thread_sys_write(fd, s, strlen(s));
+ "fd[%3d] read owner %p count %d [%s:%d]\n"
+ " write owner %p count %d [%s:%d]\n",
+ i, _thread_fd_table[i]->r_owner,
+ _thread_fd_table[i]->r_lockcount,
+ _thread_fd_table[i]->r_fname,
+ _thread_fd_table[i]->r_lineno,
+ _thread_fd_table[i]->w_owner,
+ _thread_fd_table[i]->w_lockcount,
+ _thread_fd_table[i]->w_fname,
+ _thread_fd_table[i]->w_lineno);
+ _thread_sys_write(fd, s, strlen(s));
}
}
@@ -299,6 +202,78 @@ _thread_dump_info(void)
}
}
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->active_priority, thread_info[i].name, pthread->fname,
+ pthread->lineno);
+ _thread_sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == _thread_run) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thread_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ /* File descriptor read lock wait: */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ /* Write the lock details: */
+ snprintf(s, sizeof(s), "fd %d[%s:%d]",
+ pthread->data.fd.fd,
+ pthread->data.fd.fname,
+ pthread->data.fd.branch);
+ _thread_sys_write(fd, s, strlen(s));
+ snprintf(s, sizeof(s), "owner %pr/%pw\n",
+ _thread_fd_table[pthread->data.fd.fd]->r_owner,
+ _thread_fd_table[pthread->data.fd.fd]->w_owner);
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi)");
+ _thread_sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
+ pthread->sigmask.__bits[i]);
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+ }
+}
+
/* Set the thread name for debug: */
void
pthread_set_name_np(pthread_t thread, char *name)
diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c
index 3cbd453..35731c4 100644
--- a/lib/libc_r/uthread/uthread_init.c
+++ b/lib/libc_r/uthread/uthread_init.c
@@ -92,7 +92,7 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
- struct itimerval itimer;
+ struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@@ -133,7 +133,7 @@ _thread_init(void)
/*
* Create a pipe that is written to by the signal handler to prevent
- * signals being missed in calls to _select:
+ * signals being missed in calls to _select:
*/
if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
/* Cannot create pipe, so abort: */
@@ -168,12 +168,12 @@ _thread_init(void)
else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
/*
* Insufficient memory to initialise this application, so
- * abort:
+ * abort:
*/
PANIC("Cannot allocate memory for initial thread");
}
/* Allocate memory for the scheduler stack: */
- else if ((_thread_kern_sched_stack = malloc(PAGE_SIZE * 10)) == NULL)
+ else if ((_thread_kern_sched_stack = malloc(SCHED_STACK_SIZE)) == NULL)
PANIC("Failed to allocate stack for scheduler");
else {
/* Zero the global kernel thread structure: */
@@ -217,8 +217,8 @@ _thread_init(void)
/* Setup the context for the scheduler: */
_setjmp(_thread_kern_sched_jb);
- SET_STACK_JB(_thread_kern_sched_jb,
- _thread_kern_sched_stack + PAGE_SIZE*10 - sizeof(double));
+ SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack +
+ SCHED_STACK_SIZE - sizeof(double));
SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
/*
@@ -253,12 +253,9 @@ _thread_init(void)
/* Initialize last active: */
_thread_initial->last_active = (long) _sched_ticks;
- /* Initialize the initial signal frame: */
- _thread_initial->sigframes[0] = &_thread_initial->sigframe0;
- _thread_initial->curframe = &_thread_initial->sigframe0;
- _thread_initial->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- _thread_initial->curframe->stackp = (unsigned long) USRSTACK;
+ /* Initialize the initial context: */
+ _thread_initial->curframe = NULL;
+ _thread_initial->ctxtype = CTX_JB_NOSIG;
/* Initialise the rest of the fields: */
_thread_initial->poll_data.nfds = 0;
@@ -276,7 +273,7 @@ _thread_init(void)
/* Initialise the global signal action structure: */
sigfillset(&act.sa_mask);
act.sa_handler = (void (*) ()) _thread_sig_handler;
- act.sa_flags = SA_SIGINFO;
+ act.sa_flags = SA_SIGINFO | SA_ONSTACK;
/* Clear pending signals for the process: */
sigemptyset(&_process_sigpending);
@@ -284,6 +281,13 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
+ /* Create and install an alternate signal stack: */
+ alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
+ alt.ss_size = SIGSTKSZ;
+ alt.ss_flags = 0;
+ if (_thread_sys_sigaltstack(&alt, NULL) != 0)
+ PANIC("Unable to install alternate signal stack");
+
/* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
@@ -295,7 +299,7 @@ _thread_init(void)
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
- * initialisation fails:
+ * initialisation fails:
*/
PANIC("Cannot read signal handler info");
}
@@ -313,7 +317,7 @@ _thread_init(void)
_thread_sys_sigaction(SIGINFO, &act, NULL) != 0 ||
_thread_sys_sigaction(SIGCHLD, &act, NULL) != 0) {
/*
- * Abort this process if signal initialisation fails:
+ * Abort this process if signal initialisation fails:
*/
PANIC("Cannot initialise signal handler");
}
@@ -335,7 +339,7 @@ _thread_init(void)
if ((_thread_dtablesize = getdtablesize()) < 0) {
/*
* Cannot get the system defined table size, so abort
- * this process.
+ * this process.
*/
PANIC("Cannot get dtablesize");
}
@@ -346,7 +350,7 @@ _thread_init(void)
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for file descriptor table");
}
@@ -354,13 +358,13 @@ _thread_init(void)
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for pollfd table");
} else {
/*
* Enter a loop to initialise the file descriptor
- * table:
+ * table:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Initialise the file descriptor table: */
@@ -374,14 +378,6 @@ _thread_init(void)
PANIC("Cannot initialize stdio file "
"descriptor table entry");
}
-
- /* Install the scheduling timer: */
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = _clock_res_usec;
- itimer.it_value = itimer.it_interval;
- if (setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL) != 0)
- PANIC("Cannot set interval timer");
-
}
}
@@ -401,10 +397,10 @@ _thread_init(void)
}
/*
- * Special start up code for NetBSD/Alpha
+ * Special start up code for NetBSD/Alpha
*/
#if defined(__NetBSD__) && defined(__alpha__)
-int
+int
main(int argc, char *argv[], char *env);
int
diff --git a/lib/libc_r/uthread/uthread_jmp.c b/lib/libc_r/uthread/uthread_jmp.c
index f2c38c2..db19ebd 100644
--- a/lib/libc_r/uthread/uthread_jmp.c
+++ b/lib/libc_r/uthread/uthread_jmp.c
@@ -40,163 +40,72 @@
#include <pthread.h>
#include "pthread_private.h"
+/* Prototypes: */
+static inline int check_stack(pthread_t thread, void *stackp);
+
void
siglongjmp(sigjmp_buf env, int savemask)
{
- void *jmp_stackp;
- void *stack_begin, *stack_end;
- int frame, dst_frame;
-
- if ((frame = _thread_run->sigframe_count) == 0)
- __siglongjmp(env, savemask);
-
- /* Get the stack pointer from the jump buffer. */
- jmp_stackp = (void *) GET_STACK_SJB(env);
-
- /* Get the bounds of the current threads stack. */
- PTHREAD_ASSERT(_thread_run->stack != NULL,
- "Thread stack pointer is null");
- stack_begin = _thread_run->stack;
- stack_end = stack_begin + _thread_run->attr.stacksize_attr;
-
- /*
- * Make sure we aren't jumping to a different stack. Make sure
- * jmp_stackp is between stack_begin and stack end, to correctly detect
- * this condition regardless of whether the stack grows up or down.
- */
- if (((jmp_stackp < stack_begin) && (jmp_stackp < stack_end)) ||
- ((jmp_stackp > stack_begin) && (jmp_stackp > stack_end)))
+ if (check_stack(_thread_run, (void *) GET_STACK_SJB(env)))
PANIC("siglongjmp()ing between thread contexts is undefined by "
"POSIX 1003.1");
- if ((dst_frame = _thread_sigframe_find(_thread_run, jmp_stackp)) < 0)
- /*
- * The stack pointer was verified above, so this
- * shouldn't happen. Let's be anal anyways.
- */
- PANIC("Error locating signal frame");
- else if (dst_frame == frame) {
- /*
- * The stack pointer is somewhere within the current
- * frame. Jump to the users context.
- */
- __siglongjmp(env, savemask);
- }
/*
- * Copy the users context to the return context of the
- * destination frame.
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
*/
- memcpy(&_thread_run->sigframes[dst_frame]->ctx.sigjb, env, sizeof(*env));
- _thread_run->sigframes[dst_frame]->ctxtype = CTX_SJB;
- _thread_run->sigframes[dst_frame]->longjmp_val = savemask;
- _thread_run->curframe->dst_frame = dst_frame;
- ___longjmp(*_thread_run->curframe->sig_jb, 1);
+ __siglongjmp(env, savemask);
}
void
longjmp(jmp_buf env, int val)
{
- void *jmp_stackp;
- void *stack_begin, *stack_end;
- int frame, dst_frame;
-
- if ((frame = _thread_run->sigframe_count) == 0)
- __longjmp(env, val);
-
- /* Get the stack pointer from the jump buffer. */
- jmp_stackp = (void *) GET_STACK_JB(env);
-
- /* Get the bounds of the current threads stack. */
- PTHREAD_ASSERT(_thread_run->stack != NULL,
- "Thread stack pointer is null");
- stack_begin = _thread_run->stack;
- stack_end = stack_begin + _thread_run->attr.stacksize_attr;
-
- /*
- * Make sure we aren't jumping to a different stack. Make sure
- * jmp_stackp is between stack_begin and stack end, to correctly detect
- * this condition regardless of whether the stack grows up or down.
- */
- if (((jmp_stackp < stack_begin) && (jmp_stackp < stack_end)) ||
- ((jmp_stackp > stack_begin) && (jmp_stackp > stack_end)))
+ if (check_stack(_thread_run, (void *) GET_STACK_JB(env)))
PANIC("longjmp()ing between thread contexts is undefined by "
"POSIX 1003.1");
- if ((dst_frame = _thread_sigframe_find(_thread_run, jmp_stackp)) < 0)
- /*
- * The stack pointer was verified above, so this
- * shouldn't happen. Let's be anal anyways.
- */
- PANIC("Error locating signal frame");
- else if (dst_frame == frame) {
- /*
- * The stack pointer is somewhere within the current
- * frame. Jump to the users context.
- */
- __longjmp(env, val);
- }
-
/*
- * Copy the users context to the return context of the
- * destination frame.
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
*/
- memcpy(&_thread_run->sigframes[dst_frame]->ctx.jb, env, sizeof(*env));
- _thread_run->sigframes[dst_frame]->ctxtype = CTX_JB;
- _thread_run->sigframes[dst_frame]->longjmp_val = val;
- _thread_run->curframe->dst_frame = dst_frame;
- ___longjmp(*_thread_run->curframe->sig_jb, 1);
+ __longjmp(env, val);
}
void
_longjmp(jmp_buf env, int val)
{
- void *jmp_stackp;
- void *stack_begin, *stack_end;
- int frame, dst_frame;
+ if (check_stack(_thread_run, (void *) GET_STACK_JB(env)))
+ PANIC("_longjmp()ing between thread contexts is undefined by "
+ "POSIX 1003.1");
- if ((frame = _thread_run->sigframe_count) == 0)
- ___longjmp(env, val);
+ /*
+ * The stack pointer is somewhere within the threads stack.
+ * Jump to the users context.
+ */
+ ___longjmp(env, val);
+}
- /* Get the stack pointer from the jump buffer. */
- jmp_stackp = (void *) GET_STACK_JB(env);
+/* Returns 0 if stack check is OK, non-zero otherwise. */
+static inline int
+check_stack(pthread_t thread, void *stackp)
+{
+ void *stack_begin, *stack_end;
/* Get the bounds of the current threads stack. */
- PTHREAD_ASSERT(_thread_run->stack != NULL,
+ PTHREAD_ASSERT(thread->stack != NULL,
"Thread stack pointer is null");
- stack_begin = _thread_run->stack;
- stack_end = stack_begin + _thread_run->attr.stacksize_attr;
+ stack_begin = thread->stack;
+ stack_end = stack_begin + thread->attr.stacksize_attr;
/*
* Make sure we aren't jumping to a different stack. Make sure
* jmp_stackp is between stack_begin and stack end, to correctly detect
* this condition regardless of whether the stack grows up or down.
*/
- if (((jmp_stackp < stack_begin) && (jmp_stackp < stack_end)) ||
- ((jmp_stackp > stack_begin) && (jmp_stackp > stack_end)))
- PANIC("_longjmp()ing between thread contexts is undefined by "
- "POSIX 1003.1");
-
- if ((dst_frame = _thread_sigframe_find(_thread_run, jmp_stackp)) < 0)
- /*
- * The stack pointer was verified above, so this
- * shouldn't happen. Let's be anal anyways.
- */
- PANIC("Error locating signal frame");
- else if (dst_frame == frame) {
- /*
- * The stack pointer is somewhere within the current
- * frame. Jump to the users context.
- */
- ___longjmp(env, val);
- }
- /*
- * Copy the users context to the return context of the
- * destination frame.
- */
- memcpy(&_thread_run->sigframes[dst_frame]->ctx.jb, env, sizeof(*env));
- _thread_run->sigframes[dst_frame]->ctxtype = CTX_JB_NOSIG;
- _thread_run->sigframes[dst_frame]->longjmp_val = val;
- _thread_run->curframe->dst_frame = dst_frame;
- ___longjmp(*_thread_run->curframe->sig_jb, 1);
+ if (((stackp < stack_begin) && (stackp < stack_end)) ||
+ ((stackp > stack_begin) && (stackp > stack_end)))
+ return (1);
+ else
+ return (0);
}
#endif
diff --git a/lib/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c
index cda31bd..b4a7c61 100644
--- a/lib/libc_r/uthread/uthread_join.c
+++ b/lib/libc_r/uthread/uthread_join.c
@@ -74,46 +74,74 @@ pthread_join(pthread_t pthread, void **thread_return)
else if (pthread->state != PS_DEAD) {
PTHREAD_ASSERT_NOT_IN_SYNCQ(_thread_run);
- /* Clear the interrupted flag: */
- _thread_run->interrupted = 0;
-
/*
- * Protect against being context switched out while
- * adding this thread to the join queue.
+ * Enter a loop in case this thread is woken prematurely
+ * in order to invoke a signal handler:
*/
- _thread_kern_sig_defer();
-
- /* Add the running thread to the join queue: */
- TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
- _thread_run->data.thread = pthread;
-
- /* Schedule the next thread: */
- _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
-
- if (_thread_run->interrupted != 0) {
- TAILQ_REMOVE(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ for (;;) {
+ /* Clear the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Protect against being context switched out while
+ * adding this thread to the join queue.
+ */
+ _thread_kern_sig_defer();
+
+ /* Add the running thread to the join queue: */
+ TAILQ_INSERT_TAIL(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
+ _thread_run->data.thread = pthread;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+
+ if ((_thread_run->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
+ TAILQ_REMOVE(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ }
+ _thread_run->data.thread = NULL;
+
+ _thread_kern_sig_undefer();
+
+ if (_thread_run->interrupted != 0) {
+ if (_thread_run->continuation != NULL)
+ _thread_run->continuation(_thread_run);
+ /*
+ * This thread was interrupted, probably to
+ * invoke a signal handler. Make sure the
+ * target thread is still joinable.
+ */
+ if (((_find_thread(pthread) != 0) &&
+ (_find_dead_thread(pthread) != 0)) ||
+ ((pthread->attr.flags &
+ PTHREAD_DETACHED) != 0)) {
+ /* Return an error: */
+ ret = ESRCH;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
+ else if (pthread->state == PS_DEAD) {
+ /* We're done; break out of the loop. */
+ break;
+ }
+ } else {
+ /*
+ * The thread return value and error are set
+ * by the thread we're joining to when it
+ * exits or detaches:
+ */
+ ret = _thread_run->error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = _thread_run->ret;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
}
- _thread_run->data.thread = NULL;
-
- _thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation(_thread_run);
-
- /* Check if the thread is not detached: */
- if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
- /* Check if the return value is required: */
- if (thread_return)
- /* Return the thread's return value: */
- *thread_return = pthread->ret;
- }
- else
- /* Return an error: */
- ret = ESRCH;
-
/* Check if the return value is required: */
} else if (thread_return != NULL)
/* Return the thread's return value: */
@@ -129,7 +157,7 @@ void
_join_backout(pthread_t pthread)
{
_thread_kern_sig_defer();
- if (pthread->state == PS_JOIN) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
TAILQ_REMOVE(&pthread->data.thread->join_queue, pthread, sqe);
_thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
}
diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c
index 23f16bc..67844e1 100644
--- a/lib/libc_r/uthread/uthread_kern.c
+++ b/lib/libc_r/uthread/uthread_kern.c
@@ -60,7 +60,7 @@
#endif
/* Static function prototype definitions: */
-static void
+static void
thread_kern_poll(int wait_reqd);
static void
@@ -77,7 +77,7 @@ static int last_tick = 0;
* return to a previous frame.
*/
void
-_thread_kern_sched_frame(int frame)
+_thread_kern_sched_frame(struct pthread_signal_frame *psf)
{
/*
* Flag the pthread kernel as executing scheduler code
@@ -86,13 +86,8 @@ _thread_kern_sched_frame(int frame)
*/
_thread_kern_in_sched = 1;
- /* Return to the specified frame: */
- _thread_run->curframe = _thread_run->sigframes[frame];
- _thread_run->sigframe_count = frame;
-
- if (_thread_run->sigframe_count == 0)
- /* Restore the threads priority: */
- _thread_run->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+ /* Restore the signal frame: */
+ _thread_sigframe_restore(_thread_run, psf);
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
@@ -127,16 +122,16 @@ _thread_kern_sched(ucontext_t *scp)
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
- if (_setjmp(_thread_run->curframe->ctx.jb) == 0) {
+ if (_setjmp(_thread_run->ctx.jb) == 0) {
/* Flag the jump buffer was the last state saved: */
- _thread_run->curframe->ctxtype = CTX_JB_NOSIG;
- _thread_run->curframe->longjmp_val = 1;
+ _thread_run->ctxtype = CTX_JB_NOSIG;
+ _thread_run->longjmp_val = 1;
} else {
DBG_MSG("Returned from ___longjmp, thread %p\n",
_thread_run);
/*
* This point is reached when a longjmp() is called
- * to restore the state of a thread.
+ * to restore the state of a thread.
*
* This is the normal way out of the scheduler.
*/
@@ -147,7 +142,7 @@ _thread_kern_sched(ucontext_t *scp)
PTHREAD_AT_CANCEL_POINT) == 0) &&
((_thread_run->cancelflags &
PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
- /*
+ /*
* Cancellations override signals.
*
* Stick a cancellation point at the
@@ -183,7 +178,6 @@ _thread_kern_sched_sig(void)
void
_thread_kern_scheduler(void)
{
- struct pthread_signal_frame *psf;
struct timespec ts;
struct timeval tv;
pthread_t pthread, pthread_h;
@@ -205,7 +199,7 @@ _thread_kern_scheduler(void)
* ready to run. This loop completes when there are no more threads
* in the global list or when a thread has its state restored by
* either a sigreturn (if the state was saved as a sigcontext) or a
- * longjmp (if the state was saved by a setjmp).
+ * longjmp (if the state was saved by a setjmp).
*/
while (!(TAILQ_EMPTY(&_thread_list))) {
/* Get the current time of day: */
@@ -229,7 +223,7 @@ _thread_kern_scheduler(void)
if (_thread_run->state != PS_RUNNING) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
_thread_run->last_inactive = (long)current_tick;
if (_thread_run->last_inactive <
@@ -266,7 +260,7 @@ _thread_kern_scheduler(void)
/*
* States which do not depend on file descriptor I/O
- * operations or timeouts:
+ * operations or timeouts:
*/
case PS_DEADLOCK:
case PS_FDLR_WAIT:
@@ -326,10 +320,16 @@ _thread_kern_scheduler(void)
}
/*
+ * Avoid polling file descriptors if there are none
+ * waiting:
+ */
+ if (TAILQ_EMPTY(&_workq) == 0) {
+ }
+ /*
* Poll file descriptors only if a new scheduling signal
* has occurred or if we have no more runnable threads.
*/
- if (((current_tick = _sched_ticks) != last_tick) ||
+ else if (((current_tick = _sched_ticks) != last_tick) ||
((_thread_run->state != PS_RUNNING) &&
(PTHREAD_PRIOQ_FIRST() == NULL))) {
/* Unprotect the scheduling queues: */
@@ -337,7 +337,7 @@ _thread_kern_scheduler(void)
/*
* Poll file descriptors to update the state of threads
- * waiting on file I/O where data may be available:
+ * waiting on file I/O where data may be available:
*/
thread_kern_poll(0);
@@ -392,7 +392,7 @@ _thread_kern_scheduler(void)
if (add_to_prioq != 0) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
current_tick = _sched_ticks;
_thread_run->last_inactive = (long)current_tick;
@@ -445,7 +445,7 @@ _thread_kern_scheduler(void)
/*
* Lock the pthread kernel by changing the pointer to
* the running thread to point to the global kernel
- * thread structure:
+ * thread structure:
*/
_thread_run = &_thread_kern_thread;
DBG_MSG("No runnable threads, using kernel thread %p\n",
@@ -456,7 +456,7 @@ _thread_kern_scheduler(void)
/*
* There are no threads ready to run, so wait until
- * something happens that changes this condition:
+ * something happens that changes this condition:
*/
thread_kern_poll(1);
@@ -524,7 +524,7 @@ _thread_kern_scheduler(void)
/*
* Save the current time as the time that the thread
- * became active:
+ * became active:
*/
current_tick = _sched_ticks;
_thread_run->last_active = (long) current_tick;
@@ -532,7 +532,7 @@ _thread_kern_scheduler(void)
/*
* Check if this thread is running for the first time
* or running again after using its full time slice
- * allocation:
+ * allocation:
*/
if (_thread_run->slice_usec == -1) {
/* Reset the accumulated time slice period: */
@@ -551,36 +551,39 @@ _thread_kern_scheduler(void)
/*
* Continue the thread at its current frame:
*/
- psf = _thread_run->curframe;
- switch(psf->ctxtype) {
+ switch(_thread_run->ctxtype) {
case CTX_JB_NOSIG:
- ___longjmp(psf->ctx.jb, psf->longjmp_val);
+ ___longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_JB:
- __longjmp(psf->ctx.jb, psf->longjmp_val);
+ __longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_SJB:
- __siglongjmp(psf->ctx.sigjb, psf->longjmp_val);
+ __siglongjmp(_thread_run->ctx.sigjb,
+ _thread_run->longjmp_val);
break;
case CTX_UC:
/* XXX - Restore FP regsisters? */
- FP_RESTORE_UC(&psf->ctx.uc);
+ FP_RESTORE_UC(&_thread_run->ctx.uc);
/*
* Do a sigreturn to restart the thread that
- * was interrupted by a signal:
+ * was interrupted by a signal:
*/
_thread_kern_in_sched = 0;
#if NOT_YET
- _setcontext(&psf->ctx.uc);
+ _setcontext(&_thread_run->ctx.uc);
#else
/*
* Ensure the process signal mask is set
* correctly:
*/
- psf->ctx.uc.uc_sigmask = _process_sigmask;
- _thread_sys_sigreturn(&psf->ctx.uc);
+ _thread_run->ctx.uc.uc_sigmask =
+ _process_sigmask;
+ _thread_sys_sigreturn(&_thread_run->ctx.uc);
#endif
break;
}
@@ -800,14 +803,14 @@ thread_kern_poll(int wait_reqd)
/*
* Wait for a file descriptor to be ready for read, write, or
- * an exception, or a timeout to occur:
+ * an exception, or a timeout to occur:
*/
count = _thread_sys_poll(_thread_pfd_table, nfds, timeout_ms);
if (kern_pipe_added != 0)
/*
* Remove the pthread kernel pipe file descriptor
- * from the pollfd table:
+ * from the pollfd table:
*/
nfds = 1;
else
@@ -821,7 +824,7 @@ thread_kern_poll(int wait_reqd)
(_thread_pfd_table[0].revents & POLLRDNORM))) {
/*
* If the kernel read pipe was included in the
- * count:
+ * count:
*/
if (count > 0) {
/* Decrement the count of file descriptors: */
@@ -843,7 +846,7 @@ thread_kern_poll(int wait_reqd)
/*
* Enter a loop to look for threads waiting on file
* descriptors that are flagged as available by the
- * _poll syscall:
+ * _poll syscall:
*/
PTHREAD_WAITQ_SETACTIVE();
TAILQ_FOREACH(pthread, &_workq, qe) {
@@ -986,7 +989,7 @@ _thread_kern_set_timeout(const struct timespec * timeout)
if (timeout == NULL) {
/*
* Set the wakeup time to something that can be recognised as
- * different to an actual time of day:
+ * different to an actual time of day:
*/
_thread_run->wakeup_time.tv_sec = -1;
_thread_run->wakeup_time.tv_nsec = -1;
@@ -1042,7 +1045,7 @@ _thread_kern_sig_undefer(void)
if (_sigq_check_reqd != 0)
_thread_kern_sched(NULL);
- /*
+ /*
* Check for asynchronous cancellation before delivering any
* pending signals:
*/
@@ -1071,7 +1074,7 @@ dequeue_signals(void)
int num;
/*
- * Enter a loop to clear the pthread kernel pipe:
+ * Enter a loop to clear the pthread kernel pipe:
*/
while (((num = _thread_sys_read(_thread_kern_pipe[0], bufr,
sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) {
diff --git a/lib/libc_r/uthread/uthread_mutex.c b/lib/libc_r/uthread/uthread_mutex.c
index ec6c0f6..f3649db 100644
--- a/lib/libc_r/uthread/uthread_mutex.c
+++ b/lib/libc_r/uthread/uthread_mutex.c
@@ -406,13 +406,29 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_thread_init();
if (mutex == NULL)
- ret = EINVAL;
+ return (EINVAL);
/*
* If the mutex is statically initialized, perform the dynamic
* initialization:
*/
- else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
+ if ((*mutex == NULL) &&
+ ((ret = init_static(mutex)) != 0))
+ return (ret);
+
+ /* Reset the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ while (((*mutex)->m_owner != _thread_run) && (ret == 0) &&
+ (_thread_run->interrupted == 0)) {
/*
* Defer signals to protect the scheduling queues from
* access by the signal handler:
@@ -432,9 +448,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_MUTEX_INIT_LINK(*mutex);
}
- /* Reset the interrupted flag: */
- _thread_run->interrupted = 0;
-
/* Process according to mutex type: */
switch ((*mutex)->m_protocol) {
/* Default POSIX mutex: */
@@ -624,12 +637,12 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
* necessary:
*/
_thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
}
+ if (_thread_run->interrupted != 0 &&
+ _thread_run->continuation != NULL)
+ _thread_run->continuation((void *) _thread_run);
+
/* Return the completion status: */
return (ret);
}
@@ -1381,7 +1394,7 @@ _mutex_lock_backout(pthread_t pthread)
* access by the signal handler:
*/
_thread_kern_sig_defer();
- if (pthread->state == PS_MUTEX_WAIT) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
mutex = pthread->data.mutex;
/* Lock the mutex structure: */
@@ -1390,7 +1403,7 @@ _mutex_lock_backout(pthread_t pthread)
mutex_queue_remove(mutex, pthread);
/* This thread is no longer waiting for the mutex: */
- mutex->m_owner->data.mutex = NULL;
+ pthread->data.mutex = NULL;
/* Unlock the mutex structure: */
_SPINUNLOCK(&mutex->lock);
diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c
index f19582d..3bcd9c1 100644
--- a/lib/libc_r/uthread/uthread_sig.c
+++ b/lib/libc_r/uthread/uthread_sig.c
@@ -49,9 +49,7 @@ static void thread_sig_check_state(pthread_t pthread, int sig);
static pthread_t thread_sig_find(int sig);
static void thread_sig_handle_special(int sig);
static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp);
-static void thread_sigframe_add(pthread_t thread, int sig);
-static void thread_sigframe_leave(pthread_t thread, int frame);
-static void thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
+static void thread_sigframe_add(pthread_t thread, int sig, int has_args);
static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf);
/* #define DEBUG_SIGNAL */
@@ -72,21 +70,30 @@ static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *
void
_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
- pthread_t pthread;
- int current_frame;
+ pthread_t pthread, pthread_h;
+ void *stackp;
+ int in_sched = 0;
char c;
if (ucp == NULL)
PANIC("Thread signal handler received null context");
DBG_MSG("Got signal %d, current thread %p\n", sig, _thread_run);
+ if (_thread_kern_in_sched != 0)
+ in_sched = 1;
+ else {
+ stackp = (void *)GET_STACK_UC(ucp);
+ if ((stackp >= _thread_kern_sched_stack) &&
+ (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE))
+ in_sched = 1;
+ }
/* Check if an interval timer signal: */
if (sig == _SCHED_SIGNAL) {
/* Update the scheduling clock: */
gettimeofday((struct timeval *)&_sched_tod, NULL);
_sched_ticks++;
- if (_thread_kern_in_sched != 0) {
+ if (in_sched != 0) {
/*
* The scheduler is already running; ignore this
* signal.
@@ -108,13 +115,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/*
* Schedule the next thread. This function is not
* expected to return because it will do a longjmp
- * instead.
+ * instead.
*/
_thread_kern_sched(ucp);
/*
* This point should not be reached, so abort the
- * process:
+ * process:
*/
PANIC("Returned to signal function from scheduler");
}
@@ -124,8 +131,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* is accessing the scheduling queues or if there is a currently
* running thread that has deferred signals.
*/
- else if ((_thread_kern_in_sched != 0) ||
- (_thread_run->sig_defer_count > 0)) {
+ else if ((in_sched != 0) || (_thread_run->sig_defer_count > 0)) {
/* Cast the signal number to a character variable: */
c = sig;
@@ -176,10 +182,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* cannot be interrupted by other signals.
*/
else if (_thread_sigq[sig - 1].blocked == 0) {
- /* The signal is not blocked; handle the signal: */
- current_frame = _thread_run->sigframe_count;
-
/*
+ * The signal is not blocked; handle the signal.
+ *
* Ignore subsequent occurrences of this signal
* until the current signal is handled:
*/
@@ -204,6 +209,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/* Handle special signals: */
thread_sig_handle_special(sig);
+ pthread_h = NULL;
if ((pthread = thread_sig_find(sig)) != NULL) {
DBG_MSG("Got signal %d, adding frame to thread %p\n",
sig, pthread);
@@ -221,9 +227,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
thread_sig_add(pthread, sig, /*has_args*/ 1);
/* Take a peek at the next ready to run thread: */
- pthread = PTHREAD_PRIOQ_FIRST();
+ pthread_h = PTHREAD_PRIOQ_FIRST();
DBG_MSG("Finished adding frame, head of prio list %p\n",
- pthread);
+ pthread_h);
}
else
DBG_MSG("No thread to handle signal %d\n", sig);
@@ -235,11 +241,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* signal and the currently running thread is not in a
* signal handler.
*/
- if ((_thread_run->sigframe_count > current_frame) ||
- ((pthread != NULL) &&
- (pthread->active_priority > _thread_run->active_priority))) {
+ if ((pthread == _thread_run) || ((pthread_h != NULL) &&
+ (pthread_h->active_priority > _thread_run->active_priority))) {
/* Enter the kernel scheduler: */
- DBG_MSG("Entering scheduler from signal handler\n");
_thread_kern_sched(ucp);
}
}
@@ -253,17 +257,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
static void
thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp)
{
- struct pthread_signal_frame *psf;
-
- psf = _thread_run->curframe;
-
- memcpy(&psf->ctx.uc, ucp, sizeof(*ucp));
+ memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp));
/* XXX - Save FP registers too? */
- FP_SAVE_UC(&psf->ctx.uc);
+ FP_SAVE_UC(&pthread->ctx.uc);
/* Mark the context saved as a ucontext: */
- psf->ctxtype = CTX_UC;
+ pthread->ctxtype = CTX_UC;
}
/*
@@ -278,10 +278,13 @@ thread_sig_find(int sig)
DBG_MSG("Looking for thread to handle signal %d\n", sig);
/* Check if the signal requires a dump of thread information: */
- if (sig == SIGINFO)
+ if (sig == SIGINFO) {
/* Dump thread information to file: */
_thread_dump_info();
+ /* Unblock this signal to allow further dumps: */
+ _thread_sigq[sig - 1].blocked = 0;
+ }
/* Check if an interval timer signal: */
else if (sig == _SCHED_SIGNAL) {
/*
@@ -326,7 +329,7 @@ thread_sig_find(int sig)
* A signal handler is not invoked for threads
* in sigwait. Clear the blocked and pending
* flags.
- */
+ */
_thread_sigq[sig - 1].blocked = 0;
_thread_sigq[sig - 1].pending = 0;
@@ -375,7 +378,7 @@ thread_sig_find(int sig)
signaled_thread == NULL) {
/*
* Enter a loop to look for other threads
- * capable of receiving the signal:
+ * capable of receiving the signal:
*/
TAILQ_FOREACH(pthread, &_thread_list, tle) {
if (!sigismember(&pthread->sigmask,
@@ -565,8 +568,7 @@ thread_sig_handle_special(int sig)
static void
thread_sig_add(pthread_t pthread, int sig, int has_args)
{
- int restart, frame;
- int block_signals = 0;
+ int restart;
int suppress_handler = 0;
restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
@@ -657,8 +659,11 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* States which cannot be interrupted but still require the
* signal handler to run:
*/
- case PS_COND_WAIT:
case PS_JOIN:
+ /* Only set the interrupted flag for PS_JOIN: */
+ pthread->interrupted = 1;
+ /* FALLTHROUGH */
+ case PS_COND_WAIT:
case PS_MUTEX_WAIT:
/*
* Remove the thread from the wait queue. It will
@@ -687,14 +692,6 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* the actual handler.
*/
PTHREAD_WAITQ_REMOVE(pthread);
- /*
- * To ensure the thread is removed from the fd and file
- * queues before any other signal interrupts it, set the
- * signal mask to block all signals. As soon as the thread
- * is removed from the queue the signal mask will be
- * restored.
- */
- block_signals = 1;
break;
/*
@@ -736,22 +733,15 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
}
if (suppress_handler == 0) {
+ /* Setup a signal frame and save the current threads state: */
+ thread_sigframe_add(pthread, sig, has_args);
+
/*
- * Save the current state of the thread and add a
- * new signal frame.
+ * Signals are deferred until just before the threads
+ * signal handler is invoked:
*/
- frame = pthread->sigframe_count;
- thread_sigframe_save(pthread, pthread->curframe);
- thread_sigframe_add(pthread, sig);
- pthread->sigframes[frame + 1]->sig_has_args = has_args;
- SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask);
- if (block_signals != 0) {
- /* Save the signal mask and block all signals: */
- pthread->sigframes[frame + 1]->saved_state.psd_sigmask =
- pthread->sigmask;
- sigfillset(&pthread->sigmask);
- }
-
+ pthread->sig_defer_count = 1;
+
/* Make sure the thread is runnable: */
if (pthread->state != PS_RUNNING)
PTHREAD_SET_STATE(pthread, PS_RUNNING);
@@ -925,19 +915,16 @@ _thread_sig_wrapper(void)
{
void (*sigfunc)(int, siginfo_t *, void *);
struct pthread_signal_frame *psf;
- pthread_t thread;
- int dead = 0;
- int i, sig, has_args;
- int frame, dst_frame;
+ pthread_t thread;
thread = _thread_run;
/* Get the current frame and state: */
- frame = thread->sigframe_count;
- PTHREAD_ASSERT(frame > 0, "Invalid signal frame in signal handler");
psf = thread->curframe;
+ thread->curframe = NULL;
+ PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
- /* Check the threads previous state: */
+ /* Check the threads previous state: */
if (psf->saved_state.psd_state != PS_RUNNING) {
/*
* Do a little cleanup handling for those threads in
@@ -950,15 +937,26 @@ _thread_sig_wrapper(void)
case PS_FDLW_WAIT:
_fd_lock_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
break;
case PS_FILE_WAIT:
_flockfile_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
+ break;
+
+ case PS_COND_WAIT:
+ _cond_wait_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_JOIN:
+ _join_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ _mutex_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
break;
default:
@@ -966,11 +964,20 @@ _thread_sig_wrapper(void)
}
}
+ /* Unblock the signal in case we don't return from the handler: */
+ _thread_sigq[psf->signo - 1].blocked = 0;
+
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+
/*
- * Unless the thread exits or longjmps out of the signal handler,
- * return to the previous frame:
+ * Reenable interruptions without checking for the need to
+ * context switch:
*/
- dst_frame = frame - 1;
+ thread->sig_defer_count = 0;
/*
* Check that a custom handler is installed and if the signal
@@ -979,141 +986,45 @@ _thread_sig_wrapper(void)
sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction;
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN)) {
+ DBG_MSG("_thread_sig_wrapper: Calling signal handler for "
+ "thread 0x%p\n", thread);
/*
- * The signal jump buffer is allocated off the stack.
- * If the signal handler tries to [_][sig]longjmp() or
- * setcontext(), our wrapped versions of these routines
- * will copy the user supplied jump buffer or context
- * to the destination signal frame, set the destination
- * signal frame in psf->dst_frame, and _longjmp() back
- * to here.
- */
- jmp_buf jb;
-
- /*
- * Set up the context for abnormal returns out of signal
- * handlers.
+ * Dispatch the signal via the custom signal
+ * handler:
*/
- psf->sig_jb = &jb;
- if (_setjmp(jb) == 0) {
- DBG_MSG("_thread_sig_wrapper: Entering frame %d, "
- "stack 0x%lx\n", frame, GET_STACK_JB(jb));
- /*
- * Invalidate the destination frame before calling
- * the signal handler.
- */
- psf->dst_frame = -1;
-
- /*
- * Dispatch the signal via the custom signal
- * handler:
- */
- if (psf->sig_has_args == 0)
- (*(sigfunc))(psf->signo, NULL, NULL);
- else if ((_thread_sigact[psf->signo - 1].sa_flags &
- SA_SIGINFO) != 0)
- (*(sigfunc))(psf->signo,
- &_thread_sigq[psf->signo - 1].siginfo,
- &_thread_sigq[psf->signo - 1].uc);
- else
- (*(sigfunc))(psf->signo,
- (siginfo_t *)_thread_sigq[psf->signo - 1].siginfo.si_code,
- &_thread_sigq[psf->signo - 1].uc);
- }
- else {
- /*
- * The return from _setjmp() should only be non-zero
- * when the signal handler wants to xxxlongjmp() or
- * setcontext() to a different context, or if the
- * thread has exited (via pthread_exit).
- */
- /*
- * Grab a copy of the destination frame before it
- * gets clobbered after unwinding.
- */
- dst_frame = psf->dst_frame;
- DBG_MSG("Abnormal exit from handler for signal %d, "
- "frame %d\n", psf->signo, frame);
-
- /* Has the thread exited? */
- if ((dead = thread->flags & PTHREAD_EXITING) != 0)
- /* When exiting, unwind to frame 0. */
- dst_frame = 0;
- else if ((dst_frame < 0) || (dst_frame > frame))
- PANIC("Attempt to unwind to invalid "
- "signal frame");
-
- /* Unwind to the target frame: */
- for (i = frame; i > dst_frame; i--) {
- DBG_MSG("Leaving frame %d, signal %d\n", i,
- thread->sigframes[i]->signo);
- /* Leave the current signal frame: */
- thread_sigframe_leave(thread, i);
-
- /*
- * Save whatever is needed out of the state
- * data; as soon as the frame count is
- * is decremented, another signal can arrive
- * and corrupt this view of the state data.
- */
- sig = thread->sigframes[i]->signo;
- has_args = thread->sigframes[i]->sig_has_args;
-
- /*
- * We're done with this signal frame:
- */
- thread->curframe = thread->sigframes[i - 1];
- thread->sigframe_count = i - 1;
-
- /*
- * Only unblock the signal if it was a
- * process signal as opposed to a signal
- * generated by pthread_kill().
- */
- if (has_args != 0)
- _thread_sigq[sig - 1].blocked = 0;
- }
- }
+ if (psf->sig_has_args == 0)
+ (*(sigfunc))(psf->signo, NULL, NULL);
+ else if ((_thread_sigact[psf->signo - 1].sa_flags &
+ SA_SIGINFO) != 0)
+ (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc);
+ else
+ (*(sigfunc))(psf->signo,
+ (siginfo_t *)psf->siginfo.si_code, &psf->uc);
}
-
/*
- * Call the kernel scheduler to schedule the next
- * thread.
+ * Call the kernel scheduler to safely restore the frame and
+ * schedule the next thread:
*/
- if (dead == 0) {
- /* Restore the threads state: */
- thread_sigframe_restore(thread, thread->sigframes[dst_frame]);
- _thread_kern_sched_frame(dst_frame);
- }
- else {
- PTHREAD_ASSERT(dst_frame == 0,
- "Invalid signal frame for dead thread");
-
- /* Perform any necessary cleanup before exiting. */
- thread_sigframe_leave(thread, 0);
-
- /* This should never return: */
- _thread_exit_finish();
- PANIC("Return from _thread_exit_finish in signal wrapper");
- }
+ _thread_kern_sched_frame(psf);
}
static void
-thread_sigframe_add(pthread_t thread, int sig)
+thread_sigframe_add(pthread_t thread, int sig, int has_args)
{
+ struct pthread_signal_frame *psf = NULL;
unsigned long stackp = 0;
/* Get the top of the threads stack: */
- switch (thread->curframe->ctxtype) {
+ switch (thread->ctxtype) {
case CTX_JB:
case CTX_JB_NOSIG:
- stackp = GET_STACK_JB(thread->curframe->ctx.jb);
+ stackp = GET_STACK_JB(thread->ctx.jb);
break;
case CTX_SJB:
- stackp = GET_STACK_SJB(thread->curframe->ctx.sigjb);
+ stackp = GET_STACK_SJB(thread->ctx.sigjb);
break;
case CTX_UC:
- stackp = GET_STACK_UC(&thread->curframe->ctx.uc);
+ stackp = GET_STACK_UC(&thread->ctx.uc);
break;
default:
PANIC("Invalid thread context type");
@@ -1130,138 +1041,76 @@ thread_sigframe_add(pthread_t thread, int sig)
/* Allocate room on top of the stack for a new signal frame: */
stackp -= sizeof(struct pthread_signal_frame);
- /* Set up the new frame: */
- thread->sigframe_count++;
- thread->sigframes[thread->sigframe_count] =
- (struct pthread_signal_frame *) stackp;
- thread->curframe = thread->sigframes[thread->sigframe_count];
- thread->curframe->stackp = stackp;
- thread->curframe->ctxtype = CTX_JB_NOSIG;
- thread->curframe->longjmp_val = 1;
- thread->curframe->signo = sig;
+ psf = (struct pthread_signal_frame *) stackp;
- /*
- * Set up the context:
- */
- _setjmp(thread->curframe->ctx.jb);
- SET_STACK_JB(thread->curframe->ctx.jb, stackp);
- SET_RETURN_ADDR_JB(thread->curframe->ctx.jb, _thread_sig_wrapper);
-}
+ /* Save the current context in the signal frame: */
+ thread_sigframe_save(thread, psf);
-/*
- * Locate the signal frame from the specified stack pointer.
- */
-int
-_thread_sigframe_find(pthread_t pthread, void *stackp)
-{
- int frame;
+ /* Set handler specific information: */
+ psf->sig_has_args = has_args;
+ psf->signo = sig;
+ if (has_args) {
+ /* Copy the signal handler arguments to the signal frame: */
+ memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
+ sizeof(psf->uc));
+ memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
+ sizeof(psf->siginfo));
+ }
+ /* Set up the new frame: */
+ thread->curframe = psf;
+ thread->ctxtype = CTX_JB_NOSIG;
+ thread->longjmp_val = 1;
+ thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
+ PTHREAD_FLAGS_IN_SYNCQ;
/*
- * Find the destination of the target frame based on the
- * given stack pointer.
+ * Set up the context:
*/
- for (frame = pthread->sigframe_count; frame >= 0; frame--) {
- if (stackp < (void *)pthread->sigframes[frame]->stackp)
- break;
- }
- return (frame);
+ stackp += sizeof(double);
+ _setjmp(thread->ctx.jb);
+ SET_STACK_JB(thread->ctx.jb, stackp);
+ SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
}
-
+
void
-thread_sigframe_leave(pthread_t thread, int frame)
+_thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
{
- struct pthread_state_data *psd;
-
- psd = &thread->sigframes[frame]->saved_state;
-
+ thread->ctxtype = psf->ctxtype;
+ memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc));
/*
- * Perform any necessary cleanup for this signal frame:
+ * Only restore the signal mask if it hasn't been changed
+ * by the application during invocation of the signal handler:
*/
- switch (psd->psd_state) {
- case PS_DEAD:
- case PS_DEADLOCK:
- case PS_RUNNING:
- case PS_SIGTHREAD:
- case PS_STATE_MAX:
- case PS_SUSPENDED:
- break;
-
- /*
- * Threads in the following states need to be removed
- * from queues.
- */
- case PS_COND_WAIT:
- _cond_wait_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- _fd_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FILE_WAIT:
- _flockfile_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_JOIN:
- _join_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_MUTEX_WAIT:
- _mutex_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- case PS_POLL_WAIT:
- case PS_SELECT_WAIT:
- case PS_SIGSUSPEND:
- case PS_SIGWAIT:
- case PS_SLEEP_WAIT:
- case PS_SPINBLOCK:
- case PS_WAIT_WAIT:
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
- PTHREAD_WAITQ_REMOVE(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
- PTHREAD_WORKQ_REMOVE(thread);
- }
- break;
- }
-}
-
-static void
-thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
-{
- thread->interrupted = psf->saved_state.psd_interrupted;
- thread->sigmask = psf->saved_state.psd_sigmask;
- thread->state = psf->saved_state.psd_state;
- thread->flags = psf->saved_state.psd_flags;
+ if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
+ thread->sigmask = psf->saved_state.psd_sigmask;
+ thread->curframe = psf->saved_state.psd_curframe;
thread->wakeup_time = psf->saved_state.psd_wakeup_time;
thread->data = psf->saved_state.psd_wait_data;
+ thread->state = psf->saved_state.psd_state;
+ thread->flags = psf->saved_state.psd_flags;
+ thread->interrupted = psf->saved_state.psd_interrupted;
+ thread->longjmp_val = psf->saved_state.psd_longjmp_val;
+ thread->signo = psf->saved_state.psd_signo;
+ thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
}
static void
thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
{
- psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->ctxtype = thread->ctxtype;
+ memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc));
psf->saved_state.psd_sigmask = thread->sigmask;
- psf->saved_state.psd_state = thread->state;
- psf->saved_state.psd_flags = thread->flags;
- thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
- PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ |
- PTHREAD_FLAGS_IN_JOINQ;
+ psf->saved_state.psd_curframe = thread->curframe;
psf->saved_state.psd_wakeup_time = thread->wakeup_time;
psf->saved_state.psd_wait_data = thread->data;
+ psf->saved_state.psd_state = thread->state;
+ psf->saved_state.psd_flags = thread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->saved_state.psd_longjmp_val = thread->longjmp_val;
+ psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
+ psf->saved_state.psd_signo = thread->signo;
+ psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
}
#endif
diff --git a/lib/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c
index e78f329..4d13819 100644
--- a/lib/libc_r/uthread/uthread_sigaction.c
+++ b/lib/libc_r/uthread/uthread_sigaction.c
@@ -80,7 +80,7 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
* handler arguments.
*/
sigfillset(&gact.sa_mask);
- gact.sa_flags = SA_SIGINFO;
+ gact.sa_flags = SA_SIGINFO | SA_ONSTACK;
/*
* Check if the signal handler is being set to
diff --git a/lib/libc_r/uthread/uthread_sigmask.c b/lib/libc_r/uthread/uthread_sigmask.c
index bdb0b43..53d0774 100644
--- a/lib/libc_r/uthread/uthread_sigmask.c
+++ b/lib/libc_r/uthread/uthread_sigmask.c
@@ -81,6 +81,9 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
break;
}
+ /* Increment the sequence number: */
+ _thread_run->sigmask_seqno++;
+
/*
* Check if there are pending signals for the running
* thread or process that aren't blocked:
diff --git a/lib/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c
index 50cf927..5ff0967 100644
--- a/lib/libkse/thread/thr_cond.c
+++ b/lib/libkse/thread/thr_cond.c
@@ -47,7 +47,7 @@ static inline void cond_queue_enq(pthread_cond_t, pthread_t);
/* Reinitialize a condition variable to defaults. */
int
-_cond_reinit(pthread_cond_t * cond)
+_cond_reinit(pthread_cond_t *cond)
{
int ret = 0;
@@ -63,13 +63,14 @@ _cond_reinit(pthread_cond_t * cond)
(*cond)->c_flags = COND_FLAGS_INITED;
(*cond)->c_type = COND_TYPE_FAST;
(*cond)->c_mutex = NULL;
+ (*cond)->c_seqno = 0;
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
}
return (ret);
}
int
-pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
+pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
{
enum pthread_cond_type type;
pthread_cond_t pcond;
@@ -118,6 +119,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
memset(&pcond->lock,0,sizeof(pcond->lock));
*cond = pcond;
}
@@ -128,7 +130,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
}
int
-pthread_cond_destroy(pthread_cond_t * cond)
+pthread_cond_destroy(pthread_cond_t *cond)
{
int rval = 0;
@@ -155,22 +157,37 @@ pthread_cond_destroy(pthread_cond_t * cond)
}
int
-pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
+pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (cond == NULL)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized,
* perform the dynamic initialization:
*/
- else if (*cond != NULL ||
- (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -205,14 +222,16 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Wait forever: */
_thread_run->wakeup_time.tv_sec = -1;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -230,19 +249,23 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
- if (_thread_run->interrupted != 0) {
- /*
- * Remember that this thread
- * was interrupted:
- */
- interrupted = 1;
+ done = (seqno != (*cond)->c_seqno);
+ if ((_thread_run->flags &
+ PTHREAD_FLAGS_IN_CONDQ) != 0) {
/*
* Lock the condition variable
* while removing the thread.
@@ -260,6 +283,12 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
/*
+ * Save the interrupted flag; locking
+ * the mutex will destroy it.
+ */
+ interrupted = _thread_run->interrupted;
+
+ /*
* Note that even though this thread may have
* been canceled, POSIX requires that the mutex
* be reaquired prior to cancellation.
@@ -279,11 +308,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -296,18 +323,33 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
const struct timespec * abstime)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized, perform dynamic
* initialization.
*/
- else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -348,11 +390,13 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -368,35 +412,39 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
_SPINUNLOCK(&(*cond)->lock);
} else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
+ done = (seqno != (*cond)->c_seqno);
+
/*
- * Check if the wait timedout or was
- * interrupted (canceled):
+ * Check if the wait timedout, was
+ * interrupted (canceled), or needs to
+ * be resumed after handling a signal.
*/
if ((_thread_run->timeout == 0) &&
- (_thread_run->interrupted == 0)) {
+ (_thread_run->interrupted == 0) &&
+ (done != 0)) {
/* Lock the mutex: */
rval = _mutex_cv_lock(mutex);
-
} else {
- /*
- * Remember if this thread was
- * interrupted:
- */
- interrupted = _thread_run->interrupted;
-
- /* Lock the condition variable structure: */
+ /* Lock the CV structure: */
_SPINLOCK(&(*cond)->lock);
/*
* The wait timed out; remove
* the thread from the condition
- * variable queue:
+ * variable queue:
*/
cond_queue_remove(*cond,
_thread_run);
@@ -405,11 +453,18 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
- /* Unock the condition variable structure: */
+ /* Unock the CV structure: */
_SPINUNLOCK(&(*cond)->lock);
/* Return a timeout error: */
- rval = ETIMEDOUT;
+ if (_thread_run->timeout != 0)
+ rval = ETIMEDOUT;
+ /*
+ * Save the interrupted flag;
+ * locking the mutex will
+ * destroy it.
+ */
+ interrupted = _thread_run->interrupted;
/*
* Lock the mutex and ignore any
@@ -435,11 +490,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -473,6 +526,9 @@ pthread_cond_signal(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
if ((pthread = cond_queue_deq(*cond)) != NULL) {
/*
* Unless the thread is currently suspended,
@@ -538,6 +594,9 @@ pthread_cond_broadcast(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
/*
* Enter a loop to bring all threads off the
* condition queue:
diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c
index 0390f1b..430869e 100644
--- a/lib/libkse/thread/thr_create.c
+++ b/lib/libkse/thread/thr_create.c
@@ -49,16 +49,13 @@
static u_int64_t next_uniqueid = 1;
#define OFF(f) offsetof(struct pthread, f)
-#define SIGFRAME_OFF(f) offsetof(struct pthread_signal_frame, f)
int _thread_next_offset = OFF(tle.tqe_next);
int _thread_uniqueid_offset = OFF(uniqueid);
int _thread_state_offset = OFF(state);
int _thread_name_offset = OFF(name);
-int _thread_curframe_offset = OFF(curframe);
-int _thread_sigframe_ctx_offset = SIGFRAME_OFF(ctx);
-int _thread_sigframe_ctxtype_offset = SIGFRAME_OFF(ctxtype);
+int _thread_ctxtype_offset = OFF(ctxtype);
+int _thread_ctx_offset = OFF(ctx);
#undef OFF
-#undef SIGFRAME_OFF
int _thread_PS_RUNNING_value = PS_RUNNING;
int _thread_PS_DEAD_value = PS_DEAD;
@@ -66,12 +63,12 @@ int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG;
int _thread_CTX_JB_value = CTX_JB;
int _thread_CTX_SJB_value = CTX_SJB;
int _thread_CTX_UC_value = CTX_UC;
-int _thread_sigframe_size_value = sizeof(struct pthread_signal_frame);
int
pthread_create(pthread_t * thread, const pthread_attr_t * attr,
void *(*start_routine) (void *), void *arg)
{
+ struct itimerval itimer;
int f_gc = 0;
int ret = 0;
pthread_t gc_thread;
@@ -127,7 +124,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
-
+
/*
* Even if stack allocation fails, we don't want
* to try to use this location again, so
@@ -184,40 +181,35 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Initialise the thread for signals: */
new_thread->sigmask = _thread_run->sigmask;
+ new_thread->sigmask_seqno = 0;
- /* Initialize the first signal frame: */
- new_thread->sigframes[0] = &new_thread->sigframe0;
- new_thread->curframe = &new_thread->sigframe0;
+ /* Initialize the signal frame: */
+ new_thread->curframe = NULL;
/* Initialise the jump buffer: */
- _setjmp(new_thread->curframe->ctx.jb);
+ _setjmp(new_thread->ctx.jb);
/*
* Set up new stack frame so that it looks like it
* returned from a longjmp() to the beginning of
* _thread_start().
*/
- SET_RETURN_ADDR_JB(new_thread->curframe->ctx.jb,
- _thread_start);
+ SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
/* The stack starts high and builds down: */
- SET_STACK_JB(new_thread->curframe->ctx.jb,
+ SET_STACK_JB(new_thread->ctx.jb,
(long)new_thread->stack + pattr->stacksize_attr
- sizeof(double));
/* Initialize the rest of the frame: */
- new_thread->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- new_thread->curframe->stackp =
- GET_STACK_JB(new_thread->curframe->ctx.jb);
- new_thread->sigframe_count = 0;
+ new_thread->ctxtype = CTX_JB_NOSIG;
/* Copy the thread attributes: */
memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
/*
* Check if this thread is to inherit the scheduling
- * attributes from its parent:
+ * attributes from its parent:
*/
if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
/* Copy the scheduling attributes: */
@@ -233,7 +225,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/*
* Use just the thread priority, leaving the
* other scheduling attributes as their
- * default values:
+ * default values:
*/
new_thread->base_priority =
new_thread->attr.prio;
@@ -292,8 +284,19 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Return a pointer to the thread structure: */
(*thread) = new_thread;
+ if (f_gc != 0) {
+ /* Install the scheduling timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = _clock_res_usec;
+ itimer.it_value = itimer.it_interval;
+ if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
+ NULL) != 0)
+ PANIC("Cannot set interval timer");
+ }
+
/* Schedule the new user thread: */
_thread_kern_sched(NULL);
+
/*
* Start a garbage collector thread
* if necessary.
diff --git a/lib/libkse/thread/thr_detach.c b/lib/libkse/thread/thr_detach.c
index 3bade9d..6dd762a 100644
--- a/lib/libkse/thread/thr_detach.c
+++ b/lib/libkse/thread/thr_detach.c
@@ -65,7 +65,12 @@ pthread_detach(pthread_t pthread)
pthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
/* Make the thread runnable: */
- PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
+ PTHREAD_NEW_STATE(next_thread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ next_thread->error = ESRCH;
}
/*
diff --git a/lib/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c
index 7fbeb65..aef12fe 100644
--- a/lib/libkse/thread/thr_exit.c
+++ b/lib/libkse/thread/thr_exit.c
@@ -141,7 +141,7 @@ _thread_exit_cleanup(void)
void
pthread_exit(void *status)
{
- int frame;
+ pthread_t pthread;
/* Check if this thread is already in the process of exiting: */
if ((_thread_run->flags & PTHREAD_EXITING) != 0) {
@@ -159,7 +159,6 @@ pthread_exit(void *status)
while (_thread_run->cleanup != NULL) {
pthread_cleanup_pop(1);
}
-
if (_thread_run->attr.cleanup_attr != NULL) {
_thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr);
}
@@ -175,25 +174,6 @@ pthread_exit(void *status)
_thread_run->poll_data.fds = NULL;
}
- if ((frame = _thread_run->sigframe_count) == 0)
- _thread_exit_finish();
- else {
- /*
- * Jump back and unwind the signal frames to gracefully
- * cleanup.
- */
- ___longjmp(*_thread_run->sigframes[frame]->sig_jb, 1);
- }
-
- /* This point should not be reached. */
- PANIC("Dead thread has resumed");
-}
-
-void
-_thread_exit_finish(void)
-{
- pthread_t pthread;
-
/*
* Lock the garbage collector mutex to ensure that the garbage
* collector is not using the dead thread list.
@@ -233,6 +213,16 @@ _thread_exit_finish(void)
* detach this thread:
*/
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ if ((_thread_run->attr.flags & PTHREAD_DETACHED) != 0)
+ pthread->error = ESRCH;
+ else {
+ pthread->ret = _thread_run->ret;
+ pthread->error = 0;
+ }
}
/* Remove this thread from the thread list: */
@@ -240,5 +230,8 @@ _thread_exit_finish(void)
/* This thread will never be re-scheduled. */
_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
}
#endif
diff --git a/lib/libkse/thread/thr_info.c b/lib/libkse/thread/thr_info.c
index ca91512..956ae7c 100644
--- a/lib/libkse/thread/thr_info.c
+++ b/lib/libkse/thread/thr_info.c
@@ -41,6 +41,13 @@
#include <errno.h>
#include "pthread_private.h"
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+
struct s_thread_info {
enum pthread_state state;
char *name;
@@ -77,12 +84,11 @@ _thread_dump_info(void)
char s[512];
int fd;
int i;
- int j;
pthread_t pthread;
char tmpfile[128];
pq_list_t *pq_list;
- for (i = 0; i < 100000; i++) {
+ for (i = 0; i < 100000; i++) {
snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i",
getpid(), i);
/* Open the dump file for append and create it if necessary: */
@@ -112,70 +118,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the global list: */
TAILQ_FOREACH(pthread, &_thread_list, tle) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
-
- /* Check if this is the running thread: */
- if (pthread == _thread_run) {
- /* Output a record for the running thread: */
- strcpy(s, "This is the running thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Check if this is the initial thread: */
- if (pthread == _thread_initial) {
- /* Output a record for the initial thread: */
- strcpy(s, "This is the initial thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Process according to thread state: */
- switch (pthread->state) {
- /* File descriptor read lock wait: */
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- /* Write the lock details: */
- snprintf(s, sizeof(s), "fd %d[%s:%d]",
- pthread->data.fd.fd,
- pthread->data.fd.fname,
- pthread->data.fd.branch);
- _thread_sys_write(fd, s, strlen(s));
- snprintf(s, sizeof(s), "owner %pr/%pw\n",
- _thread_fd_table[pthread->data.fd.fd]->r_owner,
- _thread_fd_table[pthread->data.fd.fd]->w_owner);
- _thread_sys_write(fd, s, strlen(s));
- break;
- case PS_SIGWAIT:
- snprintf(s, sizeof(s), "sigmask (hi)");
- _thread_sys_write(fd, s, strlen(s));
- for (i = _SIG_WORDS - 1; i >= 0; i--) {
- snprintf(s, sizeof(s), "%08x\n",
- pthread->sigmask.__bits[i]);
- _thread_sys_write(fd, s, strlen(s));
- }
- snprintf(s, sizeof(s), "(lo)\n");
- _thread_sys_write(fd, s, strlen(s));
- break;
-
- /*
- * Trap other states that are not explicitly
- * coded to dump information:
- */
- default:
- /* Nothing to do here. */
- break;
- }
+ dump_thread(fd, pthread, /*long_verson*/ 1);
}
/* Output a header for ready threads: */
@@ -185,19 +128,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the ready queue: */
TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) {
TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
@@ -207,19 +138,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_waitingq, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Output a header for threads in the work queue: */
@@ -228,19 +147,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_workq, qe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Check if there are no dead threads: */
@@ -255,42 +162,38 @@ _thread_dump_info(void)
/*
* Enter a loop to report each thread in the global
- * dead thread list:
+ * dead thread list:
*/
TAILQ_FOREACH(pthread, &_dead_list, dle) {
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "Thread %p prio %3d [%s:%d]\n",
- pthread, pthread->base_priority,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
/* Output a header for file descriptors: */
- snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize);
+ snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR "
+ "TABLE (table size %d)\n\n", _thread_dtablesize);
_thread_sys_write(fd, s, strlen(s));
/* Enter a loop to report file descriptor lock usage: */
for (i = 0; i < _thread_dtablesize; i++) {
/*
* Check if memory is allocated for this file
- * descriptor:
+ * descriptor:
*/
if (_thread_fd_table[i] != NULL) {
/* Report the file descriptor lock status: */
snprintf(s, sizeof(s),
- "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n",
- i,
- _thread_fd_table[i]->r_owner,
- _thread_fd_table[i]->r_lockcount,
- _thread_fd_table[i]->r_fname,
- _thread_fd_table[i]->r_lineno,
- _thread_fd_table[i]->w_owner,
- _thread_fd_table[i]->w_lockcount,
- _thread_fd_table[i]->w_fname,
- _thread_fd_table[i]->w_lineno);
- _thread_sys_write(fd, s, strlen(s));
+ "fd[%3d] read owner %p count %d [%s:%d]\n"
+ " write owner %p count %d [%s:%d]\n",
+ i, _thread_fd_table[i]->r_owner,
+ _thread_fd_table[i]->r_lockcount,
+ _thread_fd_table[i]->r_fname,
+ _thread_fd_table[i]->r_lineno,
+ _thread_fd_table[i]->w_owner,
+ _thread_fd_table[i]->w_lockcount,
+ _thread_fd_table[i]->w_fname,
+ _thread_fd_table[i]->w_lineno);
+ _thread_sys_write(fd, s, strlen(s));
}
}
@@ -299,6 +202,78 @@ _thread_dump_info(void)
}
}
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->active_priority, thread_info[i].name, pthread->fname,
+ pthread->lineno);
+ _thread_sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == _thread_run) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thread_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ /* File descriptor read lock wait: */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ /* Write the lock details: */
+ snprintf(s, sizeof(s), "fd %d[%s:%d]",
+ pthread->data.fd.fd,
+ pthread->data.fd.fname,
+ pthread->data.fd.branch);
+ _thread_sys_write(fd, s, strlen(s));
+ snprintf(s, sizeof(s), "owner %pr/%pw\n",
+ _thread_fd_table[pthread->data.fd.fd]->r_owner,
+ _thread_fd_table[pthread->data.fd.fd]->w_owner);
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi)");
+ _thread_sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
+ pthread->sigmask.__bits[i]);
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+ }
+}
+
/* Set the thread name for debug: */
void
pthread_set_name_np(pthread_t thread, char *name)
diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c
index 3cbd453..35731c4 100644
--- a/lib/libkse/thread/thr_init.c
+++ b/lib/libkse/thread/thr_init.c
@@ -92,7 +92,7 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
- struct itimerval itimer;
+ struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@@ -133,7 +133,7 @@ _thread_init(void)
/*
* Create a pipe that is written to by the signal handler to prevent
- * signals being missed in calls to _select:
+ * signals being missed in calls to _select:
*/
if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
/* Cannot create pipe, so abort: */
@@ -168,12 +168,12 @@ _thread_init(void)
else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
/*
* Insufficient memory to initialise this application, so
- * abort:
+ * abort:
*/
PANIC("Cannot allocate memory for initial thread");
}
/* Allocate memory for the scheduler stack: */
- else if ((_thread_kern_sched_stack = malloc(PAGE_SIZE * 10)) == NULL)
+ else if ((_thread_kern_sched_stack = malloc(SCHED_STACK_SIZE)) == NULL)
PANIC("Failed to allocate stack for scheduler");
else {
/* Zero the global kernel thread structure: */
@@ -217,8 +217,8 @@ _thread_init(void)
/* Setup the context for the scheduler: */
_setjmp(_thread_kern_sched_jb);
- SET_STACK_JB(_thread_kern_sched_jb,
- _thread_kern_sched_stack + PAGE_SIZE*10 - sizeof(double));
+ SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack +
+ SCHED_STACK_SIZE - sizeof(double));
SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
/*
@@ -253,12 +253,9 @@ _thread_init(void)
/* Initialize last active: */
_thread_initial->last_active = (long) _sched_ticks;
- /* Initialize the initial signal frame: */
- _thread_initial->sigframes[0] = &_thread_initial->sigframe0;
- _thread_initial->curframe = &_thread_initial->sigframe0;
- _thread_initial->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- _thread_initial->curframe->stackp = (unsigned long) USRSTACK;
+ /* Initialize the initial context: */
+ _thread_initial->curframe = NULL;
+ _thread_initial->ctxtype = CTX_JB_NOSIG;
/* Initialise the rest of the fields: */
_thread_initial->poll_data.nfds = 0;
@@ -276,7 +273,7 @@ _thread_init(void)
/* Initialise the global signal action structure: */
sigfillset(&act.sa_mask);
act.sa_handler = (void (*) ()) _thread_sig_handler;
- act.sa_flags = SA_SIGINFO;
+ act.sa_flags = SA_SIGINFO | SA_ONSTACK;
/* Clear pending signals for the process: */
sigemptyset(&_process_sigpending);
@@ -284,6 +281,13 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
+ /* Create and install an alternate signal stack: */
+ alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
+ alt.ss_size = SIGSTKSZ;
+ alt.ss_flags = 0;
+ if (_thread_sys_sigaltstack(&alt, NULL) != 0)
+ PANIC("Unable to install alternate signal stack");
+
/* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
@@ -295,7 +299,7 @@ _thread_init(void)
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
- * initialisation fails:
+ * initialisation fails:
*/
PANIC("Cannot read signal handler info");
}
@@ -313,7 +317,7 @@ _thread_init(void)
_thread_sys_sigaction(SIGINFO, &act, NULL) != 0 ||
_thread_sys_sigaction(SIGCHLD, &act, NULL) != 0) {
/*
- * Abort this process if signal initialisation fails:
+ * Abort this process if signal initialisation fails:
*/
PANIC("Cannot initialise signal handler");
}
@@ -335,7 +339,7 @@ _thread_init(void)
if ((_thread_dtablesize = getdtablesize()) < 0) {
/*
* Cannot get the system defined table size, so abort
- * this process.
+ * this process.
*/
PANIC("Cannot get dtablesize");
}
@@ -346,7 +350,7 @@ _thread_init(void)
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for file descriptor table");
}
@@ -354,13 +358,13 @@ _thread_init(void)
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for pollfd table");
} else {
/*
* Enter a loop to initialise the file descriptor
- * table:
+ * table:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Initialise the file descriptor table: */
@@ -374,14 +378,6 @@ _thread_init(void)
PANIC("Cannot initialize stdio file "
"descriptor table entry");
}
-
- /* Install the scheduling timer: */
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = _clock_res_usec;
- itimer.it_value = itimer.it_interval;
- if (setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL) != 0)
- PANIC("Cannot set interval timer");
-
}
}
@@ -401,10 +397,10 @@ _thread_init(void)
}
/*
- * Special start up code for NetBSD/Alpha
+ * Special start up code for NetBSD/Alpha
*/
#if defined(__NetBSD__) && defined(__alpha__)
-int
+int
main(int argc, char *argv[], char *env);
int
diff --git a/lib/libkse/thread/thr_join.c b/lib/libkse/thread/thr_join.c
index cda31bd..b4a7c61 100644
--- a/lib/libkse/thread/thr_join.c
+++ b/lib/libkse/thread/thr_join.c
@@ -74,46 +74,74 @@ pthread_join(pthread_t pthread, void **thread_return)
else if (pthread->state != PS_DEAD) {
PTHREAD_ASSERT_NOT_IN_SYNCQ(_thread_run);
- /* Clear the interrupted flag: */
- _thread_run->interrupted = 0;
-
/*
- * Protect against being context switched out while
- * adding this thread to the join queue.
+ * Enter a loop in case this thread is woken prematurely
+ * in order to invoke a signal handler:
*/
- _thread_kern_sig_defer();
-
- /* Add the running thread to the join queue: */
- TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
- _thread_run->data.thread = pthread;
-
- /* Schedule the next thread: */
- _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
-
- if (_thread_run->interrupted != 0) {
- TAILQ_REMOVE(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ for (;;) {
+ /* Clear the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Protect against being context switched out while
+ * adding this thread to the join queue.
+ */
+ _thread_kern_sig_defer();
+
+ /* Add the running thread to the join queue: */
+ TAILQ_INSERT_TAIL(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
+ _thread_run->data.thread = pthread;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+
+ if ((_thread_run->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
+ TAILQ_REMOVE(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ }
+ _thread_run->data.thread = NULL;
+
+ _thread_kern_sig_undefer();
+
+ if (_thread_run->interrupted != 0) {
+ if (_thread_run->continuation != NULL)
+ _thread_run->continuation(_thread_run);
+ /*
+ * This thread was interrupted, probably to
+ * invoke a signal handler. Make sure the
+ * target thread is still joinable.
+ */
+ if (((_find_thread(pthread) != 0) &&
+ (_find_dead_thread(pthread) != 0)) ||
+ ((pthread->attr.flags &
+ PTHREAD_DETACHED) != 0)) {
+ /* Return an error: */
+ ret = ESRCH;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
+ else if (pthread->state == PS_DEAD) {
+ /* We're done; break out of the loop. */
+ break;
+ }
+ } else {
+ /*
+ * The thread return value and error are set
+ * by the thread we're joining to when it
+ * exits or detaches:
+ */
+ ret = _thread_run->error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = _thread_run->ret;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
}
- _thread_run->data.thread = NULL;
-
- _thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation(_thread_run);
-
- /* Check if the thread is not detached: */
- if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
- /* Check if the return value is required: */
- if (thread_return)
- /* Return the thread's return value: */
- *thread_return = pthread->ret;
- }
- else
- /* Return an error: */
- ret = ESRCH;
-
/* Check if the return value is required: */
} else if (thread_return != NULL)
/* Return the thread's return value: */
@@ -129,7 +157,7 @@ void
_join_backout(pthread_t pthread)
{
_thread_kern_sig_defer();
- if (pthread->state == PS_JOIN) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
TAILQ_REMOVE(&pthread->data.thread->join_queue, pthread, sqe);
_thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
}
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index 23f16bc..67844e1 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -60,7 +60,7 @@
#endif
/* Static function prototype definitions: */
-static void
+static void
thread_kern_poll(int wait_reqd);
static void
@@ -77,7 +77,7 @@ static int last_tick = 0;
* return to a previous frame.
*/
void
-_thread_kern_sched_frame(int frame)
+_thread_kern_sched_frame(struct pthread_signal_frame *psf)
{
/*
* Flag the pthread kernel as executing scheduler code
@@ -86,13 +86,8 @@ _thread_kern_sched_frame(int frame)
*/
_thread_kern_in_sched = 1;
- /* Return to the specified frame: */
- _thread_run->curframe = _thread_run->sigframes[frame];
- _thread_run->sigframe_count = frame;
-
- if (_thread_run->sigframe_count == 0)
- /* Restore the threads priority: */
- _thread_run->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+ /* Restore the signal frame: */
+ _thread_sigframe_restore(_thread_run, psf);
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
@@ -127,16 +122,16 @@ _thread_kern_sched(ucontext_t *scp)
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
- if (_setjmp(_thread_run->curframe->ctx.jb) == 0) {
+ if (_setjmp(_thread_run->ctx.jb) == 0) {
/* Flag the jump buffer was the last state saved: */
- _thread_run->curframe->ctxtype = CTX_JB_NOSIG;
- _thread_run->curframe->longjmp_val = 1;
+ _thread_run->ctxtype = CTX_JB_NOSIG;
+ _thread_run->longjmp_val = 1;
} else {
DBG_MSG("Returned from ___longjmp, thread %p\n",
_thread_run);
/*
* This point is reached when a longjmp() is called
- * to restore the state of a thread.
+ * to restore the state of a thread.
*
* This is the normal way out of the scheduler.
*/
@@ -147,7 +142,7 @@ _thread_kern_sched(ucontext_t *scp)
PTHREAD_AT_CANCEL_POINT) == 0) &&
((_thread_run->cancelflags &
PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
- /*
+ /*
* Cancellations override signals.
*
* Stick a cancellation point at the
@@ -183,7 +178,6 @@ _thread_kern_sched_sig(void)
void
_thread_kern_scheduler(void)
{
- struct pthread_signal_frame *psf;
struct timespec ts;
struct timeval tv;
pthread_t pthread, pthread_h;
@@ -205,7 +199,7 @@ _thread_kern_scheduler(void)
* ready to run. This loop completes when there are no more threads
* in the global list or when a thread has its state restored by
* either a sigreturn (if the state was saved as a sigcontext) or a
- * longjmp (if the state was saved by a setjmp).
+ * longjmp (if the state was saved by a setjmp).
*/
while (!(TAILQ_EMPTY(&_thread_list))) {
/* Get the current time of day: */
@@ -229,7 +223,7 @@ _thread_kern_scheduler(void)
if (_thread_run->state != PS_RUNNING) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
_thread_run->last_inactive = (long)current_tick;
if (_thread_run->last_inactive <
@@ -266,7 +260,7 @@ _thread_kern_scheduler(void)
/*
* States which do not depend on file descriptor I/O
- * operations or timeouts:
+ * operations or timeouts:
*/
case PS_DEADLOCK:
case PS_FDLR_WAIT:
@@ -326,10 +320,16 @@ _thread_kern_scheduler(void)
}
/*
+ * Avoid polling file descriptors if there are none
+ * waiting:
+ */
+ if (TAILQ_EMPTY(&_workq) == 0) {
+ }
+ /*
* Poll file descriptors only if a new scheduling signal
* has occurred or if we have no more runnable threads.
*/
- if (((current_tick = _sched_ticks) != last_tick) ||
+ else if (((current_tick = _sched_ticks) != last_tick) ||
((_thread_run->state != PS_RUNNING) &&
(PTHREAD_PRIOQ_FIRST() == NULL))) {
/* Unprotect the scheduling queues: */
@@ -337,7 +337,7 @@ _thread_kern_scheduler(void)
/*
* Poll file descriptors to update the state of threads
- * waiting on file I/O where data may be available:
+ * waiting on file I/O where data may be available:
*/
thread_kern_poll(0);
@@ -392,7 +392,7 @@ _thread_kern_scheduler(void)
if (add_to_prioq != 0) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
current_tick = _sched_ticks;
_thread_run->last_inactive = (long)current_tick;
@@ -445,7 +445,7 @@ _thread_kern_scheduler(void)
/*
* Lock the pthread kernel by changing the pointer to
* the running thread to point to the global kernel
- * thread structure:
+ * thread structure:
*/
_thread_run = &_thread_kern_thread;
DBG_MSG("No runnable threads, using kernel thread %p\n",
@@ -456,7 +456,7 @@ _thread_kern_scheduler(void)
/*
* There are no threads ready to run, so wait until
- * something happens that changes this condition:
+ * something happens that changes this condition:
*/
thread_kern_poll(1);
@@ -524,7 +524,7 @@ _thread_kern_scheduler(void)
/*
* Save the current time as the time that the thread
- * became active:
+ * became active:
*/
current_tick = _sched_ticks;
_thread_run->last_active = (long) current_tick;
@@ -532,7 +532,7 @@ _thread_kern_scheduler(void)
/*
* Check if this thread is running for the first time
* or running again after using its full time slice
- * allocation:
+ * allocation:
*/
if (_thread_run->slice_usec == -1) {
/* Reset the accumulated time slice period: */
@@ -551,36 +551,39 @@ _thread_kern_scheduler(void)
/*
* Continue the thread at its current frame:
*/
- psf = _thread_run->curframe;
- switch(psf->ctxtype) {
+ switch(_thread_run->ctxtype) {
case CTX_JB_NOSIG:
- ___longjmp(psf->ctx.jb, psf->longjmp_val);
+ ___longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_JB:
- __longjmp(psf->ctx.jb, psf->longjmp_val);
+ __longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_SJB:
- __siglongjmp(psf->ctx.sigjb, psf->longjmp_val);
+ __siglongjmp(_thread_run->ctx.sigjb,
+ _thread_run->longjmp_val);
break;
case CTX_UC:
/* XXX - Restore FP regsisters? */
- FP_RESTORE_UC(&psf->ctx.uc);
+ FP_RESTORE_UC(&_thread_run->ctx.uc);
/*
* Do a sigreturn to restart the thread that
- * was interrupted by a signal:
+ * was interrupted by a signal:
*/
_thread_kern_in_sched = 0;
#if NOT_YET
- _setcontext(&psf->ctx.uc);
+ _setcontext(&_thread_run->ctx.uc);
#else
/*
* Ensure the process signal mask is set
* correctly:
*/
- psf->ctx.uc.uc_sigmask = _process_sigmask;
- _thread_sys_sigreturn(&psf->ctx.uc);
+ _thread_run->ctx.uc.uc_sigmask =
+ _process_sigmask;
+ _thread_sys_sigreturn(&_thread_run->ctx.uc);
#endif
break;
}
@@ -800,14 +803,14 @@ thread_kern_poll(int wait_reqd)
/*
* Wait for a file descriptor to be ready for read, write, or
- * an exception, or a timeout to occur:
+ * an exception, or a timeout to occur:
*/
count = _thread_sys_poll(_thread_pfd_table, nfds, timeout_ms);
if (kern_pipe_added != 0)
/*
* Remove the pthread kernel pipe file descriptor
- * from the pollfd table:
+ * from the pollfd table:
*/
nfds = 1;
else
@@ -821,7 +824,7 @@ thread_kern_poll(int wait_reqd)
(_thread_pfd_table[0].revents & POLLRDNORM))) {
/*
* If the kernel read pipe was included in the
- * count:
+ * count:
*/
if (count > 0) {
/* Decrement the count of file descriptors: */
@@ -843,7 +846,7 @@ thread_kern_poll(int wait_reqd)
/*
* Enter a loop to look for threads waiting on file
* descriptors that are flagged as available by the
- * _poll syscall:
+ * _poll syscall:
*/
PTHREAD_WAITQ_SETACTIVE();
TAILQ_FOREACH(pthread, &_workq, qe) {
@@ -986,7 +989,7 @@ _thread_kern_set_timeout(const struct timespec * timeout)
if (timeout == NULL) {
/*
* Set the wakeup time to something that can be recognised as
- * different to an actual time of day:
+ * different to an actual time of day:
*/
_thread_run->wakeup_time.tv_sec = -1;
_thread_run->wakeup_time.tv_nsec = -1;
@@ -1042,7 +1045,7 @@ _thread_kern_sig_undefer(void)
if (_sigq_check_reqd != 0)
_thread_kern_sched(NULL);
- /*
+ /*
* Check for asynchronous cancellation before delivering any
* pending signals:
*/
@@ -1071,7 +1074,7 @@ dequeue_signals(void)
int num;
/*
- * Enter a loop to clear the pthread kernel pipe:
+ * Enter a loop to clear the pthread kernel pipe:
*/
while (((num = _thread_sys_read(_thread_kern_pipe[0], bufr,
sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) {
diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c
index ec6c0f6..f3649db 100644
--- a/lib/libkse/thread/thr_mutex.c
+++ b/lib/libkse/thread/thr_mutex.c
@@ -406,13 +406,29 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_thread_init();
if (mutex == NULL)
- ret = EINVAL;
+ return (EINVAL);
/*
* If the mutex is statically initialized, perform the dynamic
* initialization:
*/
- else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
+ if ((*mutex == NULL) &&
+ ((ret = init_static(mutex)) != 0))
+ return (ret);
+
+ /* Reset the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ while (((*mutex)->m_owner != _thread_run) && (ret == 0) &&
+ (_thread_run->interrupted == 0)) {
/*
* Defer signals to protect the scheduling queues from
* access by the signal handler:
@@ -432,9 +448,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_MUTEX_INIT_LINK(*mutex);
}
- /* Reset the interrupted flag: */
- _thread_run->interrupted = 0;
-
/* Process according to mutex type: */
switch ((*mutex)->m_protocol) {
/* Default POSIX mutex: */
@@ -624,12 +637,12 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
* necessary:
*/
_thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
}
+ if (_thread_run->interrupted != 0 &&
+ _thread_run->continuation != NULL)
+ _thread_run->continuation((void *) _thread_run);
+
/* Return the completion status: */
return (ret);
}
@@ -1381,7 +1394,7 @@ _mutex_lock_backout(pthread_t pthread)
* access by the signal handler:
*/
_thread_kern_sig_defer();
- if (pthread->state == PS_MUTEX_WAIT) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
mutex = pthread->data.mutex;
/* Lock the mutex structure: */
@@ -1390,7 +1403,7 @@ _mutex_lock_backout(pthread_t pthread)
mutex_queue_remove(mutex, pthread);
/* This thread is no longer waiting for the mutex: */
- mutex->m_owner->data.mutex = NULL;
+ pthread->data.mutex = NULL;
/* Unlock the mutex structure: */
_SPINUNLOCK(&mutex->lock);
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index 5076510..e8fff12 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -327,6 +327,7 @@ struct pthread_cond {
pthread_mutex_t c_mutex;
void *c_data;
long c_flags;
+ int c_seqno;
/*
* Lock for accesses to this structure.
@@ -351,7 +352,7 @@ struct pthread_cond_attr {
*/
#define PTHREAD_COND_STATIC_INITIALIZER \
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
- 0, _SPINLOCK_INITIALIZER }
+ 0, 0, _SPINLOCK_INITIALIZER }
/*
* Semaphore definitions.
@@ -424,6 +425,9 @@ enum pthread_susp {
*/
#define PTHREAD_STACK_INITIAL 0x100000
+/* Size of the scheduler stack: */
+#define SCHED_STACK_SIZE PAGE_SIZE
+
/*
* Define the different priority ranges. All applications have thread
* priorities constrained within 0-31. The threads library raises the
@@ -574,13 +578,20 @@ union pthread_wait_data {
*/
typedef void (*thread_continuation_t) (void *);
+struct pthread_signal_frame;
+
struct pthread_state_data {
- int psd_interrupted;
+ struct pthread_signal_frame *psd_curframe;
sigset_t psd_sigmask;
- enum pthread_state psd_state;
- int psd_flags;
struct timespec psd_wakeup_time;
union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_longjmp_val;
+ int psd_sigmask_seqno;
+ int psd_signo;
+ int psd_sig_defer_count;
/* XXX - What about thread->timeout and/or thread->error? */
};
@@ -620,9 +631,6 @@ struct pthread_signal_frame {
*/
struct pthread_state_data saved_state;
- /* Beginning (bottom) of threads stack frame for this signal. */
- unsigned long stackp;
-
/*
* Threads return context; ctxtype identifies the type of context.
* For signal frame 0, these point to the context storage area
@@ -637,18 +645,10 @@ struct pthread_signal_frame {
} ctx;
thread_context_t ctxtype;
int longjmp_val;
-
- /* Threads "jump out of signal handler" destination frame. */
- int dst_frame;
-
- /*
- * Used to return back to the signal handling frame in case
- * the application tries to change contexts from the handler.
- */
- jmp_buf *sig_jb;
-
int signo; /* signal, arg 1 to sighandler */
int sig_has_args; /* use signal args if true */
+ ucontext_t uc;
+ siginfo_t siginfo;
};
/*
@@ -685,18 +685,20 @@ struct pthread {
struct pthread_attr attr;
/*
- * Used for tracking delivery of nested signal handlers.
- * Signal frame 0 is used for normal context (when no
- * signal handlers are active for the thread). Frame
- * 1 is used as the context for the first signal, and
- * frames 2 .. NSIG-1 are used when additional signals
- * arrive interrupting already active signal handlers.
+ * Threads return context; ctxtype identifies the type of context.
+ */
+ union {
+ jmp_buf jb;
+ sigjmp_buf sigjb;
+ ucontext_t uc;
+ } ctx;
+ thread_context_t ctxtype;
+ int longjmp_val;
+
+ /*
+ * Used for tracking delivery of signal handlers.
*/
- struct pthread_signal_frame *sigframes[NSIG];
- struct pthread_signal_frame sigframe0;
struct pthread_signal_frame *curframe;
- int sigframe_count;
- int sigframe_done;
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -716,6 +718,7 @@ struct pthread {
*/
sigset_t sigmask;
sigset_t sigpend;
+ int sigmask_seqno;
int check_pending;
/* Thread state: */
@@ -1078,7 +1081,11 @@ SCLASS int _thread_dfl_count[NSIG];
* Pending signals and mask for this process:
*/
SCLASS sigset_t _process_sigpending;
-SCLASS sigset_t _process_sigmask;
+SCLASS sigset_t _process_sigmask
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { {0, 0, 0, 0} }
+#endif
+;
/*
* Scheduling queues:
@@ -1222,7 +1229,6 @@ void _waitq_clearactive(void);
#endif
void _thread_exit(char *, int, char *);
void _thread_exit_cleanup(void);
-void _thread_exit_finish(void);
void _thread_fd_unlock(int, int);
void _thread_fd_unlock_debug(int, int, char *, int);
void _thread_fd_unlock_owned(pthread_t);
@@ -1232,7 +1238,7 @@ void _thread_dump_info(void);
void _thread_init(void);
void _thread_kern_sched(ucontext_t *);
void _thread_kern_scheduler(void);
-void _thread_kern_sched_frame(int frame);
+void _thread_kern_sched_frame(struct pthread_signal_frame *psf);
void _thread_kern_sched_sig(void);
void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno);
void _thread_kern_sched_state_unlock(enum pthread_state state,
@@ -1245,7 +1251,7 @@ void _thread_sig_check_pending(pthread_t pthread);
void _thread_sig_handle_pending(void);
void _thread_sig_send(pthread_t pthread, int sig);
void _thread_sig_wrapper(void);
-int _thread_sigframe_find(pthread_t pthread, void *stackp);
+void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
void _thread_start(void);
void _thread_seterrno(pthread_t, int);
int _thread_fd_table_init(int fd);
@@ -1262,6 +1268,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
+int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c
index f19582d..3bcd9c1 100644
--- a/lib/libkse/thread/thr_sig.c
+++ b/lib/libkse/thread/thr_sig.c
@@ -49,9 +49,7 @@ static void thread_sig_check_state(pthread_t pthread, int sig);
static pthread_t thread_sig_find(int sig);
static void thread_sig_handle_special(int sig);
static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp);
-static void thread_sigframe_add(pthread_t thread, int sig);
-static void thread_sigframe_leave(pthread_t thread, int frame);
-static void thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
+static void thread_sigframe_add(pthread_t thread, int sig, int has_args);
static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf);
/* #define DEBUG_SIGNAL */
@@ -72,21 +70,30 @@ static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *
void
_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
- pthread_t pthread;
- int current_frame;
+ pthread_t pthread, pthread_h;
+ void *stackp;
+ int in_sched = 0;
char c;
if (ucp == NULL)
PANIC("Thread signal handler received null context");
DBG_MSG("Got signal %d, current thread %p\n", sig, _thread_run);
+ if (_thread_kern_in_sched != 0)
+ in_sched = 1;
+ else {
+ stackp = (void *)GET_STACK_UC(ucp);
+ if ((stackp >= _thread_kern_sched_stack) &&
+ (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE))
+ in_sched = 1;
+ }
/* Check if an interval timer signal: */
if (sig == _SCHED_SIGNAL) {
/* Update the scheduling clock: */
gettimeofday((struct timeval *)&_sched_tod, NULL);
_sched_ticks++;
- if (_thread_kern_in_sched != 0) {
+ if (in_sched != 0) {
/*
* The scheduler is already running; ignore this
* signal.
@@ -108,13 +115,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/*
* Schedule the next thread. This function is not
* expected to return because it will do a longjmp
- * instead.
+ * instead.
*/
_thread_kern_sched(ucp);
/*
* This point should not be reached, so abort the
- * process:
+ * process:
*/
PANIC("Returned to signal function from scheduler");
}
@@ -124,8 +131,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* is accessing the scheduling queues or if there is a currently
* running thread that has deferred signals.
*/
- else if ((_thread_kern_in_sched != 0) ||
- (_thread_run->sig_defer_count > 0)) {
+ else if ((in_sched != 0) || (_thread_run->sig_defer_count > 0)) {
/* Cast the signal number to a character variable: */
c = sig;
@@ -176,10 +182,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* cannot be interrupted by other signals.
*/
else if (_thread_sigq[sig - 1].blocked == 0) {
- /* The signal is not blocked; handle the signal: */
- current_frame = _thread_run->sigframe_count;
-
/*
+ * The signal is not blocked; handle the signal.
+ *
* Ignore subsequent occurrences of this signal
* until the current signal is handled:
*/
@@ -204,6 +209,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/* Handle special signals: */
thread_sig_handle_special(sig);
+ pthread_h = NULL;
if ((pthread = thread_sig_find(sig)) != NULL) {
DBG_MSG("Got signal %d, adding frame to thread %p\n",
sig, pthread);
@@ -221,9 +227,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
thread_sig_add(pthread, sig, /*has_args*/ 1);
/* Take a peek at the next ready to run thread: */
- pthread = PTHREAD_PRIOQ_FIRST();
+ pthread_h = PTHREAD_PRIOQ_FIRST();
DBG_MSG("Finished adding frame, head of prio list %p\n",
- pthread);
+ pthread_h);
}
else
DBG_MSG("No thread to handle signal %d\n", sig);
@@ -235,11 +241,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* signal and the currently running thread is not in a
* signal handler.
*/
- if ((_thread_run->sigframe_count > current_frame) ||
- ((pthread != NULL) &&
- (pthread->active_priority > _thread_run->active_priority))) {
+ if ((pthread == _thread_run) || ((pthread_h != NULL) &&
+ (pthread_h->active_priority > _thread_run->active_priority))) {
/* Enter the kernel scheduler: */
- DBG_MSG("Entering scheduler from signal handler\n");
_thread_kern_sched(ucp);
}
}
@@ -253,17 +257,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
static void
thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp)
{
- struct pthread_signal_frame *psf;
-
- psf = _thread_run->curframe;
-
- memcpy(&psf->ctx.uc, ucp, sizeof(*ucp));
+ memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp));
/* XXX - Save FP registers too? */
- FP_SAVE_UC(&psf->ctx.uc);
+ FP_SAVE_UC(&pthread->ctx.uc);
/* Mark the context saved as a ucontext: */
- psf->ctxtype = CTX_UC;
+ pthread->ctxtype = CTX_UC;
}
/*
@@ -278,10 +278,13 @@ thread_sig_find(int sig)
DBG_MSG("Looking for thread to handle signal %d\n", sig);
/* Check if the signal requires a dump of thread information: */
- if (sig == SIGINFO)
+ if (sig == SIGINFO) {
/* Dump thread information to file: */
_thread_dump_info();
+ /* Unblock this signal to allow further dumps: */
+ _thread_sigq[sig - 1].blocked = 0;
+ }
/* Check if an interval timer signal: */
else if (sig == _SCHED_SIGNAL) {
/*
@@ -326,7 +329,7 @@ thread_sig_find(int sig)
* A signal handler is not invoked for threads
* in sigwait. Clear the blocked and pending
* flags.
- */
+ */
_thread_sigq[sig - 1].blocked = 0;
_thread_sigq[sig - 1].pending = 0;
@@ -375,7 +378,7 @@ thread_sig_find(int sig)
signaled_thread == NULL) {
/*
* Enter a loop to look for other threads
- * capable of receiving the signal:
+ * capable of receiving the signal:
*/
TAILQ_FOREACH(pthread, &_thread_list, tle) {
if (!sigismember(&pthread->sigmask,
@@ -565,8 +568,7 @@ thread_sig_handle_special(int sig)
static void
thread_sig_add(pthread_t pthread, int sig, int has_args)
{
- int restart, frame;
- int block_signals = 0;
+ int restart;
int suppress_handler = 0;
restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
@@ -657,8 +659,11 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* States which cannot be interrupted but still require the
* signal handler to run:
*/
- case PS_COND_WAIT:
case PS_JOIN:
+ /* Only set the interrupted flag for PS_JOIN: */
+ pthread->interrupted = 1;
+ /* FALLTHROUGH */
+ case PS_COND_WAIT:
case PS_MUTEX_WAIT:
/*
* Remove the thread from the wait queue. It will
@@ -687,14 +692,6 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* the actual handler.
*/
PTHREAD_WAITQ_REMOVE(pthread);
- /*
- * To ensure the thread is removed from the fd and file
- * queues before any other signal interrupts it, set the
- * signal mask to block all signals. As soon as the thread
- * is removed from the queue the signal mask will be
- * restored.
- */
- block_signals = 1;
break;
/*
@@ -736,22 +733,15 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
}
if (suppress_handler == 0) {
+ /* Setup a signal frame and save the current threads state: */
+ thread_sigframe_add(pthread, sig, has_args);
+
/*
- * Save the current state of the thread and add a
- * new signal frame.
+ * Signals are deferred until just before the threads
+ * signal handler is invoked:
*/
- frame = pthread->sigframe_count;
- thread_sigframe_save(pthread, pthread->curframe);
- thread_sigframe_add(pthread, sig);
- pthread->sigframes[frame + 1]->sig_has_args = has_args;
- SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask);
- if (block_signals != 0) {
- /* Save the signal mask and block all signals: */
- pthread->sigframes[frame + 1]->saved_state.psd_sigmask =
- pthread->sigmask;
- sigfillset(&pthread->sigmask);
- }
-
+ pthread->sig_defer_count = 1;
+
/* Make sure the thread is runnable: */
if (pthread->state != PS_RUNNING)
PTHREAD_SET_STATE(pthread, PS_RUNNING);
@@ -925,19 +915,16 @@ _thread_sig_wrapper(void)
{
void (*sigfunc)(int, siginfo_t *, void *);
struct pthread_signal_frame *psf;
- pthread_t thread;
- int dead = 0;
- int i, sig, has_args;
- int frame, dst_frame;
+ pthread_t thread;
thread = _thread_run;
/* Get the current frame and state: */
- frame = thread->sigframe_count;
- PTHREAD_ASSERT(frame > 0, "Invalid signal frame in signal handler");
psf = thread->curframe;
+ thread->curframe = NULL;
+ PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
- /* Check the threads previous state: */
+ /* Check the threads previous state: */
if (psf->saved_state.psd_state != PS_RUNNING) {
/*
* Do a little cleanup handling for those threads in
@@ -950,15 +937,26 @@ _thread_sig_wrapper(void)
case PS_FDLW_WAIT:
_fd_lock_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
break;
case PS_FILE_WAIT:
_flockfile_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
+ break;
+
+ case PS_COND_WAIT:
+ _cond_wait_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_JOIN:
+ _join_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ _mutex_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
break;
default:
@@ -966,11 +964,20 @@ _thread_sig_wrapper(void)
}
}
+ /* Unblock the signal in case we don't return from the handler: */
+ _thread_sigq[psf->signo - 1].blocked = 0;
+
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+
/*
- * Unless the thread exits or longjmps out of the signal handler,
- * return to the previous frame:
+ * Reenable interruptions without checking for the need to
+ * context switch:
*/
- dst_frame = frame - 1;
+ thread->sig_defer_count = 0;
/*
* Check that a custom handler is installed and if the signal
@@ -979,141 +986,45 @@ _thread_sig_wrapper(void)
sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction;
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN)) {
+ DBG_MSG("_thread_sig_wrapper: Calling signal handler for "
+ "thread 0x%p\n", thread);
/*
- * The signal jump buffer is allocated off the stack.
- * If the signal handler tries to [_][sig]longjmp() or
- * setcontext(), our wrapped versions of these routines
- * will copy the user supplied jump buffer or context
- * to the destination signal frame, set the destination
- * signal frame in psf->dst_frame, and _longjmp() back
- * to here.
- */
- jmp_buf jb;
-
- /*
- * Set up the context for abnormal returns out of signal
- * handlers.
+ * Dispatch the signal via the custom signal
+ * handler:
*/
- psf->sig_jb = &jb;
- if (_setjmp(jb) == 0) {
- DBG_MSG("_thread_sig_wrapper: Entering frame %d, "
- "stack 0x%lx\n", frame, GET_STACK_JB(jb));
- /*
- * Invalidate the destination frame before calling
- * the signal handler.
- */
- psf->dst_frame = -1;
-
- /*
- * Dispatch the signal via the custom signal
- * handler:
- */
- if (psf->sig_has_args == 0)
- (*(sigfunc))(psf->signo, NULL, NULL);
- else if ((_thread_sigact[psf->signo - 1].sa_flags &
- SA_SIGINFO) != 0)
- (*(sigfunc))(psf->signo,
- &_thread_sigq[psf->signo - 1].siginfo,
- &_thread_sigq[psf->signo - 1].uc);
- else
- (*(sigfunc))(psf->signo,
- (siginfo_t *)_thread_sigq[psf->signo - 1].siginfo.si_code,
- &_thread_sigq[psf->signo - 1].uc);
- }
- else {
- /*
- * The return from _setjmp() should only be non-zero
- * when the signal handler wants to xxxlongjmp() or
- * setcontext() to a different context, or if the
- * thread has exited (via pthread_exit).
- */
- /*
- * Grab a copy of the destination frame before it
- * gets clobbered after unwinding.
- */
- dst_frame = psf->dst_frame;
- DBG_MSG("Abnormal exit from handler for signal %d, "
- "frame %d\n", psf->signo, frame);
-
- /* Has the thread exited? */
- if ((dead = thread->flags & PTHREAD_EXITING) != 0)
- /* When exiting, unwind to frame 0. */
- dst_frame = 0;
- else if ((dst_frame < 0) || (dst_frame > frame))
- PANIC("Attempt to unwind to invalid "
- "signal frame");
-
- /* Unwind to the target frame: */
- for (i = frame; i > dst_frame; i--) {
- DBG_MSG("Leaving frame %d, signal %d\n", i,
- thread->sigframes[i]->signo);
- /* Leave the current signal frame: */
- thread_sigframe_leave(thread, i);
-
- /*
- * Save whatever is needed out of the state
- * data; as soon as the frame count is
- * is decremented, another signal can arrive
- * and corrupt this view of the state data.
- */
- sig = thread->sigframes[i]->signo;
- has_args = thread->sigframes[i]->sig_has_args;
-
- /*
- * We're done with this signal frame:
- */
- thread->curframe = thread->sigframes[i - 1];
- thread->sigframe_count = i - 1;
-
- /*
- * Only unblock the signal if it was a
- * process signal as opposed to a signal
- * generated by pthread_kill().
- */
- if (has_args != 0)
- _thread_sigq[sig - 1].blocked = 0;
- }
- }
+ if (psf->sig_has_args == 0)
+ (*(sigfunc))(psf->signo, NULL, NULL);
+ else if ((_thread_sigact[psf->signo - 1].sa_flags &
+ SA_SIGINFO) != 0)
+ (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc);
+ else
+ (*(sigfunc))(psf->signo,
+ (siginfo_t *)psf->siginfo.si_code, &psf->uc);
}
-
/*
- * Call the kernel scheduler to schedule the next
- * thread.
+ * Call the kernel scheduler to safely restore the frame and
+ * schedule the next thread:
*/
- if (dead == 0) {
- /* Restore the threads state: */
- thread_sigframe_restore(thread, thread->sigframes[dst_frame]);
- _thread_kern_sched_frame(dst_frame);
- }
- else {
- PTHREAD_ASSERT(dst_frame == 0,
- "Invalid signal frame for dead thread");
-
- /* Perform any necessary cleanup before exiting. */
- thread_sigframe_leave(thread, 0);
-
- /* This should never return: */
- _thread_exit_finish();
- PANIC("Return from _thread_exit_finish in signal wrapper");
- }
+ _thread_kern_sched_frame(psf);
}
static void
-thread_sigframe_add(pthread_t thread, int sig)
+thread_sigframe_add(pthread_t thread, int sig, int has_args)
{
+ struct pthread_signal_frame *psf = NULL;
unsigned long stackp = 0;
/* Get the top of the threads stack: */
- switch (thread->curframe->ctxtype) {
+ switch (thread->ctxtype) {
case CTX_JB:
case CTX_JB_NOSIG:
- stackp = GET_STACK_JB(thread->curframe->ctx.jb);
+ stackp = GET_STACK_JB(thread->ctx.jb);
break;
case CTX_SJB:
- stackp = GET_STACK_SJB(thread->curframe->ctx.sigjb);
+ stackp = GET_STACK_SJB(thread->ctx.sigjb);
break;
case CTX_UC:
- stackp = GET_STACK_UC(&thread->curframe->ctx.uc);
+ stackp = GET_STACK_UC(&thread->ctx.uc);
break;
default:
PANIC("Invalid thread context type");
@@ -1130,138 +1041,76 @@ thread_sigframe_add(pthread_t thread, int sig)
/* Allocate room on top of the stack for a new signal frame: */
stackp -= sizeof(struct pthread_signal_frame);
- /* Set up the new frame: */
- thread->sigframe_count++;
- thread->sigframes[thread->sigframe_count] =
- (struct pthread_signal_frame *) stackp;
- thread->curframe = thread->sigframes[thread->sigframe_count];
- thread->curframe->stackp = stackp;
- thread->curframe->ctxtype = CTX_JB_NOSIG;
- thread->curframe->longjmp_val = 1;
- thread->curframe->signo = sig;
+ psf = (struct pthread_signal_frame *) stackp;
- /*
- * Set up the context:
- */
- _setjmp(thread->curframe->ctx.jb);
- SET_STACK_JB(thread->curframe->ctx.jb, stackp);
- SET_RETURN_ADDR_JB(thread->curframe->ctx.jb, _thread_sig_wrapper);
-}
+ /* Save the current context in the signal frame: */
+ thread_sigframe_save(thread, psf);
-/*
- * Locate the signal frame from the specified stack pointer.
- */
-int
-_thread_sigframe_find(pthread_t pthread, void *stackp)
-{
- int frame;
+ /* Set handler specific information: */
+ psf->sig_has_args = has_args;
+ psf->signo = sig;
+ if (has_args) {
+ /* Copy the signal handler arguments to the signal frame: */
+ memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
+ sizeof(psf->uc));
+ memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
+ sizeof(psf->siginfo));
+ }
+ /* Set up the new frame: */
+ thread->curframe = psf;
+ thread->ctxtype = CTX_JB_NOSIG;
+ thread->longjmp_val = 1;
+ thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
+ PTHREAD_FLAGS_IN_SYNCQ;
/*
- * Find the destination of the target frame based on the
- * given stack pointer.
+ * Set up the context:
*/
- for (frame = pthread->sigframe_count; frame >= 0; frame--) {
- if (stackp < (void *)pthread->sigframes[frame]->stackp)
- break;
- }
- return (frame);
+ stackp += sizeof(double);
+ _setjmp(thread->ctx.jb);
+ SET_STACK_JB(thread->ctx.jb, stackp);
+ SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
}
-
+
void
-thread_sigframe_leave(pthread_t thread, int frame)
+_thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
{
- struct pthread_state_data *psd;
-
- psd = &thread->sigframes[frame]->saved_state;
-
+ thread->ctxtype = psf->ctxtype;
+ memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc));
/*
- * Perform any necessary cleanup for this signal frame:
+ * Only restore the signal mask if it hasn't been changed
+ * by the application during invocation of the signal handler:
*/
- switch (psd->psd_state) {
- case PS_DEAD:
- case PS_DEADLOCK:
- case PS_RUNNING:
- case PS_SIGTHREAD:
- case PS_STATE_MAX:
- case PS_SUSPENDED:
- break;
-
- /*
- * Threads in the following states need to be removed
- * from queues.
- */
- case PS_COND_WAIT:
- _cond_wait_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- _fd_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FILE_WAIT:
- _flockfile_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_JOIN:
- _join_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_MUTEX_WAIT:
- _mutex_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- case PS_POLL_WAIT:
- case PS_SELECT_WAIT:
- case PS_SIGSUSPEND:
- case PS_SIGWAIT:
- case PS_SLEEP_WAIT:
- case PS_SPINBLOCK:
- case PS_WAIT_WAIT:
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
- PTHREAD_WAITQ_REMOVE(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
- PTHREAD_WORKQ_REMOVE(thread);
- }
- break;
- }
-}
-
-static void
-thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
-{
- thread->interrupted = psf->saved_state.psd_interrupted;
- thread->sigmask = psf->saved_state.psd_sigmask;
- thread->state = psf->saved_state.psd_state;
- thread->flags = psf->saved_state.psd_flags;
+ if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
+ thread->sigmask = psf->saved_state.psd_sigmask;
+ thread->curframe = psf->saved_state.psd_curframe;
thread->wakeup_time = psf->saved_state.psd_wakeup_time;
thread->data = psf->saved_state.psd_wait_data;
+ thread->state = psf->saved_state.psd_state;
+ thread->flags = psf->saved_state.psd_flags;
+ thread->interrupted = psf->saved_state.psd_interrupted;
+ thread->longjmp_val = psf->saved_state.psd_longjmp_val;
+ thread->signo = psf->saved_state.psd_signo;
+ thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
}
static void
thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
{
- psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->ctxtype = thread->ctxtype;
+ memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc));
psf->saved_state.psd_sigmask = thread->sigmask;
- psf->saved_state.psd_state = thread->state;
- psf->saved_state.psd_flags = thread->flags;
- thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
- PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ |
- PTHREAD_FLAGS_IN_JOINQ;
+ psf->saved_state.psd_curframe = thread->curframe;
psf->saved_state.psd_wakeup_time = thread->wakeup_time;
psf->saved_state.psd_wait_data = thread->data;
+ psf->saved_state.psd_state = thread->state;
+ psf->saved_state.psd_flags = thread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->saved_state.psd_longjmp_val = thread->longjmp_val;
+ psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
+ psf->saved_state.psd_signo = thread->signo;
+ psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
}
#endif
diff --git a/lib/libkse/thread/thr_sigaction.c b/lib/libkse/thread/thr_sigaction.c
index e78f329..4d13819 100644
--- a/lib/libkse/thread/thr_sigaction.c
+++ b/lib/libkse/thread/thr_sigaction.c
@@ -80,7 +80,7 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
* handler arguments.
*/
sigfillset(&gact.sa_mask);
- gact.sa_flags = SA_SIGINFO;
+ gact.sa_flags = SA_SIGINFO | SA_ONSTACK;
/*
* Check if the signal handler is being set to
diff --git a/lib/libkse/thread/thr_sigmask.c b/lib/libkse/thread/thr_sigmask.c
index bdb0b43..53d0774 100644
--- a/lib/libkse/thread/thr_sigmask.c
+++ b/lib/libkse/thread/thr_sigmask.c
@@ -81,6 +81,9 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
break;
}
+ /* Increment the sequence number: */
+ _thread_run->sigmask_seqno++;
+
/*
* Check if there are pending signals for the running
* thread or process that aren't blocked:
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c
index 50cf927..5ff0967 100644
--- a/lib/libpthread/thread/thr_cond.c
+++ b/lib/libpthread/thread/thr_cond.c
@@ -47,7 +47,7 @@ static inline void cond_queue_enq(pthread_cond_t, pthread_t);
/* Reinitialize a condition variable to defaults. */
int
-_cond_reinit(pthread_cond_t * cond)
+_cond_reinit(pthread_cond_t *cond)
{
int ret = 0;
@@ -63,13 +63,14 @@ _cond_reinit(pthread_cond_t * cond)
(*cond)->c_flags = COND_FLAGS_INITED;
(*cond)->c_type = COND_TYPE_FAST;
(*cond)->c_mutex = NULL;
+ (*cond)->c_seqno = 0;
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
}
return (ret);
}
int
-pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
+pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
{
enum pthread_cond_type type;
pthread_cond_t pcond;
@@ -118,6 +119,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
pcond->c_mutex = NULL;
+ pcond->c_seqno = 0;
memset(&pcond->lock,0,sizeof(pcond->lock));
*cond = pcond;
}
@@ -128,7 +130,7 @@ pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
}
int
-pthread_cond_destroy(pthread_cond_t * cond)
+pthread_cond_destroy(pthread_cond_t *cond)
{
int rval = 0;
@@ -155,22 +157,37 @@ pthread_cond_destroy(pthread_cond_t * cond)
}
int
-pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
+pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (cond == NULL)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized,
* perform the dynamic initialization:
*/
- else if (*cond != NULL ||
- (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL &&
+ (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -205,14 +222,16 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Wait forever: */
_thread_run->wakeup_time.tv_sec = -1;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -230,19 +249,23 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
- if (_thread_run->interrupted != 0) {
- /*
- * Remember that this thread
- * was interrupted:
- */
- interrupted = 1;
+ done = (seqno != (*cond)->c_seqno);
+ if ((_thread_run->flags &
+ PTHREAD_FLAGS_IN_CONDQ) != 0) {
/*
* Lock the condition variable
* while removing the thread.
@@ -260,6 +283,12 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
}
/*
+ * Save the interrupted flag; locking
+ * the mutex will destroy it.
+ */
+ interrupted = _thread_run->interrupted;
+
+ /*
* Note that even though this thread may have
* been canceled, POSIX requires that the mutex
* be reaquired prior to cancellation.
@@ -279,11 +308,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -296,18 +323,33 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
const struct timespec * abstime)
{
int rval = 0;
+ int done = 0;
int interrupted = 0;
+ int unlock_mutex = 1;
+ int seqno;
_thread_enter_cancellation_point();
if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000)
- rval = EINVAL;
+ return (EINVAL);
/*
* If the condition variable is statically initialized, perform dynamic
* initialization.
*/
- else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
+ if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
+ return (rval);
+
+ /*
+ * Enter a loop waiting for a condition signal or broadcast
+ * to wake up this thread. A loop is needed in case the waiting
+ * thread is interrupted by a signal to execute a signal handler.
+ * It is not (currently) possible to remain in the waiting queue
+ * while running a handler. Instead, the thread is interrupted
+ * and backed out of the waiting queue prior to executing the
+ * signal handler.
+ */
+ do {
/* Lock the condition variable structure: */
_SPINLOCK(&(*cond)->lock);
@@ -348,11 +390,13 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
cond_queue_enq(*cond, _thread_run);
- /* Remember the mutex that is being used: */
+ /* Remember the mutex and sequence number: */
(*cond)->c_mutex = *mutex;
+ seqno = (*cond)->c_seqno;
/* Unlock the mutex: */
- if ((rval = _mutex_cv_unlock(mutex)) != 0) {
+ if ((unlock_mutex != 0) &&
+ ((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
* the running thread from the condition
@@ -368,35 +412,39 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
_SPINUNLOCK(&(*cond)->lock);
} else {
/*
+ * Don't unlock the mutex in the event
+ * this thread has to be requeued in
+ * condition variable queue:
+ */
+ unlock_mutex = 0;
+
+ /*
* Schedule the next thread and unlock
* the condition variable structure:
*/
_thread_kern_sched_state_unlock(PS_COND_WAIT,
&(*cond)->lock, __FILE__, __LINE__);
+ done = (seqno != (*cond)->c_seqno);
+
/*
- * Check if the wait timedout or was
- * interrupted (canceled):
+ * Check if the wait timedout, was
+ * interrupted (canceled), or needs to
+ * be resumed after handling a signal.
*/
if ((_thread_run->timeout == 0) &&
- (_thread_run->interrupted == 0)) {
+ (_thread_run->interrupted == 0) &&
+ (done != 0)) {
/* Lock the mutex: */
rval = _mutex_cv_lock(mutex);
-
} else {
- /*
- * Remember if this thread was
- * interrupted:
- */
- interrupted = _thread_run->interrupted;
-
- /* Lock the condition variable structure: */
+ /* Lock the CV structure: */
_SPINLOCK(&(*cond)->lock);
/*
* The wait timed out; remove
* the thread from the condition
- * variable queue:
+ * variable queue:
*/
cond_queue_remove(*cond,
_thread_run);
@@ -405,11 +453,18 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
- /* Unock the condition variable structure: */
+ /* Unock the CV structure: */
_SPINUNLOCK(&(*cond)->lock);
/* Return a timeout error: */
- rval = ETIMEDOUT;
+ if (_thread_run->timeout != 0)
+ rval = ETIMEDOUT;
+ /*
+ * Save the interrupted flag;
+ * locking the mutex will
+ * destroy it.
+ */
+ interrupted = _thread_run->interrupted;
/*
* Lock the mutex and ignore any
@@ -435,11 +490,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
break;
}
- if (interrupted != 0) {
- if (_thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
- }
- }
+ if ((interrupted != 0) && (_thread_run->continuation != NULL))
+ _thread_run->continuation((void *) _thread_run);
+ } while ((done == 0) && (rval == 0));
_thread_leave_cancellation_point();
@@ -473,6 +526,9 @@ pthread_cond_signal(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
if ((pthread = cond_queue_deq(*cond)) != NULL) {
/*
* Unless the thread is currently suspended,
@@ -538,6 +594,9 @@ pthread_cond_broadcast(pthread_cond_t * cond)
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
+ /* Increment the sequence number: */
+ (*cond)->c_seqno++;
+
/*
* Enter a loop to bring all threads off the
* condition queue:
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
index 0390f1b..430869e 100644
--- a/lib/libpthread/thread/thr_create.c
+++ b/lib/libpthread/thread/thr_create.c
@@ -49,16 +49,13 @@
static u_int64_t next_uniqueid = 1;
#define OFF(f) offsetof(struct pthread, f)
-#define SIGFRAME_OFF(f) offsetof(struct pthread_signal_frame, f)
int _thread_next_offset = OFF(tle.tqe_next);
int _thread_uniqueid_offset = OFF(uniqueid);
int _thread_state_offset = OFF(state);
int _thread_name_offset = OFF(name);
-int _thread_curframe_offset = OFF(curframe);
-int _thread_sigframe_ctx_offset = SIGFRAME_OFF(ctx);
-int _thread_sigframe_ctxtype_offset = SIGFRAME_OFF(ctxtype);
+int _thread_ctxtype_offset = OFF(ctxtype);
+int _thread_ctx_offset = OFF(ctx);
#undef OFF
-#undef SIGFRAME_OFF
int _thread_PS_RUNNING_value = PS_RUNNING;
int _thread_PS_DEAD_value = PS_DEAD;
@@ -66,12 +63,12 @@ int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG;
int _thread_CTX_JB_value = CTX_JB;
int _thread_CTX_SJB_value = CTX_SJB;
int _thread_CTX_UC_value = CTX_UC;
-int _thread_sigframe_size_value = sizeof(struct pthread_signal_frame);
int
pthread_create(pthread_t * thread, const pthread_attr_t * attr,
void *(*start_routine) (void *), void *arg)
{
+ struct itimerval itimer;
int f_gc = 0;
int ret = 0;
pthread_t gc_thread;
@@ -127,7 +124,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
} else {
/* Allocate a new stack. */
stack = _next_stack + PTHREAD_STACK_GUARD;
-
+
/*
* Even if stack allocation fails, we don't want
* to try to use this location again, so
@@ -184,40 +181,35 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Initialise the thread for signals: */
new_thread->sigmask = _thread_run->sigmask;
+ new_thread->sigmask_seqno = 0;
- /* Initialize the first signal frame: */
- new_thread->sigframes[0] = &new_thread->sigframe0;
- new_thread->curframe = &new_thread->sigframe0;
+ /* Initialize the signal frame: */
+ new_thread->curframe = NULL;
/* Initialise the jump buffer: */
- _setjmp(new_thread->curframe->ctx.jb);
+ _setjmp(new_thread->ctx.jb);
/*
* Set up new stack frame so that it looks like it
* returned from a longjmp() to the beginning of
* _thread_start().
*/
- SET_RETURN_ADDR_JB(new_thread->curframe->ctx.jb,
- _thread_start);
+ SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
/* The stack starts high and builds down: */
- SET_STACK_JB(new_thread->curframe->ctx.jb,
+ SET_STACK_JB(new_thread->ctx.jb,
(long)new_thread->stack + pattr->stacksize_attr
- sizeof(double));
/* Initialize the rest of the frame: */
- new_thread->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- new_thread->curframe->stackp =
- GET_STACK_JB(new_thread->curframe->ctx.jb);
- new_thread->sigframe_count = 0;
+ new_thread->ctxtype = CTX_JB_NOSIG;
/* Copy the thread attributes: */
memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
/*
* Check if this thread is to inherit the scheduling
- * attributes from its parent:
+ * attributes from its parent:
*/
if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
/* Copy the scheduling attributes: */
@@ -233,7 +225,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/*
* Use just the thread priority, leaving the
* other scheduling attributes as their
- * default values:
+ * default values:
*/
new_thread->base_priority =
new_thread->attr.prio;
@@ -292,8 +284,19 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Return a pointer to the thread structure: */
(*thread) = new_thread;
+ if (f_gc != 0) {
+ /* Install the scheduling timer: */
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = _clock_res_usec;
+ itimer.it_value = itimer.it_interval;
+ if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
+ NULL) != 0)
+ PANIC("Cannot set interval timer");
+ }
+
/* Schedule the new user thread: */
_thread_kern_sched(NULL);
+
/*
* Start a garbage collector thread
* if necessary.
diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c
index 3bade9d..6dd762a 100644
--- a/lib/libpthread/thread/thr_detach.c
+++ b/lib/libpthread/thread/thr_detach.c
@@ -65,7 +65,12 @@ pthread_detach(pthread_t pthread)
pthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
/* Make the thread runnable: */
- PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
+ PTHREAD_NEW_STATE(next_thread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ next_thread->error = ESRCH;
}
/*
diff --git a/lib/libpthread/thread/thr_exit.c b/lib/libpthread/thread/thr_exit.c
index 7fbeb65..aef12fe 100644
--- a/lib/libpthread/thread/thr_exit.c
+++ b/lib/libpthread/thread/thr_exit.c
@@ -141,7 +141,7 @@ _thread_exit_cleanup(void)
void
pthread_exit(void *status)
{
- int frame;
+ pthread_t pthread;
/* Check if this thread is already in the process of exiting: */
if ((_thread_run->flags & PTHREAD_EXITING) != 0) {
@@ -159,7 +159,6 @@ pthread_exit(void *status)
while (_thread_run->cleanup != NULL) {
pthread_cleanup_pop(1);
}
-
if (_thread_run->attr.cleanup_attr != NULL) {
_thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr);
}
@@ -175,25 +174,6 @@ pthread_exit(void *status)
_thread_run->poll_data.fds = NULL;
}
- if ((frame = _thread_run->sigframe_count) == 0)
- _thread_exit_finish();
- else {
- /*
- * Jump back and unwind the signal frames to gracefully
- * cleanup.
- */
- ___longjmp(*_thread_run->sigframes[frame]->sig_jb, 1);
- }
-
- /* This point should not be reached. */
- PANIC("Dead thread has resumed");
-}
-
-void
-_thread_exit_finish(void)
-{
- pthread_t pthread;
-
/*
* Lock the garbage collector mutex to ensure that the garbage
* collector is not using the dead thread list.
@@ -233,6 +213,16 @@ _thread_exit_finish(void)
* detach this thread:
*/
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
+
+ /*
+ * Set the return value for the woken thread:
+ */
+ if ((_thread_run->attr.flags & PTHREAD_DETACHED) != 0)
+ pthread->error = ESRCH;
+ else {
+ pthread->ret = _thread_run->ret;
+ pthread->error = 0;
+ }
}
/* Remove this thread from the thread list: */
@@ -240,5 +230,8 @@ _thread_exit_finish(void)
/* This thread will never be re-scheduled. */
_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
+
+ /* This point should not be reached. */
+ PANIC("Dead thread has resumed");
}
#endif
diff --git a/lib/libpthread/thread/thr_info.c b/lib/libpthread/thread/thr_info.c
index ca91512..956ae7c 100644
--- a/lib/libpthread/thread/thr_info.c
+++ b/lib/libpthread/thread/thr_info.c
@@ -41,6 +41,13 @@
#include <errno.h>
#include "pthread_private.h"
+#ifndef NELEMENTS
+#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+static void dump_thread(int fd, pthread_t pthread, int long_version);
+
+
struct s_thread_info {
enum pthread_state state;
char *name;
@@ -77,12 +84,11 @@ _thread_dump_info(void)
char s[512];
int fd;
int i;
- int j;
pthread_t pthread;
char tmpfile[128];
pq_list_t *pq_list;
- for (i = 0; i < 100000; i++) {
+ for (i = 0; i < 100000; i++) {
snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i",
getpid(), i);
/* Open the dump file for append and create it if necessary: */
@@ -112,70 +118,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the global list: */
TAILQ_FOREACH(pthread, &_thread_list, tle) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
-
- /* Check if this is the running thread: */
- if (pthread == _thread_run) {
- /* Output a record for the running thread: */
- strcpy(s, "This is the running thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Check if this is the initial thread: */
- if (pthread == _thread_initial) {
- /* Output a record for the initial thread: */
- strcpy(s, "This is the initial thread\n");
- _thread_sys_write(fd, s, strlen(s));
- }
- /* Process according to thread state: */
- switch (pthread->state) {
- /* File descriptor read lock wait: */
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- /* Write the lock details: */
- snprintf(s, sizeof(s), "fd %d[%s:%d]",
- pthread->data.fd.fd,
- pthread->data.fd.fname,
- pthread->data.fd.branch);
- _thread_sys_write(fd, s, strlen(s));
- snprintf(s, sizeof(s), "owner %pr/%pw\n",
- _thread_fd_table[pthread->data.fd.fd]->r_owner,
- _thread_fd_table[pthread->data.fd.fd]->w_owner);
- _thread_sys_write(fd, s, strlen(s));
- break;
- case PS_SIGWAIT:
- snprintf(s, sizeof(s), "sigmask (hi)");
- _thread_sys_write(fd, s, strlen(s));
- for (i = _SIG_WORDS - 1; i >= 0; i--) {
- snprintf(s, sizeof(s), "%08x\n",
- pthread->sigmask.__bits[i]);
- _thread_sys_write(fd, s, strlen(s));
- }
- snprintf(s, sizeof(s), "(lo)\n");
- _thread_sys_write(fd, s, strlen(s));
- break;
-
- /*
- * Trap other states that are not explicitly
- * coded to dump information:
- */
- default:
- /* Nothing to do here. */
- break;
- }
+ dump_thread(fd, pthread, /*long_verson*/ 1);
}
/* Output a header for ready threads: */
@@ -185,19 +128,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the ready queue: */
TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) {
TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
@@ -207,19 +138,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_waitingq, pqe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Output a header for threads in the work queue: */
@@ -228,19 +147,7 @@ _thread_dump_info(void)
/* Enter a loop to report each thread in the waiting queue: */
TAILQ_FOREACH (pthread, &_workq, qe) {
- /* Find the state: */
- for (j = 0; j < (sizeof(thread_info) /
- sizeof(struct s_thread_info)) - 1; j++)
- if (thread_info[j].state == pthread->state)
- break;
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
- pthread, (pthread->name == NULL) ?
- "":pthread->name, pthread->base_priority,
- thread_info[j].name,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
/* Check if there are no dead threads: */
@@ -255,42 +162,38 @@ _thread_dump_info(void)
/*
* Enter a loop to report each thread in the global
- * dead thread list:
+ * dead thread list:
*/
TAILQ_FOREACH(pthread, &_dead_list, dle) {
- /* Output a record for the current thread: */
- snprintf(s, sizeof(s),
- "Thread %p prio %3d [%s:%d]\n",
- pthread, pthread->base_priority,
- pthread->fname,pthread->lineno);
- _thread_sys_write(fd, s, strlen(s));
+ dump_thread(fd, pthread, /*long_version*/ 0);
}
}
/* Output a header for file descriptors: */
- snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR TABLE (table size %d)\n\n",_thread_dtablesize);
+ snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR "
+ "TABLE (table size %d)\n\n", _thread_dtablesize);
_thread_sys_write(fd, s, strlen(s));
/* Enter a loop to report file descriptor lock usage: */
for (i = 0; i < _thread_dtablesize; i++) {
/*
* Check if memory is allocated for this file
- * descriptor:
+ * descriptor:
*/
if (_thread_fd_table[i] != NULL) {
/* Report the file descriptor lock status: */
snprintf(s, sizeof(s),
- "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n",
- i,
- _thread_fd_table[i]->r_owner,
- _thread_fd_table[i]->r_lockcount,
- _thread_fd_table[i]->r_fname,
- _thread_fd_table[i]->r_lineno,
- _thread_fd_table[i]->w_owner,
- _thread_fd_table[i]->w_lockcount,
- _thread_fd_table[i]->w_fname,
- _thread_fd_table[i]->w_lineno);
- _thread_sys_write(fd, s, strlen(s));
+ "fd[%3d] read owner %p count %d [%s:%d]\n"
+ " write owner %p count %d [%s:%d]\n",
+ i, _thread_fd_table[i]->r_owner,
+ _thread_fd_table[i]->r_lockcount,
+ _thread_fd_table[i]->r_fname,
+ _thread_fd_table[i]->r_lineno,
+ _thread_fd_table[i]->w_owner,
+ _thread_fd_table[i]->w_lockcount,
+ _thread_fd_table[i]->w_fname,
+ _thread_fd_table[i]->w_lineno);
+ _thread_sys_write(fd, s, strlen(s));
}
}
@@ -299,6 +202,78 @@ _thread_dump_info(void)
}
}
+static void
+dump_thread(int fd, pthread_t pthread, int long_version)
+{
+ char s[512];
+ int i;
+
+ /* Find the state: */
+ for (i = 0; i < NELEMENTS(thread_info) - 1; i++)
+ if (thread_info[i].state == pthread->state)
+ break;
+
+ /* Output a record for the thread: */
+ snprintf(s, sizeof(s),
+ "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
+ pthread, (pthread->name == NULL) ? "" : pthread->name,
+ pthread->active_priority, thread_info[i].name, pthread->fname,
+ pthread->lineno);
+ _thread_sys_write(fd, s, strlen(s));
+
+ if (long_version != 0) {
+ /* Check if this is the running thread: */
+ if (pthread == _thread_run) {
+ /* Output a record for the running thread: */
+ strcpy(s, "This is the running thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Check if this is the initial thread: */
+ if (pthread == _thread_initial) {
+ /* Output a record for the initial thread: */
+ strcpy(s, "This is the initial thread\n");
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ /* Process according to thread state: */
+ switch (pthread->state) {
+ /* File descriptor read lock wait: */
+ case PS_FDLR_WAIT:
+ case PS_FDLW_WAIT:
+ case PS_FDR_WAIT:
+ case PS_FDW_WAIT:
+ /* Write the lock details: */
+ snprintf(s, sizeof(s), "fd %d[%s:%d]",
+ pthread->data.fd.fd,
+ pthread->data.fd.fname,
+ pthread->data.fd.branch);
+ _thread_sys_write(fd, s, strlen(s));
+ snprintf(s, sizeof(s), "owner %pr/%pw\n",
+ _thread_fd_table[pthread->data.fd.fd]->r_owner,
+ _thread_fd_table[pthread->data.fd.fd]->w_owner);
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ case PS_SIGWAIT:
+ snprintf(s, sizeof(s), "sigmask (hi)");
+ _thread_sys_write(fd, s, strlen(s));
+ for (i = _SIG_WORDS - 1; i >= 0; i--) {
+ snprintf(s, sizeof(s), "%08x\n",
+ pthread->sigmask.__bits[i]);
+ _thread_sys_write(fd, s, strlen(s));
+ }
+ snprintf(s, sizeof(s), "(lo)\n");
+ _thread_sys_write(fd, s, strlen(s));
+ break;
+ /*
+ * Trap other states that are not explicitly
+ * coded to dump information:
+ */
+ default:
+ /* Nothing to do here. */
+ break;
+ }
+ }
+}
+
/* Set the thread name for debug: */
void
pthread_set_name_np(pthread_t thread, char *name)
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index 3cbd453..35731c4 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -92,7 +92,7 @@ _thread_init(void)
int mib[2];
struct clockinfo clockinfo;
struct sigaction act;
- struct itimerval itimer;
+ struct sigaltstack alt;
/* Check if this function has already been called: */
if (_thread_initial)
@@ -133,7 +133,7 @@ _thread_init(void)
/*
* Create a pipe that is written to by the signal handler to prevent
- * signals being missed in calls to _select:
+ * signals being missed in calls to _select:
*/
if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
/* Cannot create pipe, so abort: */
@@ -168,12 +168,12 @@ _thread_init(void)
else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
/*
* Insufficient memory to initialise this application, so
- * abort:
+ * abort:
*/
PANIC("Cannot allocate memory for initial thread");
}
/* Allocate memory for the scheduler stack: */
- else if ((_thread_kern_sched_stack = malloc(PAGE_SIZE * 10)) == NULL)
+ else if ((_thread_kern_sched_stack = malloc(SCHED_STACK_SIZE)) == NULL)
PANIC("Failed to allocate stack for scheduler");
else {
/* Zero the global kernel thread structure: */
@@ -217,8 +217,8 @@ _thread_init(void)
/* Setup the context for the scheduler: */
_setjmp(_thread_kern_sched_jb);
- SET_STACK_JB(_thread_kern_sched_jb,
- _thread_kern_sched_stack + PAGE_SIZE*10 - sizeof(double));
+ SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack +
+ SCHED_STACK_SIZE - sizeof(double));
SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
/*
@@ -253,12 +253,9 @@ _thread_init(void)
/* Initialize last active: */
_thread_initial->last_active = (long) _sched_ticks;
- /* Initialize the initial signal frame: */
- _thread_initial->sigframes[0] = &_thread_initial->sigframe0;
- _thread_initial->curframe = &_thread_initial->sigframe0;
- _thread_initial->curframe->ctxtype = CTX_JB_NOSIG;
- /* Set the base of the stack: */
- _thread_initial->curframe->stackp = (unsigned long) USRSTACK;
+ /* Initialize the initial context: */
+ _thread_initial->curframe = NULL;
+ _thread_initial->ctxtype = CTX_JB_NOSIG;
/* Initialise the rest of the fields: */
_thread_initial->poll_data.nfds = 0;
@@ -276,7 +273,7 @@ _thread_init(void)
/* Initialise the global signal action structure: */
sigfillset(&act.sa_mask);
act.sa_handler = (void (*) ()) _thread_sig_handler;
- act.sa_flags = SA_SIGINFO;
+ act.sa_flags = SA_SIGINFO | SA_ONSTACK;
/* Clear pending signals for the process: */
sigemptyset(&_process_sigpending);
@@ -284,6 +281,13 @@ _thread_init(void)
/* Clear the signal queue: */
memset(_thread_sigq, 0, sizeof(_thread_sigq));
+ /* Create and install an alternate signal stack: */
+ alt.ss_sp = malloc(SIGSTKSZ); /* recommended stack size */
+ alt.ss_size = SIGSTKSZ;
+ alt.ss_flags = 0;
+ if (_thread_sys_sigaltstack(&alt, NULL) != 0)
+ PANIC("Unable to install alternate signal stack");
+
/* Enter a loop to get the existing signal status: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be trapped: */
@@ -295,7 +299,7 @@ _thread_init(void)
&_thread_sigact[i - 1]) != 0) {
/*
* Abort this process if signal
- * initialisation fails:
+ * initialisation fails:
*/
PANIC("Cannot read signal handler info");
}
@@ -313,7 +317,7 @@ _thread_init(void)
_thread_sys_sigaction(SIGINFO, &act, NULL) != 0 ||
_thread_sys_sigaction(SIGCHLD, &act, NULL) != 0) {
/*
- * Abort this process if signal initialisation fails:
+ * Abort this process if signal initialisation fails:
*/
PANIC("Cannot initialise signal handler");
}
@@ -335,7 +339,7 @@ _thread_init(void)
if ((_thread_dtablesize = getdtablesize()) < 0) {
/*
* Cannot get the system defined table size, so abort
- * this process.
+ * this process.
*/
PANIC("Cannot get dtablesize");
}
@@ -346,7 +350,7 @@ _thread_init(void)
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for file descriptor table");
}
@@ -354,13 +358,13 @@ _thread_init(void)
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
/*
* Cannot allocate memory for the file descriptor
- * table, so abort this process.
+ * table, so abort this process.
*/
PANIC("Cannot allocate memory for pollfd table");
} else {
/*
* Enter a loop to initialise the file descriptor
- * table:
+ * table:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Initialise the file descriptor table: */
@@ -374,14 +378,6 @@ _thread_init(void)
PANIC("Cannot initialize stdio file "
"descriptor table entry");
}
-
- /* Install the scheduling timer: */
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = _clock_res_usec;
- itimer.it_value = itimer.it_interval;
- if (setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL) != 0)
- PANIC("Cannot set interval timer");
-
}
}
@@ -401,10 +397,10 @@ _thread_init(void)
}
/*
- * Special start up code for NetBSD/Alpha
+ * Special start up code for NetBSD/Alpha
*/
#if defined(__NetBSD__) && defined(__alpha__)
-int
+int
main(int argc, char *argv[], char *env);
int
diff --git a/lib/libpthread/thread/thr_join.c b/lib/libpthread/thread/thr_join.c
index cda31bd..b4a7c61 100644
--- a/lib/libpthread/thread/thr_join.c
+++ b/lib/libpthread/thread/thr_join.c
@@ -74,46 +74,74 @@ pthread_join(pthread_t pthread, void **thread_return)
else if (pthread->state != PS_DEAD) {
PTHREAD_ASSERT_NOT_IN_SYNCQ(_thread_run);
- /* Clear the interrupted flag: */
- _thread_run->interrupted = 0;
-
/*
- * Protect against being context switched out while
- * adding this thread to the join queue.
+ * Enter a loop in case this thread is woken prematurely
+ * in order to invoke a signal handler:
*/
- _thread_kern_sig_defer();
-
- /* Add the running thread to the join queue: */
- TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
- _thread_run->data.thread = pthread;
-
- /* Schedule the next thread: */
- _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
-
- if (_thread_run->interrupted != 0) {
- TAILQ_REMOVE(&(pthread->join_queue), _thread_run, sqe);
- _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ for (;;) {
+ /* Clear the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Protect against being context switched out while
+ * adding this thread to the join queue.
+ */
+ _thread_kern_sig_defer();
+
+ /* Add the running thread to the join queue: */
+ TAILQ_INSERT_TAIL(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags |= PTHREAD_FLAGS_IN_JOINQ;
+ _thread_run->data.thread = pthread;
+
+ /* Schedule the next thread: */
+ _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
+
+ if ((_thread_run->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
+ TAILQ_REMOVE(&(pthread->join_queue),
+ _thread_run, sqe);
+ _thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
+ }
+ _thread_run->data.thread = NULL;
+
+ _thread_kern_sig_undefer();
+
+ if (_thread_run->interrupted != 0) {
+ if (_thread_run->continuation != NULL)
+ _thread_run->continuation(_thread_run);
+ /*
+ * This thread was interrupted, probably to
+ * invoke a signal handler. Make sure the
+ * target thread is still joinable.
+ */
+ if (((_find_thread(pthread) != 0) &&
+ (_find_dead_thread(pthread) != 0)) ||
+ ((pthread->attr.flags &
+ PTHREAD_DETACHED) != 0)) {
+ /* Return an error: */
+ ret = ESRCH;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
+ else if (pthread->state == PS_DEAD) {
+ /* We're done; break out of the loop. */
+ break;
+ }
+ } else {
+ /*
+ * The thread return value and error are set
+ * by the thread we're joining to when it
+ * exits or detaches:
+ */
+ ret = _thread_run->error;
+ if ((ret == 0) && (thread_return != NULL))
+ *thread_return = _thread_run->ret;
+
+ /* We're done; break out of the loop. */
+ break;
+ }
}
- _thread_run->data.thread = NULL;
-
- _thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation(_thread_run);
-
- /* Check if the thread is not detached: */
- if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) {
- /* Check if the return value is required: */
- if (thread_return)
- /* Return the thread's return value: */
- *thread_return = pthread->ret;
- }
- else
- /* Return an error: */
- ret = ESRCH;
-
/* Check if the return value is required: */
} else if (thread_return != NULL)
/* Return the thread's return value: */
@@ -129,7 +157,7 @@ void
_join_backout(pthread_t pthread)
{
_thread_kern_sig_defer();
- if (pthread->state == PS_JOIN) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) {
TAILQ_REMOVE(&pthread->data.thread->join_queue, pthread, sqe);
_thread_run->flags &= ~PTHREAD_FLAGS_IN_JOINQ;
}
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index 23f16bc..67844e1 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -60,7 +60,7 @@
#endif
/* Static function prototype definitions: */
-static void
+static void
thread_kern_poll(int wait_reqd);
static void
@@ -77,7 +77,7 @@ static int last_tick = 0;
* return to a previous frame.
*/
void
-_thread_kern_sched_frame(int frame)
+_thread_kern_sched_frame(struct pthread_signal_frame *psf)
{
/*
* Flag the pthread kernel as executing scheduler code
@@ -86,13 +86,8 @@ _thread_kern_sched_frame(int frame)
*/
_thread_kern_in_sched = 1;
- /* Return to the specified frame: */
- _thread_run->curframe = _thread_run->sigframes[frame];
- _thread_run->sigframe_count = frame;
-
- if (_thread_run->sigframe_count == 0)
- /* Restore the threads priority: */
- _thread_run->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+ /* Restore the signal frame: */
+ _thread_sigframe_restore(_thread_run, psf);
/* Switch to the thread scheduler: */
___longjmp(_thread_kern_sched_jb, 1);
@@ -127,16 +122,16 @@ _thread_kern_sched(ucontext_t *scp)
_thread_kern_scheduler();
} else {
/* Save the state of the current thread: */
- if (_setjmp(_thread_run->curframe->ctx.jb) == 0) {
+ if (_setjmp(_thread_run->ctx.jb) == 0) {
/* Flag the jump buffer was the last state saved: */
- _thread_run->curframe->ctxtype = CTX_JB_NOSIG;
- _thread_run->curframe->longjmp_val = 1;
+ _thread_run->ctxtype = CTX_JB_NOSIG;
+ _thread_run->longjmp_val = 1;
} else {
DBG_MSG("Returned from ___longjmp, thread %p\n",
_thread_run);
/*
* This point is reached when a longjmp() is called
- * to restore the state of a thread.
+ * to restore the state of a thread.
*
* This is the normal way out of the scheduler.
*/
@@ -147,7 +142,7 @@ _thread_kern_sched(ucontext_t *scp)
PTHREAD_AT_CANCEL_POINT) == 0) &&
((_thread_run->cancelflags &
PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
- /*
+ /*
* Cancellations override signals.
*
* Stick a cancellation point at the
@@ -183,7 +178,6 @@ _thread_kern_sched_sig(void)
void
_thread_kern_scheduler(void)
{
- struct pthread_signal_frame *psf;
struct timespec ts;
struct timeval tv;
pthread_t pthread, pthread_h;
@@ -205,7 +199,7 @@ _thread_kern_scheduler(void)
* ready to run. This loop completes when there are no more threads
* in the global list or when a thread has its state restored by
* either a sigreturn (if the state was saved as a sigcontext) or a
- * longjmp (if the state was saved by a setjmp).
+ * longjmp (if the state was saved by a setjmp).
*/
while (!(TAILQ_EMPTY(&_thread_list))) {
/* Get the current time of day: */
@@ -229,7 +223,7 @@ _thread_kern_scheduler(void)
if (_thread_run->state != PS_RUNNING) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
_thread_run->last_inactive = (long)current_tick;
if (_thread_run->last_inactive <
@@ -266,7 +260,7 @@ _thread_kern_scheduler(void)
/*
* States which do not depend on file descriptor I/O
- * operations or timeouts:
+ * operations or timeouts:
*/
case PS_DEADLOCK:
case PS_FDLR_WAIT:
@@ -326,10 +320,16 @@ _thread_kern_scheduler(void)
}
/*
+ * Avoid polling file descriptors if there are none
+ * waiting:
+ */
+ if (TAILQ_EMPTY(&_workq) == 0) {
+ }
+ /*
* Poll file descriptors only if a new scheduling signal
* has occurred or if we have no more runnable threads.
*/
- if (((current_tick = _sched_ticks) != last_tick) ||
+ else if (((current_tick = _sched_ticks) != last_tick) ||
((_thread_run->state != PS_RUNNING) &&
(PTHREAD_PRIOQ_FIRST() == NULL))) {
/* Unprotect the scheduling queues: */
@@ -337,7 +337,7 @@ _thread_kern_scheduler(void)
/*
* Poll file descriptors to update the state of threads
- * waiting on file I/O where data may be available:
+ * waiting on file I/O where data may be available:
*/
thread_kern_poll(0);
@@ -392,7 +392,7 @@ _thread_kern_scheduler(void)
if (add_to_prioq != 0) {
/*
* Save the current time as the time that the
- * thread became inactive:
+ * thread became inactive:
*/
current_tick = _sched_ticks;
_thread_run->last_inactive = (long)current_tick;
@@ -445,7 +445,7 @@ _thread_kern_scheduler(void)
/*
* Lock the pthread kernel by changing the pointer to
* the running thread to point to the global kernel
- * thread structure:
+ * thread structure:
*/
_thread_run = &_thread_kern_thread;
DBG_MSG("No runnable threads, using kernel thread %p\n",
@@ -456,7 +456,7 @@ _thread_kern_scheduler(void)
/*
* There are no threads ready to run, so wait until
- * something happens that changes this condition:
+ * something happens that changes this condition:
*/
thread_kern_poll(1);
@@ -524,7 +524,7 @@ _thread_kern_scheduler(void)
/*
* Save the current time as the time that the thread
- * became active:
+ * became active:
*/
current_tick = _sched_ticks;
_thread_run->last_active = (long) current_tick;
@@ -532,7 +532,7 @@ _thread_kern_scheduler(void)
/*
* Check if this thread is running for the first time
* or running again after using its full time slice
- * allocation:
+ * allocation:
*/
if (_thread_run->slice_usec == -1) {
/* Reset the accumulated time slice period: */
@@ -551,36 +551,39 @@ _thread_kern_scheduler(void)
/*
* Continue the thread at its current frame:
*/
- psf = _thread_run->curframe;
- switch(psf->ctxtype) {
+ switch(_thread_run->ctxtype) {
case CTX_JB_NOSIG:
- ___longjmp(psf->ctx.jb, psf->longjmp_val);
+ ___longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_JB:
- __longjmp(psf->ctx.jb, psf->longjmp_val);
+ __longjmp(_thread_run->ctx.jb,
+ _thread_run->longjmp_val);
break;
case CTX_SJB:
- __siglongjmp(psf->ctx.sigjb, psf->longjmp_val);
+ __siglongjmp(_thread_run->ctx.sigjb,
+ _thread_run->longjmp_val);
break;
case CTX_UC:
/* XXX - Restore FP regsisters? */
- FP_RESTORE_UC(&psf->ctx.uc);
+ FP_RESTORE_UC(&_thread_run->ctx.uc);
/*
* Do a sigreturn to restart the thread that
- * was interrupted by a signal:
+ * was interrupted by a signal:
*/
_thread_kern_in_sched = 0;
#if NOT_YET
- _setcontext(&psf->ctx.uc);
+ _setcontext(&_thread_run->ctx.uc);
#else
/*
* Ensure the process signal mask is set
* correctly:
*/
- psf->ctx.uc.uc_sigmask = _process_sigmask;
- _thread_sys_sigreturn(&psf->ctx.uc);
+ _thread_run->ctx.uc.uc_sigmask =
+ _process_sigmask;
+ _thread_sys_sigreturn(&_thread_run->ctx.uc);
#endif
break;
}
@@ -800,14 +803,14 @@ thread_kern_poll(int wait_reqd)
/*
* Wait for a file descriptor to be ready for read, write, or
- * an exception, or a timeout to occur:
+ * an exception, or a timeout to occur:
*/
count = _thread_sys_poll(_thread_pfd_table, nfds, timeout_ms);
if (kern_pipe_added != 0)
/*
* Remove the pthread kernel pipe file descriptor
- * from the pollfd table:
+ * from the pollfd table:
*/
nfds = 1;
else
@@ -821,7 +824,7 @@ thread_kern_poll(int wait_reqd)
(_thread_pfd_table[0].revents & POLLRDNORM))) {
/*
* If the kernel read pipe was included in the
- * count:
+ * count:
*/
if (count > 0) {
/* Decrement the count of file descriptors: */
@@ -843,7 +846,7 @@ thread_kern_poll(int wait_reqd)
/*
* Enter a loop to look for threads waiting on file
* descriptors that are flagged as available by the
- * _poll syscall:
+ * _poll syscall:
*/
PTHREAD_WAITQ_SETACTIVE();
TAILQ_FOREACH(pthread, &_workq, qe) {
@@ -986,7 +989,7 @@ _thread_kern_set_timeout(const struct timespec * timeout)
if (timeout == NULL) {
/*
* Set the wakeup time to something that can be recognised as
- * different to an actual time of day:
+ * different to an actual time of day:
*/
_thread_run->wakeup_time.tv_sec = -1;
_thread_run->wakeup_time.tv_nsec = -1;
@@ -1042,7 +1045,7 @@ _thread_kern_sig_undefer(void)
if (_sigq_check_reqd != 0)
_thread_kern_sched(NULL);
- /*
+ /*
* Check for asynchronous cancellation before delivering any
* pending signals:
*/
@@ -1071,7 +1074,7 @@ dequeue_signals(void)
int num;
/*
- * Enter a loop to clear the pthread kernel pipe:
+ * Enter a loop to clear the pthread kernel pipe:
*/
while (((num = _thread_sys_read(_thread_kern_pipe[0], bufr,
sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) {
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
index ec6c0f6..f3649db 100644
--- a/lib/libpthread/thread/thr_mutex.c
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -406,13 +406,29 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_thread_init();
if (mutex == NULL)
- ret = EINVAL;
+ return (EINVAL);
/*
* If the mutex is statically initialized, perform the dynamic
* initialization:
*/
- else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
+ if ((*mutex == NULL) &&
+ ((ret = init_static(mutex)) != 0))
+ return (ret);
+
+ /* Reset the interrupted flag: */
+ _thread_run->interrupted = 0;
+
+ /*
+ * Enter a loop waiting to become the mutex owner. We need a
+ * loop in case the waiting thread is interrupted by a signal
+ * to execute a signal handler. It is not (currently) possible
+ * to remain in the waiting queue while running a handler.
+ * Instead, the thread is interrupted and backed out of the
+ * waiting queue prior to executing the signal handler.
+ */
+ while (((*mutex)->m_owner != _thread_run) && (ret == 0) &&
+ (_thread_run->interrupted == 0)) {
/*
* Defer signals to protect the scheduling queues from
* access by the signal handler:
@@ -432,9 +448,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
_MUTEX_INIT_LINK(*mutex);
}
- /* Reset the interrupted flag: */
- _thread_run->interrupted = 0;
-
/* Process according to mutex type: */
switch ((*mutex)->m_protocol) {
/* Default POSIX mutex: */
@@ -624,12 +637,12 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
* necessary:
*/
_thread_kern_sig_undefer();
-
- if (_thread_run->interrupted != 0 &&
- _thread_run->continuation != NULL)
- _thread_run->continuation((void *) _thread_run);
}
+ if (_thread_run->interrupted != 0 &&
+ _thread_run->continuation != NULL)
+ _thread_run->continuation((void *) _thread_run);
+
/* Return the completion status: */
return (ret);
}
@@ -1381,7 +1394,7 @@ _mutex_lock_backout(pthread_t pthread)
* access by the signal handler:
*/
_thread_kern_sig_defer();
- if (pthread->state == PS_MUTEX_WAIT) {
+ if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
mutex = pthread->data.mutex;
/* Lock the mutex structure: */
@@ -1390,7 +1403,7 @@ _mutex_lock_backout(pthread_t pthread)
mutex_queue_remove(mutex, pthread);
/* This thread is no longer waiting for the mutex: */
- mutex->m_owner->data.mutex = NULL;
+ pthread->data.mutex = NULL;
/* Unlock the mutex structure: */
_SPINUNLOCK(&mutex->lock);
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 5076510..e8fff12 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -327,6 +327,7 @@ struct pthread_cond {
pthread_mutex_t c_mutex;
void *c_data;
long c_flags;
+ int c_seqno;
/*
* Lock for accesses to this structure.
@@ -351,7 +352,7 @@ struct pthread_cond_attr {
*/
#define PTHREAD_COND_STATIC_INITIALIZER \
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
- 0, _SPINLOCK_INITIALIZER }
+ 0, 0, _SPINLOCK_INITIALIZER }
/*
* Semaphore definitions.
@@ -424,6 +425,9 @@ enum pthread_susp {
*/
#define PTHREAD_STACK_INITIAL 0x100000
+/* Size of the scheduler stack: */
+#define SCHED_STACK_SIZE PAGE_SIZE
+
/*
* Define the different priority ranges. All applications have thread
* priorities constrained within 0-31. The threads library raises the
@@ -574,13 +578,20 @@ union pthread_wait_data {
*/
typedef void (*thread_continuation_t) (void *);
+struct pthread_signal_frame;
+
struct pthread_state_data {
- int psd_interrupted;
+ struct pthread_signal_frame *psd_curframe;
sigset_t psd_sigmask;
- enum pthread_state psd_state;
- int psd_flags;
struct timespec psd_wakeup_time;
union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_longjmp_val;
+ int psd_sigmask_seqno;
+ int psd_signo;
+ int psd_sig_defer_count;
/* XXX - What about thread->timeout and/or thread->error? */
};
@@ -620,9 +631,6 @@ struct pthread_signal_frame {
*/
struct pthread_state_data saved_state;
- /* Beginning (bottom) of threads stack frame for this signal. */
- unsigned long stackp;
-
/*
* Threads return context; ctxtype identifies the type of context.
* For signal frame 0, these point to the context storage area
@@ -637,18 +645,10 @@ struct pthread_signal_frame {
} ctx;
thread_context_t ctxtype;
int longjmp_val;
-
- /* Threads "jump out of signal handler" destination frame. */
- int dst_frame;
-
- /*
- * Used to return back to the signal handling frame in case
- * the application tries to change contexts from the handler.
- */
- jmp_buf *sig_jb;
-
int signo; /* signal, arg 1 to sighandler */
int sig_has_args; /* use signal args if true */
+ ucontext_t uc;
+ siginfo_t siginfo;
};
/*
@@ -685,18 +685,20 @@ struct pthread {
struct pthread_attr attr;
/*
- * Used for tracking delivery of nested signal handlers.
- * Signal frame 0 is used for normal context (when no
- * signal handlers are active for the thread). Frame
- * 1 is used as the context for the first signal, and
- * frames 2 .. NSIG-1 are used when additional signals
- * arrive interrupting already active signal handlers.
+ * Threads return context; ctxtype identifies the type of context.
+ */
+ union {
+ jmp_buf jb;
+ sigjmp_buf sigjb;
+ ucontext_t uc;
+ } ctx;
+ thread_context_t ctxtype;
+ int longjmp_val;
+
+ /*
+ * Used for tracking delivery of signal handlers.
*/
- struct pthread_signal_frame *sigframes[NSIG];
- struct pthread_signal_frame sigframe0;
struct pthread_signal_frame *curframe;
- int sigframe_count;
- int sigframe_done;
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -716,6 +718,7 @@ struct pthread {
*/
sigset_t sigmask;
sigset_t sigpend;
+ int sigmask_seqno;
int check_pending;
/* Thread state: */
@@ -1078,7 +1081,11 @@ SCLASS int _thread_dfl_count[NSIG];
* Pending signals and mask for this process:
*/
SCLASS sigset_t _process_sigpending;
-SCLASS sigset_t _process_sigmask;
+SCLASS sigset_t _process_sigmask
+#ifdef GLOBAL_PTHREAD_PRIVATE
+= { {0, 0, 0, 0} }
+#endif
+;
/*
* Scheduling queues:
@@ -1222,7 +1229,6 @@ void _waitq_clearactive(void);
#endif
void _thread_exit(char *, int, char *);
void _thread_exit_cleanup(void);
-void _thread_exit_finish(void);
void _thread_fd_unlock(int, int);
void _thread_fd_unlock_debug(int, int, char *, int);
void _thread_fd_unlock_owned(pthread_t);
@@ -1232,7 +1238,7 @@ void _thread_dump_info(void);
void _thread_init(void);
void _thread_kern_sched(ucontext_t *);
void _thread_kern_scheduler(void);
-void _thread_kern_sched_frame(int frame);
+void _thread_kern_sched_frame(struct pthread_signal_frame *psf);
void _thread_kern_sched_sig(void);
void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno);
void _thread_kern_sched_state_unlock(enum pthread_state state,
@@ -1245,7 +1251,7 @@ void _thread_sig_check_pending(pthread_t pthread);
void _thread_sig_handle_pending(void);
void _thread_sig_send(pthread_t pthread, int sig);
void _thread_sig_wrapper(void);
-int _thread_sigframe_find(pthread_t pthread, void *stackp);
+void _thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
void _thread_start(void);
void _thread_seterrno(pthread_t, int);
int _thread_fd_table_init(int fd);
@@ -1262,6 +1268,7 @@ int _thread_sys_sigsuspend(const sigset_t *);
int _thread_sys_siginterrupt(int, int);
int _thread_sys_sigpause(int);
int _thread_sys_sigreturn(ucontext_t *);
+int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigstack *);
int _thread_sys_sigstack(const struct sigstack *, struct sigstack *);
int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *);
void _thread_sys_psignal(unsigned int, const char *);
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index f19582d..3bcd9c1 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -49,9 +49,7 @@ static void thread_sig_check_state(pthread_t pthread, int sig);
static pthread_t thread_sig_find(int sig);
static void thread_sig_handle_special(int sig);
static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp);
-static void thread_sigframe_add(pthread_t thread, int sig);
-static void thread_sigframe_leave(pthread_t thread, int frame);
-static void thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf);
+static void thread_sigframe_add(pthread_t thread, int sig, int has_args);
static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf);
/* #define DEBUG_SIGNAL */
@@ -72,21 +70,30 @@ static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *
void
_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
- pthread_t pthread;
- int current_frame;
+ pthread_t pthread, pthread_h;
+ void *stackp;
+ int in_sched = 0;
char c;
if (ucp == NULL)
PANIC("Thread signal handler received null context");
DBG_MSG("Got signal %d, current thread %p\n", sig, _thread_run);
+ if (_thread_kern_in_sched != 0)
+ in_sched = 1;
+ else {
+ stackp = (void *)GET_STACK_UC(ucp);
+ if ((stackp >= _thread_kern_sched_stack) &&
+ (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE))
+ in_sched = 1;
+ }
/* Check if an interval timer signal: */
if (sig == _SCHED_SIGNAL) {
/* Update the scheduling clock: */
gettimeofday((struct timeval *)&_sched_tod, NULL);
_sched_ticks++;
- if (_thread_kern_in_sched != 0) {
+ if (in_sched != 0) {
/*
* The scheduler is already running; ignore this
* signal.
@@ -108,13 +115,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/*
* Schedule the next thread. This function is not
* expected to return because it will do a longjmp
- * instead.
+ * instead.
*/
_thread_kern_sched(ucp);
/*
* This point should not be reached, so abort the
- * process:
+ * process:
*/
PANIC("Returned to signal function from scheduler");
}
@@ -124,8 +131,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* is accessing the scheduling queues or if there is a currently
* running thread that has deferred signals.
*/
- else if ((_thread_kern_in_sched != 0) ||
- (_thread_run->sig_defer_count > 0)) {
+ else if ((in_sched != 0) || (_thread_run->sig_defer_count > 0)) {
/* Cast the signal number to a character variable: */
c = sig;
@@ -176,10 +182,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* cannot be interrupted by other signals.
*/
else if (_thread_sigq[sig - 1].blocked == 0) {
- /* The signal is not blocked; handle the signal: */
- current_frame = _thread_run->sigframe_count;
-
/*
+ * The signal is not blocked; handle the signal.
+ *
* Ignore subsequent occurrences of this signal
* until the current signal is handled:
*/
@@ -204,6 +209,7 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
/* Handle special signals: */
thread_sig_handle_special(sig);
+ pthread_h = NULL;
if ((pthread = thread_sig_find(sig)) != NULL) {
DBG_MSG("Got signal %d, adding frame to thread %p\n",
sig, pthread);
@@ -221,9 +227,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
thread_sig_add(pthread, sig, /*has_args*/ 1);
/* Take a peek at the next ready to run thread: */
- pthread = PTHREAD_PRIOQ_FIRST();
+ pthread_h = PTHREAD_PRIOQ_FIRST();
DBG_MSG("Finished adding frame, head of prio list %p\n",
- pthread);
+ pthread_h);
}
else
DBG_MSG("No thread to handle signal %d\n", sig);
@@ -235,11 +241,9 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
* signal and the currently running thread is not in a
* signal handler.
*/
- if ((_thread_run->sigframe_count > current_frame) ||
- ((pthread != NULL) &&
- (pthread->active_priority > _thread_run->active_priority))) {
+ if ((pthread == _thread_run) || ((pthread_h != NULL) &&
+ (pthread_h->active_priority > _thread_run->active_priority))) {
/* Enter the kernel scheduler: */
- DBG_MSG("Entering scheduler from signal handler\n");
_thread_kern_sched(ucp);
}
}
@@ -253,17 +257,13 @@ _thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
static void
thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp)
{
- struct pthread_signal_frame *psf;
-
- psf = _thread_run->curframe;
-
- memcpy(&psf->ctx.uc, ucp, sizeof(*ucp));
+ memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp));
/* XXX - Save FP registers too? */
- FP_SAVE_UC(&psf->ctx.uc);
+ FP_SAVE_UC(&pthread->ctx.uc);
/* Mark the context saved as a ucontext: */
- psf->ctxtype = CTX_UC;
+ pthread->ctxtype = CTX_UC;
}
/*
@@ -278,10 +278,13 @@ thread_sig_find(int sig)
DBG_MSG("Looking for thread to handle signal %d\n", sig);
/* Check if the signal requires a dump of thread information: */
- if (sig == SIGINFO)
+ if (sig == SIGINFO) {
/* Dump thread information to file: */
_thread_dump_info();
+ /* Unblock this signal to allow further dumps: */
+ _thread_sigq[sig - 1].blocked = 0;
+ }
/* Check if an interval timer signal: */
else if (sig == _SCHED_SIGNAL) {
/*
@@ -326,7 +329,7 @@ thread_sig_find(int sig)
* A signal handler is not invoked for threads
* in sigwait. Clear the blocked and pending
* flags.
- */
+ */
_thread_sigq[sig - 1].blocked = 0;
_thread_sigq[sig - 1].pending = 0;
@@ -375,7 +378,7 @@ thread_sig_find(int sig)
signaled_thread == NULL) {
/*
* Enter a loop to look for other threads
- * capable of receiving the signal:
+ * capable of receiving the signal:
*/
TAILQ_FOREACH(pthread, &_thread_list, tle) {
if (!sigismember(&pthread->sigmask,
@@ -565,8 +568,7 @@ thread_sig_handle_special(int sig)
static void
thread_sig_add(pthread_t pthread, int sig, int has_args)
{
- int restart, frame;
- int block_signals = 0;
+ int restart;
int suppress_handler = 0;
restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
@@ -657,8 +659,11 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* States which cannot be interrupted but still require the
* signal handler to run:
*/
- case PS_COND_WAIT:
case PS_JOIN:
+ /* Only set the interrupted flag for PS_JOIN: */
+ pthread->interrupted = 1;
+ /* FALLTHROUGH */
+ case PS_COND_WAIT:
case PS_MUTEX_WAIT:
/*
* Remove the thread from the wait queue. It will
@@ -687,14 +692,6 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
* the actual handler.
*/
PTHREAD_WAITQ_REMOVE(pthread);
- /*
- * To ensure the thread is removed from the fd and file
- * queues before any other signal interrupts it, set the
- * signal mask to block all signals. As soon as the thread
- * is removed from the queue the signal mask will be
- * restored.
- */
- block_signals = 1;
break;
/*
@@ -736,22 +733,15 @@ thread_sig_add(pthread_t pthread, int sig, int has_args)
}
if (suppress_handler == 0) {
+ /* Setup a signal frame and save the current threads state: */
+ thread_sigframe_add(pthread, sig, has_args);
+
/*
- * Save the current state of the thread and add a
- * new signal frame.
+ * Signals are deferred until just before the threads
+ * signal handler is invoked:
*/
- frame = pthread->sigframe_count;
- thread_sigframe_save(pthread, pthread->curframe);
- thread_sigframe_add(pthread, sig);
- pthread->sigframes[frame + 1]->sig_has_args = has_args;
- SIGSETOR(pthread->sigmask, _thread_sigact[sig - 1].sa_mask);
- if (block_signals != 0) {
- /* Save the signal mask and block all signals: */
- pthread->sigframes[frame + 1]->saved_state.psd_sigmask =
- pthread->sigmask;
- sigfillset(&pthread->sigmask);
- }
-
+ pthread->sig_defer_count = 1;
+
/* Make sure the thread is runnable: */
if (pthread->state != PS_RUNNING)
PTHREAD_SET_STATE(pthread, PS_RUNNING);
@@ -925,19 +915,16 @@ _thread_sig_wrapper(void)
{
void (*sigfunc)(int, siginfo_t *, void *);
struct pthread_signal_frame *psf;
- pthread_t thread;
- int dead = 0;
- int i, sig, has_args;
- int frame, dst_frame;
+ pthread_t thread;
thread = _thread_run;
/* Get the current frame and state: */
- frame = thread->sigframe_count;
- PTHREAD_ASSERT(frame > 0, "Invalid signal frame in signal handler");
psf = thread->curframe;
+ thread->curframe = NULL;
+ PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
- /* Check the threads previous state: */
+ /* Check the threads previous state: */
if (psf->saved_state.psd_state != PS_RUNNING) {
/*
* Do a little cleanup handling for those threads in
@@ -950,15 +937,26 @@ _thread_sig_wrapper(void)
case PS_FDLW_WAIT:
_fd_lock_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
break;
case PS_FILE_WAIT:
_flockfile_backout(thread);
psf->saved_state.psd_state = PS_RUNNING;
- /* Reenable signals: */
- thread->sigmask = psf->saved_state.psd_sigmask;
+ break;
+
+ case PS_COND_WAIT:
+ _cond_wait_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_JOIN:
+ _join_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
+ break;
+
+ case PS_MUTEX_WAIT:
+ _mutex_lock_backout(thread);
+ psf->saved_state.psd_state = PS_RUNNING;
break;
default:
@@ -966,11 +964,20 @@ _thread_sig_wrapper(void)
}
}
+ /* Unblock the signal in case we don't return from the handler: */
+ _thread_sigq[psf->signo - 1].blocked = 0;
+
+ /*
+ * Lower the priority before calling the handler in case
+ * it never returns (longjmps back):
+ */
+ thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
+
/*
- * Unless the thread exits or longjmps out of the signal handler,
- * return to the previous frame:
+ * Reenable interruptions without checking for the need to
+ * context switch:
*/
- dst_frame = frame - 1;
+ thread->sig_defer_count = 0;
/*
* Check that a custom handler is installed and if the signal
@@ -979,141 +986,45 @@ _thread_sig_wrapper(void)
sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction;
if (((__sighandler_t *)sigfunc != SIG_DFL) &&
((__sighandler_t *)sigfunc != SIG_IGN)) {
+ DBG_MSG("_thread_sig_wrapper: Calling signal handler for "
+ "thread 0x%p\n", thread);
/*
- * The signal jump buffer is allocated off the stack.
- * If the signal handler tries to [_][sig]longjmp() or
- * setcontext(), our wrapped versions of these routines
- * will copy the user supplied jump buffer or context
- * to the destination signal frame, set the destination
- * signal frame in psf->dst_frame, and _longjmp() back
- * to here.
- */
- jmp_buf jb;
-
- /*
- * Set up the context for abnormal returns out of signal
- * handlers.
+ * Dispatch the signal via the custom signal
+ * handler:
*/
- psf->sig_jb = &jb;
- if (_setjmp(jb) == 0) {
- DBG_MSG("_thread_sig_wrapper: Entering frame %d, "
- "stack 0x%lx\n", frame, GET_STACK_JB(jb));
- /*
- * Invalidate the destination frame before calling
- * the signal handler.
- */
- psf->dst_frame = -1;
-
- /*
- * Dispatch the signal via the custom signal
- * handler:
- */
- if (psf->sig_has_args == 0)
- (*(sigfunc))(psf->signo, NULL, NULL);
- else if ((_thread_sigact[psf->signo - 1].sa_flags &
- SA_SIGINFO) != 0)
- (*(sigfunc))(psf->signo,
- &_thread_sigq[psf->signo - 1].siginfo,
- &_thread_sigq[psf->signo - 1].uc);
- else
- (*(sigfunc))(psf->signo,
- (siginfo_t *)_thread_sigq[psf->signo - 1].siginfo.si_code,
- &_thread_sigq[psf->signo - 1].uc);
- }
- else {
- /*
- * The return from _setjmp() should only be non-zero
- * when the signal handler wants to xxxlongjmp() or
- * setcontext() to a different context, or if the
- * thread has exited (via pthread_exit).
- */
- /*
- * Grab a copy of the destination frame before it
- * gets clobbered after unwinding.
- */
- dst_frame = psf->dst_frame;
- DBG_MSG("Abnormal exit from handler for signal %d, "
- "frame %d\n", psf->signo, frame);
-
- /* Has the thread exited? */
- if ((dead = thread->flags & PTHREAD_EXITING) != 0)
- /* When exiting, unwind to frame 0. */
- dst_frame = 0;
- else if ((dst_frame < 0) || (dst_frame > frame))
- PANIC("Attempt to unwind to invalid "
- "signal frame");
-
- /* Unwind to the target frame: */
- for (i = frame; i > dst_frame; i--) {
- DBG_MSG("Leaving frame %d, signal %d\n", i,
- thread->sigframes[i]->signo);
- /* Leave the current signal frame: */
- thread_sigframe_leave(thread, i);
-
- /*
- * Save whatever is needed out of the state
- * data; as soon as the frame count is
- * is decremented, another signal can arrive
- * and corrupt this view of the state data.
- */
- sig = thread->sigframes[i]->signo;
- has_args = thread->sigframes[i]->sig_has_args;
-
- /*
- * We're done with this signal frame:
- */
- thread->curframe = thread->sigframes[i - 1];
- thread->sigframe_count = i - 1;
-
- /*
- * Only unblock the signal if it was a
- * process signal as opposed to a signal
- * generated by pthread_kill().
- */
- if (has_args != 0)
- _thread_sigq[sig - 1].blocked = 0;
- }
- }
+ if (psf->sig_has_args == 0)
+ (*(sigfunc))(psf->signo, NULL, NULL);
+ else if ((_thread_sigact[psf->signo - 1].sa_flags &
+ SA_SIGINFO) != 0)
+ (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc);
+ else
+ (*(sigfunc))(psf->signo,
+ (siginfo_t *)psf->siginfo.si_code, &psf->uc);
}
-
/*
- * Call the kernel scheduler to schedule the next
- * thread.
+ * Call the kernel scheduler to safely restore the frame and
+ * schedule the next thread:
*/
- if (dead == 0) {
- /* Restore the threads state: */
- thread_sigframe_restore(thread, thread->sigframes[dst_frame]);
- _thread_kern_sched_frame(dst_frame);
- }
- else {
- PTHREAD_ASSERT(dst_frame == 0,
- "Invalid signal frame for dead thread");
-
- /* Perform any necessary cleanup before exiting. */
- thread_sigframe_leave(thread, 0);
-
- /* This should never return: */
- _thread_exit_finish();
- PANIC("Return from _thread_exit_finish in signal wrapper");
- }
+ _thread_kern_sched_frame(psf);
}
static void
-thread_sigframe_add(pthread_t thread, int sig)
+thread_sigframe_add(pthread_t thread, int sig, int has_args)
{
+ struct pthread_signal_frame *psf = NULL;
unsigned long stackp = 0;
/* Get the top of the threads stack: */
- switch (thread->curframe->ctxtype) {
+ switch (thread->ctxtype) {
case CTX_JB:
case CTX_JB_NOSIG:
- stackp = GET_STACK_JB(thread->curframe->ctx.jb);
+ stackp = GET_STACK_JB(thread->ctx.jb);
break;
case CTX_SJB:
- stackp = GET_STACK_SJB(thread->curframe->ctx.sigjb);
+ stackp = GET_STACK_SJB(thread->ctx.sigjb);
break;
case CTX_UC:
- stackp = GET_STACK_UC(&thread->curframe->ctx.uc);
+ stackp = GET_STACK_UC(&thread->ctx.uc);
break;
default:
PANIC("Invalid thread context type");
@@ -1130,138 +1041,76 @@ thread_sigframe_add(pthread_t thread, int sig)
/* Allocate room on top of the stack for a new signal frame: */
stackp -= sizeof(struct pthread_signal_frame);
- /* Set up the new frame: */
- thread->sigframe_count++;
- thread->sigframes[thread->sigframe_count] =
- (struct pthread_signal_frame *) stackp;
- thread->curframe = thread->sigframes[thread->sigframe_count];
- thread->curframe->stackp = stackp;
- thread->curframe->ctxtype = CTX_JB_NOSIG;
- thread->curframe->longjmp_val = 1;
- thread->curframe->signo = sig;
+ psf = (struct pthread_signal_frame *) stackp;
- /*
- * Set up the context:
- */
- _setjmp(thread->curframe->ctx.jb);
- SET_STACK_JB(thread->curframe->ctx.jb, stackp);
- SET_RETURN_ADDR_JB(thread->curframe->ctx.jb, _thread_sig_wrapper);
-}
+ /* Save the current context in the signal frame: */
+ thread_sigframe_save(thread, psf);
-/*
- * Locate the signal frame from the specified stack pointer.
- */
-int
-_thread_sigframe_find(pthread_t pthread, void *stackp)
-{
- int frame;
+ /* Set handler specific information: */
+ psf->sig_has_args = has_args;
+ psf->signo = sig;
+ if (has_args) {
+ /* Copy the signal handler arguments to the signal frame: */
+ memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
+ sizeof(psf->uc));
+ memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
+ sizeof(psf->siginfo));
+ }
+ /* Set up the new frame: */
+ thread->curframe = psf;
+ thread->ctxtype = CTX_JB_NOSIG;
+ thread->longjmp_val = 1;
+ thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
+ PTHREAD_FLAGS_IN_SYNCQ;
/*
- * Find the destination of the target frame based on the
- * given stack pointer.
+ * Set up the context:
*/
- for (frame = pthread->sigframe_count; frame >= 0; frame--) {
- if (stackp < (void *)pthread->sigframes[frame]->stackp)
- break;
- }
- return (frame);
+ stackp += sizeof(double);
+ _setjmp(thread->ctx.jb);
+ SET_STACK_JB(thread->ctx.jb, stackp);
+ SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
}
-
+
void
-thread_sigframe_leave(pthread_t thread, int frame)
+_thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
{
- struct pthread_state_data *psd;
-
- psd = &thread->sigframes[frame]->saved_state;
-
+ thread->ctxtype = psf->ctxtype;
+ memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc));
/*
- * Perform any necessary cleanup for this signal frame:
+ * Only restore the signal mask if it hasn't been changed
+ * by the application during invocation of the signal handler:
*/
- switch (psd->psd_state) {
- case PS_DEAD:
- case PS_DEADLOCK:
- case PS_RUNNING:
- case PS_SIGTHREAD:
- case PS_STATE_MAX:
- case PS_SUSPENDED:
- break;
-
- /*
- * Threads in the following states need to be removed
- * from queues.
- */
- case PS_COND_WAIT:
- _cond_wait_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- _fd_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FILE_WAIT:
- _flockfile_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_JOIN:
- _join_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_MUTEX_WAIT:
- _mutex_lock_backout(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0)
- PTHREAD_WAITQ_REMOVE(thread);
- break;
-
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- case PS_POLL_WAIT:
- case PS_SELECT_WAIT:
- case PS_SIGSUSPEND:
- case PS_SIGWAIT:
- case PS_SLEEP_WAIT:
- case PS_SPINBLOCK:
- case PS_WAIT_WAIT:
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WAITQ) != 0) {
- PTHREAD_WAITQ_REMOVE(thread);
- if ((psd->psd_flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
- PTHREAD_WORKQ_REMOVE(thread);
- }
- break;
- }
-}
-
-static void
-thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf)
-{
- thread->interrupted = psf->saved_state.psd_interrupted;
- thread->sigmask = psf->saved_state.psd_sigmask;
- thread->state = psf->saved_state.psd_state;
- thread->flags = psf->saved_state.psd_flags;
+ if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
+ thread->sigmask = psf->saved_state.psd_sigmask;
+ thread->curframe = psf->saved_state.psd_curframe;
thread->wakeup_time = psf->saved_state.psd_wakeup_time;
thread->data = psf->saved_state.psd_wait_data;
+ thread->state = psf->saved_state.psd_state;
+ thread->flags = psf->saved_state.psd_flags;
+ thread->interrupted = psf->saved_state.psd_interrupted;
+ thread->longjmp_val = psf->saved_state.psd_longjmp_val;
+ thread->signo = psf->saved_state.psd_signo;
+ thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
}
static void
thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf)
{
- psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->ctxtype = thread->ctxtype;
+ memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc));
psf->saved_state.psd_sigmask = thread->sigmask;
- psf->saved_state.psd_state = thread->state;
- psf->saved_state.psd_flags = thread->flags;
- thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
- PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ |
- PTHREAD_FLAGS_IN_JOINQ;
+ psf->saved_state.psd_curframe = thread->curframe;
psf->saved_state.psd_wakeup_time = thread->wakeup_time;
psf->saved_state.psd_wait_data = thread->data;
+ psf->saved_state.psd_state = thread->state;
+ psf->saved_state.psd_flags = thread->flags &
+ (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
+ psf->saved_state.psd_interrupted = thread->interrupted;
+ psf->saved_state.psd_longjmp_val = thread->longjmp_val;
+ psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
+ psf->saved_state.psd_signo = thread->signo;
+ psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
}
#endif
diff --git a/lib/libpthread/thread/thr_sigaction.c b/lib/libpthread/thread/thr_sigaction.c
index e78f329..4d13819 100644
--- a/lib/libpthread/thread/thr_sigaction.c
+++ b/lib/libpthread/thread/thr_sigaction.c
@@ -80,7 +80,7 @@ _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
* handler arguments.
*/
sigfillset(&gact.sa_mask);
- gact.sa_flags = SA_SIGINFO;
+ gact.sa_flags = SA_SIGINFO | SA_ONSTACK;
/*
* Check if the signal handler is being set to
diff --git a/lib/libpthread/thread/thr_sigmask.c b/lib/libpthread/thread/thr_sigmask.c
index bdb0b43..53d0774 100644
--- a/lib/libpthread/thread/thr_sigmask.c
+++ b/lib/libpthread/thread/thr_sigmask.c
@@ -81,6 +81,9 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
break;
}
+ /* Increment the sequence number: */
+ _thread_run->sigmask_seqno++;
+
/*
* Check if there are pending signals for the running
* thread or process that aren't blocked:
OpenPOWER on IntegriCloud