summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libkse/sys/thr_error.c1
-rw-r--r--lib/libkse/thread/thr_cancel.c20
-rw-r--r--lib/libkse/thread/thr_clean.c4
-rw-r--r--lib/libkse/thread/thr_concurrency.c7
-rw-r--r--lib/libkse/thread/thr_cond.c220
-rw-r--r--lib/libkse/thread/thr_create.c4
-rw-r--r--lib/libkse/thread/thr_fork.c24
-rw-r--r--lib/libkse/thread/thr_init.c1
-rw-r--r--lib/libkse/thread/thr_kern.c55
-rw-r--r--lib/libkse/thread/thr_mutex.c92
-rw-r--r--lib/libkse/thread/thr_once.c6
-rw-r--r--lib/libkse/thread/thr_private.h24
-rw-r--r--lib/libkse/thread/thr_sem.c8
-rw-r--r--lib/libkse/thread/thr_sig.c275
-rw-r--r--lib/libkse/thread/thr_sigsuspend.c1
-rw-r--r--lib/libkse/thread/thr_spinlock.c16
-rw-r--r--lib/libpthread/pthread.map1
-rw-r--r--lib/libpthread/sys/thr_error.c1
-rw-r--r--lib/libpthread/thread/thr_cancel.c20
-rw-r--r--lib/libpthread/thread/thr_clean.c4
-rw-r--r--lib/libpthread/thread/thr_concurrency.c7
-rw-r--r--lib/libpthread/thread/thr_cond.c220
-rw-r--r--lib/libpthread/thread/thr_create.c4
-rw-r--r--lib/libpthread/thread/thr_fork.c24
-rw-r--r--lib/libpthread/thread/thr_init.c1
-rw-r--r--lib/libpthread/thread/thr_kern.c55
-rw-r--r--lib/libpthread/thread/thr_mutex.c92
-rw-r--r--lib/libpthread/thread/thr_once.c6
-rw-r--r--lib/libpthread/thread/thr_private.h24
-rw-r--r--lib/libpthread/thread/thr_sem.c8
-rw-r--r--lib/libpthread/thread/thr_sig.c275
-rw-r--r--lib/libpthread/thread/thr_sigsuspend.c1
-rw-r--r--lib/libpthread/thread/thr_spinlock.c16
33 files changed, 823 insertions, 694 deletions
diff --git a/lib/libkse/sys/thr_error.c b/lib/libkse/sys/thr_error.c
index 6f19f93..72e1927 100644
--- a/lib/libkse/sys/thr_error.c
+++ b/lib/libkse/sys/thr_error.c
@@ -37,6 +37,7 @@
#include "libc_private.h"
#include "thr_private.h"
+#undef errno
extern int errno;
int *
diff --git a/lib/libkse/thread/thr_cancel.c b/lib/libkse/thread/thr_cancel.c
index 8cd7acc..a6a32b8 100644
--- a/lib/libkse/thread/thr_cancel.c
+++ b/lib/libkse/thread/thr_cancel.c
@@ -14,18 +14,26 @@ __weak_reference(_pthread_testcancel, pthread_testcancel);
static inline int
checkcancel(struct pthread *curthread)
{
- if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
- ((curthread->cancelflags & THR_CANCELLING) != 0)) {
+ if ((curthread->cancelflags & THR_CANCELLING) != 0) {
/*
* It is possible for this thread to be swapped out
* while performing cancellation; do not allow it
* to be cancelled again.
*/
- curthread->cancelflags &= ~THR_CANCELLING;
- return (1);
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ /*
+ * This may happen once, but after this, it
+ * shouldn't happen again.
+ */
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (0);
+ }
+ if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (1);
+ }
}
- else
- return (0);
+ return (0);
}
static inline void
diff --git a/lib/libkse/thread/thr_clean.c b/lib/libkse/thread/thr_clean.c
index a8cedb4..1da8a6b 100644
--- a/lib/libkse/thread/thr_clean.c
+++ b/lib/libkse/thread/thr_clean.c
@@ -50,6 +50,7 @@ _pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
malloc(sizeof(struct pthread_cleanup))) != NULL) {
new->routine = routine;
new->routine_arg = routine_arg;
+ new->onstack = 0;
new->next = curthread->cleanup;
curthread->cleanup = new;
@@ -67,6 +68,7 @@ _pthread_cleanup_pop(int execute)
if (execute) {
old->routine(old->routine_arg);
}
- free(old);
+ if (old->onstack == 0)
+ free(old);
}
}
diff --git a/lib/libkse/thread/thr_concurrency.c b/lib/libkse/thread/thr_concurrency.c
index 59e8550..daea56c 100644
--- a/lib/libkse/thread/thr_concurrency.c
+++ b/lib/libkse/thread/thr_concurrency.c
@@ -84,6 +84,13 @@ _thr_setconcurrency(int new_level)
int i;
int ret;
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
+ return (EAGAIN);
+
ret = 0;
curthread = _get_curthread();
/* Race condition, but so what. */
diff --git a/lib/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c
index fd7b6d9..cd719d4 100644
--- a/lib/libkse/thread/thr_cond.c
+++ b/lib/libkse/thread/thr_cond.c
@@ -47,6 +47,9 @@
static inline struct pthread *cond_queue_deq(pthread_cond_t);
static inline void cond_queue_remove(pthread_cond_t, pthread_t);
static inline void cond_queue_enq(pthread_cond_t, pthread_t);
+static void cond_wait_backout(void *);
+static inline void check_continuation(struct pthread *,
+ struct pthread_cond *, pthread_mutex_t *);
/*
* Double underscore versions are cancellation points. Single underscore
@@ -171,8 +174,7 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
struct pthread *curthread = _get_curthread();
int rval = 0;
int done = 0;
- int interrupted = 0;
- int unlock_mutex = 1;
+ int mutex_locked = 1;
int seqno;
if (cond == NULL)
@@ -198,10 +200,11 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* and backed out of the waiting queue prior to executing the
* signal handler.
*/
- do {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
/*
* If the condvar was statically allocated, properly
* initialize the tail queue.
@@ -217,9 +220,6 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
case COND_TYPE_FAST:
if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
((*cond)->c_mutex != *mutex))) {
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return invalid argument error: */
rval = EINVAL;
} else {
@@ -233,15 +233,11 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
*/
cond_queue_enq(*cond, curthread);
- /* Remember the mutex and sequence number: */
- (*cond)->c_mutex = *mutex;
- seqno = (*cond)->c_seqno;
-
/* Wait forever: */
curthread->wakeup_time.tv_sec = -1;
/* Unlock the mutex: */
- if ((unlock_mutex != 0) &&
+ if (mutex_locked &&
((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
@@ -249,22 +245,18 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* variable queue:
*/
cond_queue_remove(*cond, curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
}
else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
/*
* Don't unlock the mutex the next
* time through the loop (if the
* thread has to be requeued after
* handling a signal).
*/
- unlock_mutex = 0;
+ mutex_locked = 0;
/*
* This thread is active and is in a
@@ -277,6 +269,7 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Remember the CV: */
curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
THR_SCHED_UNLOCK(curthread, curthread);
/* Unlock the CV structure: */
@@ -286,8 +279,6 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.cond = NULL;
-
/*
* XXX - This really isn't a good check
* since there can be more than one
@@ -299,41 +290,39 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* should be sent "as soon as possible".
*/
done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_SYNCQ(curthread)) {
+ if (done && !THR_IN_CONDQ(curthread)) {
/*
- * Lock the condition variable
- * while removing the thread.
+ * The thread is dequeued, so
+ * it is safe to clear these.
*/
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ done = (seqno != (*cond)->c_seqno);
+ if (THR_IN_CONDQ(curthread)) {
cond_queue_remove(*cond,
curthread);
/* Check for no more waiters: */
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
-
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
- }
-
- /*
- * Save the interrupted flag; locking
- * the mutex may destroy it.
- */
- interrupted = curthread->interrupted;
-
- /*
- * Note that even though this thread may
- * have been canceled, POSIX requires
- * that the mutex be reaquired prior to
- * cancellation.
- */
- if (done || interrupted) {
- rval = _mutex_cv_lock(mutex);
- unlock_mutex = 1;
}
}
}
@@ -341,18 +330,21 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Trap invalid condition variable types: */
default:
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return an invalid argument error: */
rval = EINVAL;
break;
}
- if ((interrupted != 0) && (curthread->continuation != NULL))
- curthread->continuation((void *) curthread);
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
} while ((done == 0) && (rval == 0));
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
/* Return the completion status: */
return (rval);
}
@@ -378,8 +370,7 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
struct pthread *curthread = _get_curthread();
int rval = 0;
int done = 0;
- int interrupted = 0;
- int unlock_mutex = 1;
+ int mutex_locked = 1;
int seqno;
THR_ASSERT(curthread->locklevel == 0,
@@ -407,10 +398,11 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* and backed out of the waiting queue prior to executing the
* signal handler.
*/
- do {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
/*
* If the condvar was statically allocated, properly
* initialize the tail queue.
@@ -428,9 +420,6 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
((*cond)->c_mutex != *mutex))) {
/* Return invalid argument error: */
rval = EINVAL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
} else {
/* Set the wakeup time: */
curthread->wakeup_time.tv_sec = abstime->tv_sec;
@@ -447,12 +436,8 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
cond_queue_enq(*cond, curthread);
- /* Remember the mutex and sequence number: */
- (*cond)->c_mutex = *mutex;
- seqno = (*cond)->c_seqno;
-
/* Unlock the mutex: */
- if ((unlock_mutex != 0) &&
+ if (mutex_locked &&
((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex; remove the
@@ -460,21 +445,17 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* variable queue:
*/
cond_queue_remove(*cond, curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
} else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
/*
* Don't unlock the mutex the next
* time through the loop (if the
* thread has to be requeued after
* handling a signal).
*/
- unlock_mutex = 0;
+ mutex_locked = 0;
/*
* This thread is active and is in a
@@ -487,6 +468,7 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Remember the CV: */
curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
THR_SCHED_UNLOCK(curthread, curthread);
/* Unlock the CV structure: */
@@ -496,8 +478,6 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.cond = NULL;
-
/*
* XXX - This really isn't a good check
* since there can be more than one
@@ -509,38 +489,45 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* should be sent "as soon as possible".
*/
done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_CONDQ(curthread)) {
+ if (done && !THR_IN_CONDQ(curthread)) {
/*
- * Lock the condition variable
- * while removing the thread.
+ * The thread is dequeued, so
+ * it is safe to clear these.
*/
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
cond_queue_remove(*cond,
curthread);
/* Check for no more waiters: */
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
-
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
}
- /*
- * Save the interrupted flag; locking
- * the mutex may destroy it.
- */
- interrupted = curthread->interrupted;
if (curthread->timeout != 0) {
/* The wait timedout. */
rval = ETIMEDOUT;
- (void)_mutex_cv_lock(mutex);
- } else if (interrupted || done) {
- rval = _mutex_cv_lock(mutex);
- unlock_mutex = 1;
}
}
}
@@ -548,18 +535,21 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Trap invalid condition variable types: */
default:
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return an invalid argument error: */
rval = EINVAL;
break;
}
- if ((interrupted != 0) && (curthread->continuation != NULL))
- curthread->continuation((void *)curthread);
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
} while ((done == 0) && (rval == 0));
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
/* Return the completion status: */
return (rval);
}
@@ -615,6 +605,7 @@ _pthread_cond_signal(pthread_cond_t * cond)
!= NULL) {
THR_SCHED_LOCK(curthread, pthread);
cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
if ((pthread->kseg == curthread->kseg) &&
(pthread->active_priority >
curthread->active_priority))
@@ -681,6 +672,7 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
!= NULL) {
THR_SCHED_LOCK(curthread, pthread);
cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
if ((pthread->kseg == curthread->kseg) &&
(pthread->active_priority >
curthread->active_priority))
@@ -712,9 +704,31 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
-void
-_cond_wait_backout(struct pthread *curthread)
+static inline void
+check_continuation(struct pthread *curthread, struct pthread_cond *cond,
+ pthread_mutex_t *mutex)
+{
+ if ((curthread->interrupted != 0) &&
+ (curthread->continuation != NULL)) {
+ if (cond != NULL)
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ /*
+ * Note that even though this thread may have been
+ * canceled, POSIX requires that the mutex be
+ * reaquired prior to cancellation.
+ */
+ if (mutex != NULL)
+ _mutex_cv_lock(mutex);
+ curthread->continuation((void *) curthread);
+ PANIC("continuation returned in pthread_cond_wait.\n");
+ }
+}
+
+static void
+cond_wait_backout(void *arg)
{
+ struct pthread *curthread = (struct pthread *)arg;
pthread_cond_t cond;
cond = curthread->data.cond;
@@ -740,6 +754,8 @@ _cond_wait_backout(struct pthread *curthread)
/* Unlock the condition variable structure: */
THR_LOCK_RELEASE(curthread, &cond->c_lock);
}
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
}
/*
diff --git a/lib/libkse/thread/thr_create.c b/lib/libkse/thread/thr_create.c
index 03f467b..08b2c47 100644
--- a/lib/libkse/thread/thr_create.c
+++ b/lib/libkse/thread/thr_create.c
@@ -171,9 +171,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* No thread is wanting to join to this one: */
new_thread->joiner = NULL;
- /* Initialize the signal frame: */
- new_thread->curframe = NULL;
-
/*
* Initialize the machine context.
* Enter a critical region to get consistent context.
@@ -235,6 +232,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->cleanup = NULL;
new_thread->flags = 0;
new_thread->tlflags = 0;
+ new_thread->sigbackout = NULL;
new_thread->continuation = NULL;
new_thread->wakeup_time.tv_sec = -1;
new_thread->lock_switch = 0;
diff --git a/lib/libkse/thread/thr_fork.c b/lib/libkse/thread/thr_fork.c
index 401aae9..fdbfd86 100644
--- a/lib/libkse/thread/thr_fork.c
+++ b/lib/libkse/thread/thr_fork.c
@@ -43,12 +43,6 @@
#include "libc_private.h"
#include "thr_private.h"
-/*
- * For a while, allow libpthread to work with a libc that doesn't
- * export the malloc lock.
- */
-#pragma weak __malloc_lock
-
__weak_reference(_fork, fork);
pid_t
@@ -60,11 +54,21 @@ _fork(void)
pid_t ret;
int errsave;
- if (!_kse_isthreaded())
- return (__sys_fork());
-
curthread = _get_curthread();
+ if (!_kse_isthreaded()) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ ret = __sys_fork();
+ if (ret == 0)
+ /* Child */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ else
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (ret);
+ }
+
/*
* Masks all signals until we reach a safe point in
* _kse_single_thread, and the signal masks will be
@@ -86,7 +90,7 @@ _fork(void)
}
/* Fork a new process: */
- if ((_kse_isthreaded() != 0) && (__malloc_lock != NULL)) {
+ if (_kse_isthreaded() != 0) {
_spinlock(__malloc_lock);
}
if ((ret = __sys_fork()) == 0) {
diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c
index 719195f..6d41087 100644
--- a/lib/libkse/thread/thr_init.c
+++ b/lib/libkse/thread/thr_init.c
@@ -391,6 +391,7 @@ init_main_thread(struct pthread *thread)
thread->specific = NULL;
thread->cleanup = NULL;
thread->flags = 0;
+ thread->sigbackout = NULL;
thread->continuation = NULL;
thread->state = PS_RUNNING;
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index 5d7fabb..aec2541 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
#include "thr_private.h"
#include "libc_private.h"
-/*#define DEBUG_THREAD_KERN */
+/* #define DEBUG_THREAD_KERN */
#ifdef DEBUG_THREAD_KERN
#define DBG_MSG stdout_debug
#else
@@ -165,8 +165,7 @@ static struct kse_mailbox *kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread);
static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
-static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf);
+static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp);
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread);
static void thr_destroy(struct pthread *curthread, struct pthread *thread);
@@ -352,6 +351,9 @@ _kse_single_thread(struct pthread *curthread)
curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ /* After a fork(), there child should have no pending signals. */
+ sigemptyset(&curthread->sigpend);
+
/*
* Restore signal mask early, so any memory problems could
* dump core.
@@ -615,13 +617,12 @@ _thr_sched_switch(struct pthread *curthread)
void
_thr_sched_switch_unlocked(struct pthread *curthread)
{
- struct pthread_sigframe psf;
struct kse *curkse;
volatile int resume_once = 0;
ucontext_t *uc;
/* We're in the scheduler, 5 by 5: */
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->need_switchout = 1; /* The thread yielded on its own. */
curthread->critical_yield = 0; /* No need to yield anymore. */
@@ -629,14 +630,6 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/* Thread can unlock the scheduler lock. */
curthread->lock_switch = 1;
- /*
- * The signal frame is allocated off the stack because
- * a thread can be interrupted by other signals while
- * it is running down pending signals.
- */
- psf.psf_valid = 0;
- curthread->curframe = &psf;
-
if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
kse_sched_single(&curkse->k_kcb->kcb_kmbx);
else {
@@ -658,18 +651,11 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
}
/*
- * It is ugly we must increase critical count, because we
- * have a frame saved, we must backout state in psf
- * before we can process signals.
- */
- curthread->critical_count += psf.psf_valid;
-
- /*
* Unlock the scheduling queue and leave the
* critical region.
*/
/* Don't trust this after a switch! */
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->lock_switch = 0;
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
@@ -678,16 +664,14 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/*
* This thread is being resumed; check for cancellations.
*/
- if ((psf.psf_valid ||
- ((curthread->check_pending || THR_NEED_ASYNC_CANCEL(curthread))
- && !THR_IN_CRITICAL(curthread)))) {
+ if (THR_NEED_ASYNC_CANCEL(curthread) && !THR_IN_CRITICAL(curthread)) {
uc = alloca(sizeof(ucontext_t));
resume_once = 0;
THR_GETCONTEXT(uc);
if (resume_once == 0) {
resume_once = 1;
curthread->check_pending = 0;
- thr_resume_check(curthread, uc, &psf);
+ thr_resume_check(curthread, uc);
}
}
THR_ACTIVATE_LAST_LOCK(curthread);
@@ -888,9 +872,6 @@ kse_sched_single(struct kse_mailbox *kmbx)
}
}
- /* Remove the frame reference. */
- curthread->curframe = NULL;
-
if (curthread->lock_switch == 0) {
/* Unlock the scheduling queue. */
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
@@ -925,7 +906,6 @@ kse_sched_multi(struct kse_mailbox *kmbx)
{
struct kse *curkse;
struct pthread *curthread, *td_wait;
- struct pthread_sigframe *curframe;
int ret;
curkse = (struct kse *)kmbx->km_udata;
@@ -980,6 +960,8 @@ kse_sched_multi(struct kse_mailbox *kmbx)
* will be cleared.
*/
curthread->blocked = 1;
+ DBG_MSG("Running thread %p is now blocked in kernel.\n",
+ curthread);
}
/* Check for any unblocked threads in the kernel. */
@@ -1085,10 +1067,6 @@ kse_sched_multi(struct kse_mailbox *kmbx)
/* Mark the thread active. */
curthread->active = 1;
- /* Remove the frame reference. */
- curframe = curthread->curframe;
- curthread->curframe = NULL;
-
/*
* The thread's current signal frame will only be NULL if it
* is being resumed after being blocked in the kernel. In
@@ -1096,7 +1074,7 @@ kse_sched_multi(struct kse_mailbox *kmbx)
* signals or needs a cancellation check, we need to add a
* signal frame to the thread's context.
*/
- if ((curframe == NULL) && (curthread->state == PS_RUNNING) &&
+ if (curthread->lock_switch == 0 && curthread->state == PS_RUNNING &&
(curthread->check_pending != 0 ||
THR_NEED_ASYNC_CANCEL(curthread)) &&
!THR_IN_CRITICAL(curthread)) {
@@ -1136,10 +1114,10 @@ thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
DBG_MSG(">>> sig wrapper\n");
if (curthread->lock_switch)
PANIC("thr_resume_wrapper, lock_switch != 0\n");
- thr_resume_check(curthread, ucp, NULL);
+ thr_resume_check(curthread, ucp);
errno = err_save;
_kse_critical_enter();
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->tcb->tcb_tmbx.tm_context = *ucp;
ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
if (ret != 0)
@@ -1149,10 +1127,9 @@ thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
}
static void
-thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf)
+thr_resume_check(struct pthread *curthread, ucontext_t *ucp)
{
- _thr_sig_rundown(curthread, ucp, psf);
+ _thr_sig_rundown(curthread, ucp);
if (THR_NEED_ASYNC_CANCEL(curthread))
pthread_testcancel();
diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c
index 047dca5..b502c15 100644
--- a/lib/libkse/thread/thr_mutex.c
+++ b/lib/libkse/thread/thr_mutex.c
@@ -85,26 +85,26 @@ static void mutex_rescan_owned (struct pthread *, struct pthread *,
static inline pthread_t mutex_queue_deq(pthread_mutex_t);
static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
-
+static void mutex_lock_backout(void *arg);
static struct pthread_mutex_attr static_mutex_attr =
PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */
-__weak_reference(_pthread_mutex_init, pthread_mutex_init);
__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
int
-_pthread_mutex_init(pthread_mutex_t *mutex,
+__pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr)
{
struct pthread_mutex *pmutex;
@@ -206,6 +206,22 @@ _pthread_mutex_init(pthread_mutex_t *mutex,
return (ret);
}
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex_attr mattr, *mattrp;
+
+ if ((mutex_attr == NULL) || (*mutex_attr == NULL))
+ return (__pthread_mutex_init(mutex, &static_mattr));
+ else {
+ mattr = **mutex_attr;
+ mattr.m_flags |= MUTEX_FLAGS_PRIVATE;
+ mattrp = &mattr;
+ return (__pthread_mutex_init(mutex, &mattrp));
+ }
+}
+
void
_thr_mutex_reinit(pthread_mutex_t *mutex)
{
@@ -303,6 +319,7 @@ init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
static int
mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
{
+ int private;
int ret = 0;
THR_ASSERT((mutex != NULL) && (*mutex != NULL),
@@ -310,6 +327,7 @@ mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
/* Lock the mutex structure: */
THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+ private = (*mutex)->m_flags & MUTEX_FLAGS_PRIVATE;
/*
* If the mutex was statically allocated, properly
@@ -417,6 +435,9 @@ mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
break;
}
+ if (ret == 0 && private)
+ THR_CRITICAL_ENTER(curthread);
+
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
@@ -468,6 +489,7 @@ static int
mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
const struct timespec * abstime)
{
+ int private;
int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL),
@@ -482,6 +504,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
curthread->timeout = 0;
curthread->wakeup_time.tv_sec = -1;
+ private = (*m)->m_flags & MUTEX_FLAGS_PRIVATE;
+
/*
* Enter a loop waiting to become the mutex owner. We need a
* loop in case the waiting thread is interrupted by a signal
@@ -516,6 +540,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -539,6 +565,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/*
* This thread is active and is in a critical
* region (holding the mutex lock); we should
@@ -554,12 +581,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
}
break;
@@ -590,6 +622,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -613,6 +647,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/*
* This thread is active and is in a critical
@@ -633,12 +668,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
}
break;
@@ -679,6 +719,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -702,6 +744,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/* Clear any previous error: */
curthread->error = 0;
@@ -722,12 +765,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
/*
* The threads priority may have changed while
@@ -932,6 +980,13 @@ mutex_self_lock(struct pthread *curthread, pthread_mutex_t m)
{
int ret = 0;
+ /*
+ * Don't allow evil recursive mutexes for private use
+ * in libc and libpthread.
+ */
+ if (m->m_flags & MUTEX_FLAGS_PRIVATE)
+ PANIC("Recurse on a private mutex.");
+
switch (m->m_type) {
/* case PTHREAD_MUTEX_DEFAULT: */
case PTHREAD_MUTEX_ERRORCHECK:
@@ -1135,8 +1190,13 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference)
/* Increment the reference count: */
(*m)->m_refcount++;
+ /* Leave the critical region if this is a private mutex. */
+ if ((ret == 0) && ((*m)->m_flags & MUTEX_FLAGS_PRIVATE))
+ THR_CRITICAL_LEAVE(curthread);
+
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
if (kmbx != NULL)
kse_wakeup(kmbx);
}
@@ -1511,9 +1571,10 @@ _mutex_unlock_private(pthread_t pthread)
* This is called by the current thread when it wants to back out of a
* mutex_lock in order to run a signal handler.
*/
-void
-_mutex_lock_backout(struct pthread *curthread)
+static void
+mutex_lock_backout(void *arg)
{
+ struct pthread *curthread = (struct pthread *)arg;
struct pthread_mutex *m;
if ((curthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
@@ -1554,6 +1615,8 @@ _mutex_lock_backout(struct pthread *curthread)
THR_LOCK_RELEASE(curthread, &m->m_lock);
}
}
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
}
/*
@@ -1674,13 +1737,16 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
(pthread->active_priority > curthread->active_priority))
curthread->critical_yield = 1;
- THR_SCHED_UNLOCK(curthread, pthread);
- if (mutex->m_owner == pthread)
+ if (mutex->m_owner == pthread) {
/* We're done; a valid owner was found. */
+ if (mutex->m_flags & MUTEX_FLAGS_PRIVATE)
+ THR_CRITICAL_ENTER(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
break;
- else
- /* Get the next thread from the waiting queue: */
- pthread = TAILQ_NEXT(pthread, sqe);
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Get the next thread from the waiting queue: */
+ pthread = TAILQ_NEXT(pthread, sqe);
}
if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
diff --git a/lib/libkse/thread/thr_once.c b/lib/libkse/thread/thr_once.c
index ad158d1..40344bd 100644
--- a/lib/libkse/thread/thr_once.c
+++ b/lib/libkse/thread/thr_once.c
@@ -67,6 +67,7 @@ once_cancel_handler(void *arg)
int
_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
{
+ struct pthread *curthread;
int wakeup = 0;
if (once_control->state == ONCE_DONE)
@@ -81,9 +82,10 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
once_control->state = ONCE_IN_PROGRESS;
_pthread_mutex_unlock(&once_lock);
- _pthread_cleanup_push(once_cancel_handler, once_control);
+ curthread = _get_curthread();
+ THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
init_routine();
- _pthread_cleanup_pop(0);
+ THR_CLEANUP_POP(curthread, 0);
_pthread_mutex_lock(&once_lock);
once_control->state = ONCE_DONE;
wakeup = 1;
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index b8ccb43..9f9f505 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -416,8 +416,24 @@ struct pthread_cleanup {
struct pthread_cleanup *next;
void (*routine) ();
void *routine_arg;
+ int onstack;
};
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
struct pthread_atfork {
TAILQ_ENTRY(pthread_atfork) qe;
void (*prepare)(void);
@@ -573,6 +589,7 @@ struct pthread_sigframe {
sigset_t psf_sigset;
sigset_t psf_sigmask;
int psf_seqno;
+ thread_continuation_t psf_continuation;
};
struct join_status {
@@ -645,8 +662,8 @@ struct pthread {
/*
* Used for tracking delivery of signal handlers.
*/
- struct pthread_sigframe *curframe;
siginfo_t *siginfo;
+ thread_continuation_t sigbackout;
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -1070,7 +1087,6 @@ SCLASS int _thr_debug_flags SCLASS_PRESET(0);
*/
__BEGIN_DECLS
int _cond_reinit(pthread_cond_t *);
-void _cond_wait_backout(struct pthread *);
struct kse *_kse_alloc(struct pthread *, int sys_scope);
kse_critical_t _kse_critical_enter(void);
void _kse_critical_leave(kse_critical_t);
@@ -1085,7 +1101,6 @@ int _kse_setthreaded(int);
void _kseg_free(struct kse_group *);
int _mutex_cv_lock(pthread_mutex_t *);
int _mutex_cv_unlock(pthread_mutex_t *);
-void _mutex_lock_backout(struct pthread *);
void _mutex_notify_priochange(struct pthread *, struct pthread *, int);
int _mutex_reinit(struct pthread_mutex *);
void _mutex_unlock_private(struct pthread *);
@@ -1148,8 +1163,7 @@ void _thr_set_timeout(const struct timespec *);
void _thr_seterrno(struct pthread *, int);
void _thr_sig_handler(int, siginfo_t *, ucontext_t *);
void _thr_sig_check_pending(struct pthread *);
-void _thr_sig_rundown(struct pthread *, ucontext_t *,
- struct pthread_sigframe *);
+void _thr_sig_rundown(struct pthread *, ucontext_t *);
void _thr_sig_send(struct pthread *pthread, int sig);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void);
diff --git a/lib/libkse/thread/thr_sem.c b/lib/libkse/thread/thr_sem.c
index b347a12..027960e 100644
--- a/lib/libkse/thread/thr_sem.c
+++ b/lib/libkse/thread/thr_sem.c
@@ -123,7 +123,7 @@ _sem_init(sem_t *sem, int pshared, unsigned int value)
{
semid_t semid;
- semid = SEM_USER;
+ semid = (semid_t)SEM_USER;
if ((pshared != 0) && (ksem_init(&semid, value) != 0))
return (-1);
@@ -145,8 +145,8 @@ _sem_wait(sem_t *sem)
if (sem_check_validity(sem) != 0)
return (-1);
+ curthread = _get_curthread();
if ((*sem)->syssem != 0) {
- curthread = _get_curthread();
_thr_cancel_enter(curthread);
retval = ksem_wait((*sem)->semid);
_thr_cancel_leave(curthread, retval != 0);
@@ -157,9 +157,9 @@ _sem_wait(sem_t *sem)
while ((*sem)->count <= 0) {
(*sem)->nwaiters++;
- pthread_cleanup_push(decrease_nwaiters, sem);
+ THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem);
pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
- pthread_cleanup_pop(0);
+ THR_CLEANUP_POP(curthread, 0);
(*sem)->nwaiters--;
}
(*sem)->count--;
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c
index a54663a..ec6ebd5 100644
--- a/lib/libkse/thread/thr_sig.c
+++ b/lib/libkse/thread/thr_sig.c
@@ -43,17 +43,15 @@
#include "thr_private.h"
/* Prototypes: */
-static void build_siginfo(siginfo_t *info, int signo);
+static inline void build_siginfo(siginfo_t *info, int signo);
#ifndef SYSTEM_SCOPE_ONLY
static struct pthread *thr_sig_find(struct kse *curkse, int sig,
siginfo_t *info);
-static void handle_special_signals(struct kse *curkse, int sig);
#endif
-static void thr_sigframe_add(struct pthread *thread);
-static void thr_sigframe_restore(struct pthread *thread,
- struct pthread_sigframe *psf);
-static void thr_sigframe_save(struct pthread *thread,
- struct pthread_sigframe *psf);
+static inline void thr_sigframe_restore(struct pthread *thread,
+ struct pthread_sigframe *psf);
+static inline void thr_sigframe_save(struct pthread *thread,
+ struct pthread_sigframe *psf);
#define SA_KILL 0x01 /* terminates process by default */
#define SA_STOP 0x02
@@ -254,9 +252,6 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
- /* Some signals need special handling: */
- handle_special_signals(curkse, sig);
-
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
@@ -306,11 +301,14 @@ typedef void (*ohandler)(int sig, int code,
void
_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
+ struct pthread_sigframe psf;
__siginfohandler_t *sigfunc;
struct pthread *curthread;
struct kse *curkse;
struct sigaction act;
- int sa_flags, err_save, intr_save, timeout_save;
+ int sa_flags, err_save;
+
+ err_save = errno;
DBG_MSG(">>> _thr_sig_handler(%d)\n", sig);
@@ -319,15 +317,18 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
PANIC("No current thread.\n");
if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
PANIC("Thread is not system scope.\n");
- if (curthread->flags & THR_FLAGS_EXITING)
+ if (curthread->flags & THR_FLAGS_EXITING) {
+ errno = err_save;
return;
+ }
+
curkse = _get_curkse();
/*
* If thread is in critical region or if thread is on
* the way of state transition, then latch signal into buffer.
*/
if (_kse_in_critical() || THR_IN_CRITICAL(curthread) ||
- (curthread->state != PS_RUNNING && curthread->curframe == NULL)) {
+ curthread->state != PS_RUNNING) {
DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig);
curthread->siginfo[sig-1] = *info;
curthread->check_pending = 1;
@@ -341,18 +342,24 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
*/
if (KSE_IS_IDLE(curkse))
kse_wakeup(&curkse->k_kcb->kcb_kmbx);
+ errno = err_save;
return;
}
- /* It is now safe to invoke signal handler */
- err_save = errno;
- timeout_save = curthread->timeout;
- intr_save = curthread->interrupted;
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
_thread_dump_info();
}
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+ thr_sigframe_save(curthread, &psf);
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+
_kse_critical_enter();
/* Get a fresh copy of signal mask */
__sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask);
@@ -395,14 +402,16 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
#endif
}
}
- errno = err_save;
- curthread->timeout = timeout_save;
- curthread->interrupted = intr_save;
_kse_critical_enter();
curthread->sigmask = ucp->uc_sigmask;
SIG_CANTMASK(curthread->sigmask);
_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ thr_sigframe_restore(curthread, &psf);
+
DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
+
+ errno = err_save;
}
struct sighandle_info {
@@ -439,7 +448,7 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
if (!_kse_in_critical())
PANIC("thr_sig_invoke_handler without in critical\n");
- curkse = _get_curkse();
+ curkse = curthread->kse;
/*
* Check that a custom handler is installed and if
* the signal is not blocked:
@@ -491,7 +500,7 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
_kse_critical_enter();
/* Don't trust after critical leave/enter */
- curkse = _get_curkse();
+ curkse = curthread->kse;
/*
* Restore the thread's signal mask.
@@ -752,7 +761,7 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
}
#endif /* ! SYSTEM_SCOPE_ONLY */
-static void
+static inline void
build_siginfo(siginfo_t *info, int signo)
{
bzero(info, sizeof(*info));
@@ -765,54 +774,35 @@ build_siginfo(siginfo_t *info, int signo)
* It should only be called from the context of the thread.
*/
void
-_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf)
+_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp)
{
- int interrupted = curthread->interrupted;
- int timeout = curthread->timeout;
+ struct pthread_sigframe psf;
siginfo_t siginfo;
- int i;
+ int i, err_save;
kse_critical_t crit;
struct kse *curkse;
sigset_t sigmask;
+ err_save = errno;
+
DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread);
+
/* Check the threads previous state: */
- if ((psf != NULL) && (psf->psf_valid != 0)) {
- /*
- * Do a little cleanup handling for those threads in
- * queues before calling the signal handler. Signals
- * for these threads are temporarily blocked until
- * after cleanup handling.
- */
- switch (psf->psf_state) {
- case PS_COND_WAIT:
- _cond_wait_backout(curthread);
- psf->psf_state = PS_RUNNING;
- break;
-
- case PS_MUTEX_WAIT:
- _mutex_lock_backout(curthread);
- psf->psf_state = PS_RUNNING;
- break;
-
- case PS_RUNNING:
- break;
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
- default:
- psf->psf_state = PS_RUNNING;
- break;
- }
- /* XXX see comment in thr_sched_switch_unlocked */
- curthread->critical_count--;
- }
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+ THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING");
+ thr_sigframe_save(curthread, &psf);
/*
* Lower the priority before calling the handler in case
* it never returns (longjmps back):
*/
crit = _kse_critical_enter();
- curkse = _get_curkse();
+ curkse = curthread->kse;
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
@@ -851,9 +841,8 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
}
}
- if (psf != NULL && psf->psf_valid != 0)
- thr_sigframe_restore(curthread, psf);
- curkse = _get_curkse();
+ /* Don't trust after signal handling */
+ curkse = curthread->kse;
KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
_kse_critical_leave(&curthread->tcb->tcb_tmbx);
@@ -875,10 +864,10 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
}
__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
}
- curthread->interrupted = interrupted;
- curthread->timeout = timeout;
-
DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread);
+
+ thr_sigframe_restore(curthread, &psf);
+ errno = err_save;
}
/*
@@ -897,7 +886,15 @@ _thr_sig_check_pending(struct pthread *curthread)
volatile int once;
int errsave;
- if (THR_IN_CRITICAL(curthread))
+ /*
+ * If the thread is in critical region, delay processing signals.
+ * If the thread state is not PS_RUNNING, it might be switching
+ * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it
+ * goes here, in the case we delay processing signals, lets UTS
+ * process complicated things, normally UTS will call _thr_sig_add
+ * to resume the thread, so we needn't repeat doing it here.
+ */
+ if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING)
return;
errsave = errno;
@@ -906,42 +903,11 @@ _thr_sig_check_pending(struct pthread *curthread)
if (once == 0) {
once = 1;
curthread->check_pending = 0;
- _thr_sig_rundown(curthread, &uc, NULL);
+ _thr_sig_rundown(curthread, &uc);
}
errno = errsave;
}
-#ifndef SYSTEM_SCOPE_ONLY
-/*
- * This must be called with upcalls disabled.
- */
-static void
-handle_special_signals(struct kse *curkse, int sig)
-{
- switch (sig) {
- /*
- * POSIX says that pending SIGCONT signals are
- * discarded when one of these signals occurs.
- */
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- SIGDELSET(_thr_proc_sigpending, SIGCONT);
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- break;
- case SIGCONT:
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- SIGDELSET(_thr_proc_sigpending, SIGTSTP);
- SIGDELSET(_thr_proc_sigpending, SIGTTIN);
- SIGDELSET(_thr_proc_sigpending, SIGTTOU);
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- default:
- break;
- }
-}
-#endif /* ! SYSTEM_SCOPE_ONLY */
-
/*
* Perform thread specific actions in response to a signal.
* This function is only called if there is a handler installed
@@ -979,11 +945,9 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
return (NULL);
}
- if (pthread->curframe == NULL ||
- (pthread->state != PS_SIGWAIT &&
- SIGISMEMBER(pthread->sigmask, sig)) ||
- THR_IN_CRITICAL(pthread)) {
- /* thread is running or signal was being masked */
+ if (pthread->state != PS_SIGWAIT &&
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ /* signal is masked, just add signal to thread. */
if (!fromproc) {
SIGADDSET(pthread->sigpend, sig);
if (info == NULL)
@@ -996,19 +960,6 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
return (NULL);
SIGADDSET(pthread->sigpend, sig);
}
- if (!SIGISMEMBER(pthread->sigmask, sig)) {
- /* A quick path to exit process */
- if (sigfunc == SIG_DFL && sigprop(sig) & SA_KILL) {
- kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
- /* Never reach */
- }
- pthread->check_pending = 1;
- if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
- (pthread->blocked != 0) &&
- !THR_IN_CRITICAL(pthread))
- kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
- restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
- }
}
else {
/* if process signal not exists, just return */
@@ -1049,7 +1000,6 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
/* Possible not in RUNQ and has curframe ? */
pthread->active_priority |= THR_SIGNAL_PRIORITY;
}
- suppress_handler = 1;
break;
/*
* States which cannot be interrupted but still require the
@@ -1115,19 +1065,22 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
build_siginfo(&pthread->siginfo[sig-1], sig);
else if (info != &pthread->siginfo[sig-1])
memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
-
+ pthread->check_pending = 1;
+ if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
if (suppress_handler == 0) {
/*
* Setup a signal frame and save the current threads
* state:
*/
- thr_sigframe_add(pthread);
- if (pthread->flags & THR_FLAGS_IN_RUNQ)
- THR_RUNQ_REMOVE(pthread);
- pthread->active_priority |= THR_SIGNAL_PRIORITY;
- kmbx = _thr_setrunnable_unlocked(pthread);
- } else {
- pthread->check_pending = 1;
+ if (pthread->state != PS_RUNNING) {
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
}
}
return (kmbx);
@@ -1151,6 +1104,10 @@ _thr_sig_send(struct pthread *pthread, int sig)
THR_SCHED_LOCK(curthread, pthread);
if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
kmbx = _thr_sig_add(pthread, sig, NULL);
+ /* Add a preemption point. */
+ if (kmbx == NULL && (curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
THR_SCHED_UNLOCK(curthread, pthread);
if (kmbx != NULL)
kse_wakeup(kmbx);
@@ -1161,52 +1118,55 @@ _thr_sig_send(struct pthread *pthread, int sig)
*/
if (pthread == curthread && curthread->check_pending)
_thr_sig_check_pending(curthread);
+
} else {
THR_SCHED_UNLOCK(curthread, pthread);
}
}
-static void
-thr_sigframe_add(struct pthread *thread)
+static inline void
+thr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf)
{
- if (thread->curframe == NULL)
- PANIC("Thread doesn't have signal frame ");
+ kse_critical_t crit;
+ struct kse *curkse;
- if (thread->curframe->psf_valid == 0) {
- thread->curframe->psf_valid = 1;
- /*
- * Multiple signals can be added to the same signal
- * frame. Only save the thread's state the first time.
- */
- thr_sigframe_save(thread, thread->curframe);
- }
+ THR_THREAD_LOCK(curthread, curthread);
+ curthread->cancelflags = psf->psf_cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ curthread->flags = psf->psf_flags;
+ curthread->interrupted = psf->psf_interrupted;
+ curthread->timeout = psf->psf_timeout;
+ curthread->data = psf->psf_wait_data;
+ curthread->wakeup_time = psf->psf_wakeup_time;
+ curthread->continuation = psf->psf_continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
}
-static void
-thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
+static inline void
+thr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf)
{
- if (psf->psf_valid == 0)
- PANIC("invalid pthread_sigframe\n");
- thread->flags = psf->psf_flags;
- thread->cancelflags = psf->psf_cancelflags;
- thread->interrupted = psf->psf_interrupted;
- thread->timeout = psf->psf_timeout;
- thread->state = psf->psf_state;
- thread->data = psf->psf_wait_data;
- thread->wakeup_time = psf->psf_wakeup_time;
-}
+ kse_critical_t crit;
+ struct kse *curkse;
-static void
-thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
-{
+ THR_THREAD_LOCK(curthread, curthread);
+ psf->psf_cancelflags = curthread->cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
/* This has to initialize all members of the sigframe. */
- psf->psf_flags = thread->flags & THR_FLAGS_PRIVATE;
- psf->psf_cancelflags = thread->cancelflags;
- psf->psf_interrupted = thread->interrupted;
- psf->psf_timeout = thread->timeout;
- psf->psf_state = thread->state;
- psf->psf_wait_data = thread->data;
- psf->psf_wakeup_time = thread->wakeup_time;
+ psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING));
+ psf->psf_interrupted = curthread->interrupted;
+ psf->psf_timeout = curthread->timeout;
+ psf->psf_wait_data = curthread->data;
+ psf->psf_wakeup_time = curthread->wakeup_time;
+ psf->psf_continuation = curthread->continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
}
void
@@ -1266,6 +1226,9 @@ _thr_signal_deinit(void)
int i;
struct pthread *curthread = _get_curthread();
+ /* Clear process pending signals. */
+ sigemptyset(&_thr_proc_sigpending);
+
/* Enter a loop to get the existing signal status: */
for (i = 1; i <= _SIG_MAXSIG; i++) {
/* Check for signals which cannot be trapped: */
diff --git a/lib/libkse/thread/thr_sigsuspend.c b/lib/libkse/thread/thr_sigsuspend.c
index b7802e3..ede45b5 100644
--- a/lib/libkse/thread/thr_sigsuspend.c
+++ b/lib/libkse/thread/thr_sigsuspend.c
@@ -69,6 +69,7 @@ _sigsuspend(const sigset_t *set)
/* Wait for a signal: */
_thr_sched_switch_unlocked(curthread);
} else {
+ curthread->check_pending = 1;
THR_UNLOCK_SWITCH(curthread);
/* check pending signal I can handle: */
_thr_sig_check_pending(curthread);
diff --git a/lib/libkse/thread/thr_spinlock.c b/lib/libkse/thread/thr_spinlock.c
index deaeb9b..2b2b251 100644
--- a/lib/libkse/thread/thr_spinlock.c
+++ b/lib/libkse/thread/thr_spinlock.c
@@ -49,6 +49,10 @@ struct spinlock_extra {
static void init_spinlock(spinlock_t *lck);
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
static pthread_mutex_t spinlock_static_lock;
static struct spinlock_extra extra[MAX_SPINLOCKS];
static int spinlock_count = 0;
@@ -65,7 +69,7 @@ _spinunlock(spinlock_t *lck)
struct spinlock_extra *extra;
extra = (struct spinlock_extra *)lck->fname;
- pthread_mutex_unlock(&extra->lock);
+ _pthread_mutex_unlock(&extra->lock);
}
/*
@@ -90,7 +94,7 @@ _spinlock(spinlock_t *lck)
if (lck->fname == NULL)
init_spinlock(lck);
extra = (struct spinlock_extra *)lck->fname;
- pthread_mutex_lock(&extra->lock);
+ _pthread_mutex_lock(&extra->lock);
}
/*
@@ -112,13 +116,13 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
static void
init_spinlock(spinlock_t *lck)
{
- pthread_mutex_lock(&spinlock_static_lock);
+ _pthread_mutex_lock(&spinlock_static_lock);
if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
lck->fname = (char *)&extra[spinlock_count];
extra[spinlock_count].owner = lck;
spinlock_count++;
}
- pthread_mutex_unlock(&spinlock_static_lock);
+ _pthread_mutex_unlock(&spinlock_static_lock);
if (lck->fname == NULL)
PANIC("Exceeded max spinlocks");
}
@@ -133,10 +137,10 @@ _thr_spinlock_init(void)
for (i = 0; i < spinlock_count; i++)
_thr_mutex_reinit(&extra[i].lock);
} else {
- if (pthread_mutex_init(&spinlock_static_lock, NULL))
+ if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr))
PANIC("Cannot initialize spinlock_static_lock");
for (i = 0; i < MAX_SPINLOCKS; i++) {
- if (pthread_mutex_init(&extra[i].lock, NULL))
+ if (_pthread_mutex_init(&extra[i].lock, &static_mattr))
PANIC("Cannot initialize spinlock extra");
}
initialized = 1;
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
index 4d9110e..706f54f 100644
--- a/lib/libpthread/pthread.map
+++ b/lib/libpthread/pthread.map
@@ -14,6 +14,7 @@ global:
__poll;
__pthread_cond_timedwait;
__pthread_cond_wait;
+ __pthread_mutex_init;
__pthread_mutex_lock;
__pthread_mutex_trylock;
__pthread_mutex_timedlock;
diff --git a/lib/libpthread/sys/thr_error.c b/lib/libpthread/sys/thr_error.c
index 6f19f93..72e1927 100644
--- a/lib/libpthread/sys/thr_error.c
+++ b/lib/libpthread/sys/thr_error.c
@@ -37,6 +37,7 @@
#include "libc_private.h"
#include "thr_private.h"
+#undef errno
extern int errno;
int *
diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c
index 8cd7acc..a6a32b8 100644
--- a/lib/libpthread/thread/thr_cancel.c
+++ b/lib/libpthread/thread/thr_cancel.c
@@ -14,18 +14,26 @@ __weak_reference(_pthread_testcancel, pthread_testcancel);
static inline int
checkcancel(struct pthread *curthread)
{
- if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
- ((curthread->cancelflags & THR_CANCELLING) != 0)) {
+ if ((curthread->cancelflags & THR_CANCELLING) != 0) {
/*
* It is possible for this thread to be swapped out
* while performing cancellation; do not allow it
* to be cancelled again.
*/
- curthread->cancelflags &= ~THR_CANCELLING;
- return (1);
+ if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
+ /*
+ * This may happen once, but after this, it
+ * shouldn't happen again.
+ */
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (0);
+ }
+ if ((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) {
+ curthread->cancelflags &= ~THR_CANCELLING;
+ return (1);
+ }
}
- else
- return (0);
+ return (0);
}
static inline void
diff --git a/lib/libpthread/thread/thr_clean.c b/lib/libpthread/thread/thr_clean.c
index a8cedb4..1da8a6b 100644
--- a/lib/libpthread/thread/thr_clean.c
+++ b/lib/libpthread/thread/thr_clean.c
@@ -50,6 +50,7 @@ _pthread_cleanup_push(void (*routine) (void *), void *routine_arg)
malloc(sizeof(struct pthread_cleanup))) != NULL) {
new->routine = routine;
new->routine_arg = routine_arg;
+ new->onstack = 0;
new->next = curthread->cleanup;
curthread->cleanup = new;
@@ -67,6 +68,7 @@ _pthread_cleanup_pop(int execute)
if (execute) {
old->routine(old->routine_arg);
}
- free(old);
+ if (old->onstack == 0)
+ free(old);
}
}
diff --git a/lib/libpthread/thread/thr_concurrency.c b/lib/libpthread/thread/thr_concurrency.c
index 59e8550..daea56c 100644
--- a/lib/libpthread/thread/thr_concurrency.c
+++ b/lib/libpthread/thread/thr_concurrency.c
@@ -84,6 +84,13 @@ _thr_setconcurrency(int new_level)
int i;
int ret;
+ /*
+ * Turn on threaded mode, if failed, it is unnecessary to
+ * do further work.
+ */
+ if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
+ return (EAGAIN);
+
ret = 0;
curthread = _get_curthread();
/* Race condition, but so what. */
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c
index fd7b6d9..cd719d4 100644
--- a/lib/libpthread/thread/thr_cond.c
+++ b/lib/libpthread/thread/thr_cond.c
@@ -47,6 +47,9 @@
static inline struct pthread *cond_queue_deq(pthread_cond_t);
static inline void cond_queue_remove(pthread_cond_t, pthread_t);
static inline void cond_queue_enq(pthread_cond_t, pthread_t);
+static void cond_wait_backout(void *);
+static inline void check_continuation(struct pthread *,
+ struct pthread_cond *, pthread_mutex_t *);
/*
* Double underscore versions are cancellation points. Single underscore
@@ -171,8 +174,7 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
struct pthread *curthread = _get_curthread();
int rval = 0;
int done = 0;
- int interrupted = 0;
- int unlock_mutex = 1;
+ int mutex_locked = 1;
int seqno;
if (cond == NULL)
@@ -198,10 +200,11 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* and backed out of the waiting queue prior to executing the
* signal handler.
*/
- do {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
/*
* If the condvar was statically allocated, properly
* initialize the tail queue.
@@ -217,9 +220,6 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
case COND_TYPE_FAST:
if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
((*cond)->c_mutex != *mutex))) {
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return invalid argument error: */
rval = EINVAL;
} else {
@@ -233,15 +233,11 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
*/
cond_queue_enq(*cond, curthread);
- /* Remember the mutex and sequence number: */
- (*cond)->c_mutex = *mutex;
- seqno = (*cond)->c_seqno;
-
/* Wait forever: */
curthread->wakeup_time.tv_sec = -1;
/* Unlock the mutex: */
- if ((unlock_mutex != 0) &&
+ if (mutex_locked &&
((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex, so remove
@@ -249,22 +245,18 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* variable queue:
*/
cond_queue_remove(*cond, curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
}
else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
/*
* Don't unlock the mutex the next
* time through the loop (if the
* thread has to be requeued after
* handling a signal).
*/
- unlock_mutex = 0;
+ mutex_locked = 0;
/*
* This thread is active and is in a
@@ -277,6 +269,7 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Remember the CV: */
curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
THR_SCHED_UNLOCK(curthread, curthread);
/* Unlock the CV structure: */
@@ -286,8 +279,6 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.cond = NULL;
-
/*
* XXX - This really isn't a good check
* since there can be more than one
@@ -299,41 +290,39 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
* should be sent "as soon as possible".
*/
done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_SYNCQ(curthread)) {
+ if (done && !THR_IN_CONDQ(curthread)) {
/*
- * Lock the condition variable
- * while removing the thread.
+ * The thread is dequeued, so
+ * it is safe to clear these.
*/
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ done = (seqno != (*cond)->c_seqno);
+ if (THR_IN_CONDQ(curthread)) {
cond_queue_remove(*cond,
curthread);
/* Check for no more waiters: */
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
-
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
- }
-
- /*
- * Save the interrupted flag; locking
- * the mutex may destroy it.
- */
- interrupted = curthread->interrupted;
-
- /*
- * Note that even though this thread may
- * have been canceled, POSIX requires
- * that the mutex be reaquired prior to
- * cancellation.
- */
- if (done || interrupted) {
- rval = _mutex_cv_lock(mutex);
- unlock_mutex = 1;
}
}
}
@@ -341,18 +330,21 @@ _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
/* Trap invalid condition variable types: */
default:
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return an invalid argument error: */
rval = EINVAL;
break;
}
- if ((interrupted != 0) && (curthread->continuation != NULL))
- curthread->continuation((void *) curthread);
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
} while ((done == 0) && (rval == 0));
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
/* Return the completion status: */
return (rval);
}
@@ -378,8 +370,7 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
struct pthread *curthread = _get_curthread();
int rval = 0;
int done = 0;
- int interrupted = 0;
- int unlock_mutex = 1;
+ int mutex_locked = 1;
int seqno;
THR_ASSERT(curthread->locklevel == 0,
@@ -407,10 +398,11 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* and backed out of the waiting queue prior to executing the
* signal handler.
*/
- do {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ /* Lock the condition variable structure: */
+ THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ seqno = (*cond)->c_seqno;
+ do {
/*
* If the condvar was statically allocated, properly
* initialize the tail queue.
@@ -428,9 +420,6 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
((*cond)->c_mutex != *mutex))) {
/* Return invalid argument error: */
rval = EINVAL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
} else {
/* Set the wakeup time: */
curthread->wakeup_time.tv_sec = abstime->tv_sec;
@@ -447,12 +436,8 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
*/
cond_queue_enq(*cond, curthread);
- /* Remember the mutex and sequence number: */
- (*cond)->c_mutex = *mutex;
- seqno = (*cond)->c_seqno;
-
/* Unlock the mutex: */
- if ((unlock_mutex != 0) &&
+ if (mutex_locked &&
((rval = _mutex_cv_unlock(mutex)) != 0)) {
/*
* Cannot unlock the mutex; remove the
@@ -460,21 +445,17 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* variable queue:
*/
cond_queue_remove(*cond, curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
} else {
+ /* Remember the mutex: */
+ (*cond)->c_mutex = *mutex;
+
/*
* Don't unlock the mutex the next
* time through the loop (if the
* thread has to be requeued after
* handling a signal).
*/
- unlock_mutex = 0;
+ mutex_locked = 0;
/*
* This thread is active and is in a
@@ -487,6 +468,7 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Remember the CV: */
curthread->data.cond = *cond;
+ curthread->sigbackout = cond_wait_backout;
THR_SCHED_UNLOCK(curthread, curthread);
/* Unlock the CV structure: */
@@ -496,8 +478,6 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.cond = NULL;
-
/*
* XXX - This really isn't a good check
* since there can be more than one
@@ -509,38 +489,45 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
* should be sent "as soon as possible".
*/
done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_CONDQ(curthread)) {
+ if (done && !THR_IN_CONDQ(curthread)) {
/*
- * Lock the condition variable
- * while removing the thread.
+ * The thread is dequeued, so
+ * it is safe to clear these.
*/
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+ check_continuation(curthread,
+ NULL, mutex);
+ return (_mutex_cv_lock(mutex));
+ }
+ /* Relock the CV structure: */
+ THR_LOCK_ACQUIRE(curthread,
+ &(*cond)->c_lock);
+
+ /*
+ * Clear these after taking the lock to
+ * prevent a race condition where a
+ * signal can arrive before dequeueing
+ * the thread.
+ */
+ curthread->data.cond = NULL;
+ curthread->sigbackout = NULL;
+
+ done = (seqno != (*cond)->c_seqno);
+
+ if (THR_IN_CONDQ(curthread)) {
cond_queue_remove(*cond,
curthread);
/* Check for no more waiters: */
if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
(*cond)->c_mutex = NULL;
-
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
}
- /*
- * Save the interrupted flag; locking
- * the mutex may destroy it.
- */
- interrupted = curthread->interrupted;
if (curthread->timeout != 0) {
/* The wait timedout. */
rval = ETIMEDOUT;
- (void)_mutex_cv_lock(mutex);
- } else if (interrupted || done) {
- rval = _mutex_cv_lock(mutex);
- unlock_mutex = 1;
}
}
}
@@ -548,18 +535,21 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
/* Trap invalid condition variable types: */
default:
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
/* Return an invalid argument error: */
rval = EINVAL;
break;
}
- if ((interrupted != 0) && (curthread->continuation != NULL))
- curthread->continuation((void *)curthread);
+ check_continuation(curthread, *cond,
+ mutex_locked ? NULL : mutex);
} while ((done == 0) && (rval == 0));
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
+
+ if (mutex_locked == 0)
+ _mutex_cv_lock(mutex);
+
/* Return the completion status: */
return (rval);
}
@@ -615,6 +605,7 @@ _pthread_cond_signal(pthread_cond_t * cond)
!= NULL) {
THR_SCHED_LOCK(curthread, pthread);
cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
if ((pthread->kseg == curthread->kseg) &&
(pthread->active_priority >
curthread->active_priority))
@@ -681,6 +672,7 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
!= NULL) {
THR_SCHED_LOCK(curthread, pthread);
cond_queue_remove(*cond, pthread);
+ pthread->sigbackout = NULL;
if ((pthread->kseg == curthread->kseg) &&
(pthread->active_priority >
curthread->active_priority))
@@ -712,9 +704,31 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
-void
-_cond_wait_backout(struct pthread *curthread)
+static inline void
+check_continuation(struct pthread *curthread, struct pthread_cond *cond,
+ pthread_mutex_t *mutex)
+{
+ if ((curthread->interrupted != 0) &&
+ (curthread->continuation != NULL)) {
+ if (cond != NULL)
+ /* Unlock the condition variable structure: */
+ THR_LOCK_RELEASE(curthread, &cond->c_lock);
+ /*
+ * Note that even though this thread may have been
+ * canceled, POSIX requires that the mutex be
+ * reaquired prior to cancellation.
+ */
+ if (mutex != NULL)
+ _mutex_cv_lock(mutex);
+ curthread->continuation((void *) curthread);
+ PANIC("continuation returned in pthread_cond_wait.\n");
+ }
+}
+
+static void
+cond_wait_backout(void *arg)
{
+ struct pthread *curthread = (struct pthread *)arg;
pthread_cond_t cond;
cond = curthread->data.cond;
@@ -740,6 +754,8 @@ _cond_wait_backout(struct pthread *curthread)
/* Unlock the condition variable structure: */
THR_LOCK_RELEASE(curthread, &cond->c_lock);
}
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
}
/*
diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c
index 03f467b..08b2c47 100644
--- a/lib/libpthread/thread/thr_create.c
+++ b/lib/libpthread/thread/thr_create.c
@@ -171,9 +171,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* No thread is wanting to join to this one: */
new_thread->joiner = NULL;
- /* Initialize the signal frame: */
- new_thread->curframe = NULL;
-
/*
* Initialize the machine context.
* Enter a critical region to get consistent context.
@@ -235,6 +232,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->cleanup = NULL;
new_thread->flags = 0;
new_thread->tlflags = 0;
+ new_thread->sigbackout = NULL;
new_thread->continuation = NULL;
new_thread->wakeup_time.tv_sec = -1;
new_thread->lock_switch = 0;
diff --git a/lib/libpthread/thread/thr_fork.c b/lib/libpthread/thread/thr_fork.c
index 401aae9..fdbfd86 100644
--- a/lib/libpthread/thread/thr_fork.c
+++ b/lib/libpthread/thread/thr_fork.c
@@ -43,12 +43,6 @@
#include "libc_private.h"
#include "thr_private.h"
-/*
- * For a while, allow libpthread to work with a libc that doesn't
- * export the malloc lock.
- */
-#pragma weak __malloc_lock
-
__weak_reference(_fork, fork);
pid_t
@@ -60,11 +54,21 @@ _fork(void)
pid_t ret;
int errsave;
- if (!_kse_isthreaded())
- return (__sys_fork());
-
curthread = _get_curthread();
+ if (!_kse_isthreaded()) {
+ SIGFILLSET(sigset);
+ __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset);
+ ret = __sys_fork();
+ if (ret == 0)
+ /* Child */
+ __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask,
+ NULL);
+ else
+ __sys_sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return (ret);
+ }
+
/*
* Masks all signals until we reach a safe point in
* _kse_single_thread, and the signal masks will be
@@ -86,7 +90,7 @@ _fork(void)
}
/* Fork a new process: */
- if ((_kse_isthreaded() != 0) && (__malloc_lock != NULL)) {
+ if (_kse_isthreaded() != 0) {
_spinlock(__malloc_lock);
}
if ((ret = __sys_fork()) == 0) {
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index 719195f..6d41087 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -391,6 +391,7 @@ init_main_thread(struct pthread *thread)
thread->specific = NULL;
thread->cleanup = NULL;
thread->flags = 0;
+ thread->sigbackout = NULL;
thread->continuation = NULL;
thread->state = PS_RUNNING;
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index 5d7fabb..aec2541 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
#include "thr_private.h"
#include "libc_private.h"
-/*#define DEBUG_THREAD_KERN */
+/* #define DEBUG_THREAD_KERN */
#ifdef DEBUG_THREAD_KERN
#define DBG_MSG stdout_debug
#else
@@ -165,8 +165,7 @@ static struct kse_mailbox *kse_wakeup_one(struct pthread *thread);
static void thr_cleanup(struct kse *kse, struct pthread *curthread);
static void thr_link(struct pthread *thread);
static void thr_resume_wrapper(int sig, siginfo_t *, ucontext_t *);
-static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf);
+static void thr_resume_check(struct pthread *curthread, ucontext_t *ucp);
static int thr_timedout(struct pthread *thread, struct timespec *curtime);
static void thr_unlink(struct pthread *thread);
static void thr_destroy(struct pthread *curthread, struct pthread *thread);
@@ -352,6 +351,9 @@ _kse_single_thread(struct pthread *curthread)
curthread->kse->k_kcb->kcb_kmbx.km_curthread = NULL;
curthread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
+ /* After a fork(), there child should have no pending signals. */
+ sigemptyset(&curthread->sigpend);
+
/*
* Restore signal mask early, so any memory problems could
* dump core.
@@ -615,13 +617,12 @@ _thr_sched_switch(struct pthread *curthread)
void
_thr_sched_switch_unlocked(struct pthread *curthread)
{
- struct pthread_sigframe psf;
struct kse *curkse;
volatile int resume_once = 0;
ucontext_t *uc;
/* We're in the scheduler, 5 by 5: */
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->need_switchout = 1; /* The thread yielded on its own. */
curthread->critical_yield = 0; /* No need to yield anymore. */
@@ -629,14 +630,6 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/* Thread can unlock the scheduler lock. */
curthread->lock_switch = 1;
- /*
- * The signal frame is allocated off the stack because
- * a thread can be interrupted by other signals while
- * it is running down pending signals.
- */
- psf.psf_valid = 0;
- curthread->curframe = &psf;
-
if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
kse_sched_single(&curkse->k_kcb->kcb_kmbx);
else {
@@ -658,18 +651,11 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
}
/*
- * It is ugly we must increase critical count, because we
- * have a frame saved, we must backout state in psf
- * before we can process signals.
- */
- curthread->critical_count += psf.psf_valid;
-
- /*
* Unlock the scheduling queue and leave the
* critical region.
*/
/* Don't trust this after a switch! */
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->lock_switch = 0;
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
@@ -678,16 +664,14 @@ _thr_sched_switch_unlocked(struct pthread *curthread)
/*
* This thread is being resumed; check for cancellations.
*/
- if ((psf.psf_valid ||
- ((curthread->check_pending || THR_NEED_ASYNC_CANCEL(curthread))
- && !THR_IN_CRITICAL(curthread)))) {
+ if (THR_NEED_ASYNC_CANCEL(curthread) && !THR_IN_CRITICAL(curthread)) {
uc = alloca(sizeof(ucontext_t));
resume_once = 0;
THR_GETCONTEXT(uc);
if (resume_once == 0) {
resume_once = 1;
curthread->check_pending = 0;
- thr_resume_check(curthread, uc, &psf);
+ thr_resume_check(curthread, uc);
}
}
THR_ACTIVATE_LAST_LOCK(curthread);
@@ -888,9 +872,6 @@ kse_sched_single(struct kse_mailbox *kmbx)
}
}
- /* Remove the frame reference. */
- curthread->curframe = NULL;
-
if (curthread->lock_switch == 0) {
/* Unlock the scheduling queue. */
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
@@ -925,7 +906,6 @@ kse_sched_multi(struct kse_mailbox *kmbx)
{
struct kse *curkse;
struct pthread *curthread, *td_wait;
- struct pthread_sigframe *curframe;
int ret;
curkse = (struct kse *)kmbx->km_udata;
@@ -980,6 +960,8 @@ kse_sched_multi(struct kse_mailbox *kmbx)
* will be cleared.
*/
curthread->blocked = 1;
+ DBG_MSG("Running thread %p is now blocked in kernel.\n",
+ curthread);
}
/* Check for any unblocked threads in the kernel. */
@@ -1085,10 +1067,6 @@ kse_sched_multi(struct kse_mailbox *kmbx)
/* Mark the thread active. */
curthread->active = 1;
- /* Remove the frame reference. */
- curframe = curthread->curframe;
- curthread->curframe = NULL;
-
/*
* The thread's current signal frame will only be NULL if it
* is being resumed after being blocked in the kernel. In
@@ -1096,7 +1074,7 @@ kse_sched_multi(struct kse_mailbox *kmbx)
* signals or needs a cancellation check, we need to add a
* signal frame to the thread's context.
*/
- if ((curframe == NULL) && (curthread->state == PS_RUNNING) &&
+ if (curthread->lock_switch == 0 && curthread->state == PS_RUNNING &&
(curthread->check_pending != 0 ||
THR_NEED_ASYNC_CANCEL(curthread)) &&
!THR_IN_CRITICAL(curthread)) {
@@ -1136,10 +1114,10 @@ thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
DBG_MSG(">>> sig wrapper\n");
if (curthread->lock_switch)
PANIC("thr_resume_wrapper, lock_switch != 0\n");
- thr_resume_check(curthread, ucp, NULL);
+ thr_resume_check(curthread, ucp);
errno = err_save;
_kse_critical_enter();
- curkse = _get_curkse();
+ curkse = curthread->kse;
curthread->tcb->tcb_tmbx.tm_context = *ucp;
ret = _thread_switch(curkse->k_kcb, curthread->tcb, 1);
if (ret != 0)
@@ -1149,10 +1127,9 @@ thr_resume_wrapper(int sig, siginfo_t *siginfo, ucontext_t *ucp)
}
static void
-thr_resume_check(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf)
+thr_resume_check(struct pthread *curthread, ucontext_t *ucp)
{
- _thr_sig_rundown(curthread, ucp, psf);
+ _thr_sig_rundown(curthread, ucp);
if (THR_NEED_ASYNC_CANCEL(curthread))
pthread_testcancel();
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
index 047dca5..b502c15 100644
--- a/lib/libpthread/thread/thr_mutex.c
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -85,26 +85,26 @@ static void mutex_rescan_owned (struct pthread *, struct pthread *,
static inline pthread_t mutex_queue_deq(pthread_mutex_t);
static inline void mutex_queue_remove(pthread_mutex_t, pthread_t);
static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
-
+static void mutex_lock_backout(void *arg);
static struct pthread_mutex_attr static_mutex_attr =
PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */
+__weak_reference(__pthread_mutex_init, pthread_mutex_init);
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */
-__weak_reference(_pthread_mutex_init, pthread_mutex_init);
__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
int
-_pthread_mutex_init(pthread_mutex_t *mutex,
+__pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr)
{
struct pthread_mutex *pmutex;
@@ -206,6 +206,22 @@ _pthread_mutex_init(pthread_mutex_t *mutex,
return (ret);
}
+int
+_pthread_mutex_init(pthread_mutex_t *mutex,
+ const pthread_mutexattr_t *mutex_attr)
+{
+ struct pthread_mutex_attr mattr, *mattrp;
+
+ if ((mutex_attr == NULL) || (*mutex_attr == NULL))
+ return (__pthread_mutex_init(mutex, &static_mattr));
+ else {
+ mattr = **mutex_attr;
+ mattr.m_flags |= MUTEX_FLAGS_PRIVATE;
+ mattrp = &mattr;
+ return (__pthread_mutex_init(mutex, &mattrp));
+ }
+}
+
void
_thr_mutex_reinit(pthread_mutex_t *mutex)
{
@@ -303,6 +319,7 @@ init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
static int
mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
{
+ int private;
int ret = 0;
THR_ASSERT((mutex != NULL) && (*mutex != NULL),
@@ -310,6 +327,7 @@ mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
/* Lock the mutex structure: */
THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
+ private = (*mutex)->m_flags & MUTEX_FLAGS_PRIVATE;
/*
* If the mutex was statically allocated, properly
@@ -417,6 +435,9 @@ mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
break;
}
+ if (ret == 0 && private)
+ THR_CRITICAL_ENTER(curthread);
+
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
@@ -468,6 +489,7 @@ static int
mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
const struct timespec * abstime)
{
+ int private;
int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL),
@@ -482,6 +504,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
curthread->timeout = 0;
curthread->wakeup_time.tv_sec = -1;
+ private = (*m)->m_flags & MUTEX_FLAGS_PRIVATE;
+
/*
* Enter a loop waiting to become the mutex owner. We need a
* loop in case the waiting thread is interrupted by a signal
@@ -516,6 +540,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -539,6 +565,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/*
* This thread is active and is in a critical
* region (holding the mutex lock); we should
@@ -554,12 +581,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
}
break;
@@ -590,6 +622,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -613,6 +647,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/*
* This thread is active and is in a critical
@@ -633,12 +668,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
}
break;
@@ -679,6 +719,8 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
MUTEX_ASSERT_NOT_OWNED(*m);
TAILQ_INSERT_TAIL(&curthread->mutexq,
(*m), m_qe);
+ if (private)
+ THR_CRITICAL_ENTER(curthread);
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
@@ -702,6 +744,7 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
*/
mutex_queue_enq(*m, curthread);
curthread->data.mutex = *m;
+ curthread->sigbackout = mutex_lock_backout;
/* Clear any previous error: */
curthread->error = 0;
@@ -722,12 +765,17 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
/* Schedule the next thread: */
_thr_sched_switch(curthread);
- curthread->data.mutex = NULL;
if (THR_IN_MUTEXQ(curthread)) {
THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
mutex_queue_remove(*m, curthread);
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
}
+ /*
+ * Only clear these after assuring the
+ * thread is dequeued.
+ */
+ curthread->data.mutex = NULL;
+ curthread->sigbackout = NULL;
/*
* The threads priority may have changed while
@@ -932,6 +980,13 @@ mutex_self_lock(struct pthread *curthread, pthread_mutex_t m)
{
int ret = 0;
+ /*
+ * Don't allow evil recursive mutexes for private use
+ * in libc and libpthread.
+ */
+ if (m->m_flags & MUTEX_FLAGS_PRIVATE)
+ PANIC("Recurse on a private mutex.");
+
switch (m->m_type) {
/* case PTHREAD_MUTEX_DEFAULT: */
case PTHREAD_MUTEX_ERRORCHECK:
@@ -1135,8 +1190,13 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference)
/* Increment the reference count: */
(*m)->m_refcount++;
+ /* Leave the critical region if this is a private mutex. */
+ if ((ret == 0) && ((*m)->m_flags & MUTEX_FLAGS_PRIVATE))
+ THR_CRITICAL_LEAVE(curthread);
+
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+
if (kmbx != NULL)
kse_wakeup(kmbx);
}
@@ -1511,9 +1571,10 @@ _mutex_unlock_private(pthread_t pthread)
* This is called by the current thread when it wants to back out of a
* mutex_lock in order to run a signal handler.
*/
-void
-_mutex_lock_backout(struct pthread *curthread)
+static void
+mutex_lock_backout(void *arg)
{
+ struct pthread *curthread = (struct pthread *)arg;
struct pthread_mutex *m;
if ((curthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
@@ -1554,6 +1615,8 @@ _mutex_lock_backout(struct pthread *curthread)
THR_LOCK_RELEASE(curthread, &m->m_lock);
}
}
+ /* No need to call this again. */
+ curthread->sigbackout = NULL;
}
/*
@@ -1674,13 +1737,16 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
(pthread->active_priority > curthread->active_priority))
curthread->critical_yield = 1;
- THR_SCHED_UNLOCK(curthread, pthread);
- if (mutex->m_owner == pthread)
+ if (mutex->m_owner == pthread) {
/* We're done; a valid owner was found. */
+ if (mutex->m_flags & MUTEX_FLAGS_PRIVATE)
+ THR_CRITICAL_ENTER(pthread);
+ THR_SCHED_UNLOCK(curthread, pthread);
break;
- else
- /* Get the next thread from the waiting queue: */
- pthread = TAILQ_NEXT(pthread, sqe);
+ }
+ THR_SCHED_UNLOCK(curthread, pthread);
+ /* Get the next thread from the waiting queue: */
+ pthread = TAILQ_NEXT(pthread, sqe);
}
if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
diff --git a/lib/libpthread/thread/thr_once.c b/lib/libpthread/thread/thr_once.c
index ad158d1..40344bd 100644
--- a/lib/libpthread/thread/thr_once.c
+++ b/lib/libpthread/thread/thr_once.c
@@ -67,6 +67,7 @@ once_cancel_handler(void *arg)
int
_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
{
+ struct pthread *curthread;
int wakeup = 0;
if (once_control->state == ONCE_DONE)
@@ -81,9 +82,10 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
once_control->state = ONCE_IN_PROGRESS;
_pthread_mutex_unlock(&once_lock);
- _pthread_cleanup_push(once_cancel_handler, once_control);
+ curthread = _get_curthread();
+ THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
init_routine();
- _pthread_cleanup_pop(0);
+ THR_CLEANUP_POP(curthread, 0);
_pthread_mutex_lock(&once_lock);
once_control->state = ONCE_DONE;
wakeup = 1;
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index b8ccb43..9f9f505 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -416,8 +416,24 @@ struct pthread_cleanup {
struct pthread_cleanup *next;
void (*routine) ();
void *routine_arg;
+ int onstack;
};
+#define THR_CLEANUP_PUSH(td, func, arg) { \
+ struct pthread_cleanup __cup; \
+ \
+ __cup.routine = func; \
+ __cup.routine_arg = arg; \
+ __cup.onstack = 1; \
+ __cup.next = (td)->cleanup; \
+ (td)->cleanup = &__cup;
+
+#define THR_CLEANUP_POP(td, exec) \
+ (td)->cleanup = __cup.next; \
+ if ((exec) != 0) \
+ __cup.routine(__cup.routine_arg); \
+}
+
struct pthread_atfork {
TAILQ_ENTRY(pthread_atfork) qe;
void (*prepare)(void);
@@ -573,6 +589,7 @@ struct pthread_sigframe {
sigset_t psf_sigset;
sigset_t psf_sigmask;
int psf_seqno;
+ thread_continuation_t psf_continuation;
};
struct join_status {
@@ -645,8 +662,8 @@ struct pthread {
/*
* Used for tracking delivery of signal handlers.
*/
- struct pthread_sigframe *curframe;
siginfo_t *siginfo;
+ thread_continuation_t sigbackout;
/*
* Cancelability flags - the lower 2 bits are used by cancel
@@ -1070,7 +1087,6 @@ SCLASS int _thr_debug_flags SCLASS_PRESET(0);
*/
__BEGIN_DECLS
int _cond_reinit(pthread_cond_t *);
-void _cond_wait_backout(struct pthread *);
struct kse *_kse_alloc(struct pthread *, int sys_scope);
kse_critical_t _kse_critical_enter(void);
void _kse_critical_leave(kse_critical_t);
@@ -1085,7 +1101,6 @@ int _kse_setthreaded(int);
void _kseg_free(struct kse_group *);
int _mutex_cv_lock(pthread_mutex_t *);
int _mutex_cv_unlock(pthread_mutex_t *);
-void _mutex_lock_backout(struct pthread *);
void _mutex_notify_priochange(struct pthread *, struct pthread *, int);
int _mutex_reinit(struct pthread_mutex *);
void _mutex_unlock_private(struct pthread *);
@@ -1148,8 +1163,7 @@ void _thr_set_timeout(const struct timespec *);
void _thr_seterrno(struct pthread *, int);
void _thr_sig_handler(int, siginfo_t *, ucontext_t *);
void _thr_sig_check_pending(struct pthread *);
-void _thr_sig_rundown(struct pthread *, ucontext_t *,
- struct pthread_sigframe *);
+void _thr_sig_rundown(struct pthread *, ucontext_t *);
void _thr_sig_send(struct pthread *pthread, int sig);
void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf);
void _thr_spinlock_init(void);
diff --git a/lib/libpthread/thread/thr_sem.c b/lib/libpthread/thread/thr_sem.c
index b347a12..027960e 100644
--- a/lib/libpthread/thread/thr_sem.c
+++ b/lib/libpthread/thread/thr_sem.c
@@ -123,7 +123,7 @@ _sem_init(sem_t *sem, int pshared, unsigned int value)
{
semid_t semid;
- semid = SEM_USER;
+ semid = (semid_t)SEM_USER;
if ((pshared != 0) && (ksem_init(&semid, value) != 0))
return (-1);
@@ -145,8 +145,8 @@ _sem_wait(sem_t *sem)
if (sem_check_validity(sem) != 0)
return (-1);
+ curthread = _get_curthread();
if ((*sem)->syssem != 0) {
- curthread = _get_curthread();
_thr_cancel_enter(curthread);
retval = ksem_wait((*sem)->semid);
_thr_cancel_leave(curthread, retval != 0);
@@ -157,9 +157,9 @@ _sem_wait(sem_t *sem)
while ((*sem)->count <= 0) {
(*sem)->nwaiters++;
- pthread_cleanup_push(decrease_nwaiters, sem);
+ THR_CLEANUP_PUSH(curthread, decrease_nwaiters, sem);
pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
- pthread_cleanup_pop(0);
+ THR_CLEANUP_POP(curthread, 0);
(*sem)->nwaiters--;
}
(*sem)->count--;
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index a54663a..ec6ebd5 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -43,17 +43,15 @@
#include "thr_private.h"
/* Prototypes: */
-static void build_siginfo(siginfo_t *info, int signo);
+static inline void build_siginfo(siginfo_t *info, int signo);
#ifndef SYSTEM_SCOPE_ONLY
static struct pthread *thr_sig_find(struct kse *curkse, int sig,
siginfo_t *info);
-static void handle_special_signals(struct kse *curkse, int sig);
#endif
-static void thr_sigframe_add(struct pthread *thread);
-static void thr_sigframe_restore(struct pthread *thread,
- struct pthread_sigframe *psf);
-static void thr_sigframe_save(struct pthread *thread,
- struct pthread_sigframe *psf);
+static inline void thr_sigframe_restore(struct pthread *thread,
+ struct pthread_sigframe *psf);
+static inline void thr_sigframe_save(struct pthread *thread,
+ struct pthread_sigframe *psf);
#define SA_KILL 0x01 /* terminates process by default */
#define SA_STOP 0x02
@@ -254,9 +252,6 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info)
DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig);
- /* Some signals need special handling: */
- handle_special_signals(curkse, sig);
-
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
@@ -306,11 +301,14 @@ typedef void (*ohandler)(int sig, int code,
void
_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
{
+ struct pthread_sigframe psf;
__siginfohandler_t *sigfunc;
struct pthread *curthread;
struct kse *curkse;
struct sigaction act;
- int sa_flags, err_save, intr_save, timeout_save;
+ int sa_flags, err_save;
+
+ err_save = errno;
DBG_MSG(">>> _thr_sig_handler(%d)\n", sig);
@@ -319,15 +317,18 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
PANIC("No current thread.\n");
if (!(curthread->attr.flags & PTHREAD_SCOPE_SYSTEM))
PANIC("Thread is not system scope.\n");
- if (curthread->flags & THR_FLAGS_EXITING)
+ if (curthread->flags & THR_FLAGS_EXITING) {
+ errno = err_save;
return;
+ }
+
curkse = _get_curkse();
/*
* If thread is in critical region or if thread is on
* the way of state transition, then latch signal into buffer.
*/
if (_kse_in_critical() || THR_IN_CRITICAL(curthread) ||
- (curthread->state != PS_RUNNING && curthread->curframe == NULL)) {
+ curthread->state != PS_RUNNING) {
DBG_MSG(">>> _thr_sig_handler(%d) in critical\n", sig);
curthread->siginfo[sig-1] = *info;
curthread->check_pending = 1;
@@ -341,18 +342,24 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
*/
if (KSE_IS_IDLE(curkse))
kse_wakeup(&curkse->k_kcb->kcb_kmbx);
+ errno = err_save;
return;
}
- /* It is now safe to invoke signal handler */
- err_save = errno;
- timeout_save = curthread->timeout;
- intr_save = curthread->interrupted;
/* Check if the signal requires a dump of thread information: */
if (sig == SIGINFO) {
/* Dump thread information to file: */
_thread_dump_info();
}
+
+ /* Check the threads previous state: */
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
+ thr_sigframe_save(curthread, &psf);
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+
_kse_critical_enter();
/* Get a fresh copy of signal mask */
__sys_sigprocmask(SIG_BLOCK, NULL, &curthread->sigmask);
@@ -395,14 +402,16 @@ _thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
#endif
}
}
- errno = err_save;
- curthread->timeout = timeout_save;
- curthread->interrupted = intr_save;
_kse_critical_enter();
curthread->sigmask = ucp->uc_sigmask;
SIG_CANTMASK(curthread->sigmask);
_kse_critical_leave(&curthread->tcb->tcb_tmbx);
+
+ thr_sigframe_restore(curthread, &psf);
+
DBG_MSG("<<< _thr_sig_handler(%d)\n", sig);
+
+ errno = err_save;
}
struct sighandle_info {
@@ -439,7 +448,7 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
if (!_kse_in_critical())
PANIC("thr_sig_invoke_handler without in critical\n");
- curkse = _get_curkse();
+ curkse = curthread->kse;
/*
* Check that a custom handler is installed and if
* the signal is not blocked:
@@ -491,7 +500,7 @@ thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info,
_kse_critical_enter();
/* Don't trust after critical leave/enter */
- curkse = _get_curkse();
+ curkse = curthread->kse;
/*
* Restore the thread's signal mask.
@@ -752,7 +761,7 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info)
}
#endif /* ! SYSTEM_SCOPE_ONLY */
-static void
+static inline void
build_siginfo(siginfo_t *info, int signo)
{
bzero(info, sizeof(*info));
@@ -765,54 +774,35 @@ build_siginfo(siginfo_t *info, int signo)
* It should only be called from the context of the thread.
*/
void
-_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
- struct pthread_sigframe *psf)
+_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp)
{
- int interrupted = curthread->interrupted;
- int timeout = curthread->timeout;
+ struct pthread_sigframe psf;
siginfo_t siginfo;
- int i;
+ int i, err_save;
kse_critical_t crit;
struct kse *curkse;
sigset_t sigmask;
+ err_save = errno;
+
DBG_MSG(">>> thr_sig_rundown (%p)\n", curthread);
+
/* Check the threads previous state: */
- if ((psf != NULL) && (psf->psf_valid != 0)) {
- /*
- * Do a little cleanup handling for those threads in
- * queues before calling the signal handler. Signals
- * for these threads are temporarily blocked until
- * after cleanup handling.
- */
- switch (psf->psf_state) {
- case PS_COND_WAIT:
- _cond_wait_backout(curthread);
- psf->psf_state = PS_RUNNING;
- break;
-
- case PS_MUTEX_WAIT:
- _mutex_lock_backout(curthread);
- psf->psf_state = PS_RUNNING;
- break;
-
- case PS_RUNNING:
- break;
+ curthread->critical_count++;
+ if (curthread->sigbackout != NULL)
+ curthread->sigbackout((void *)curthread);
+ curthread->critical_count--;
- default:
- psf->psf_state = PS_RUNNING;
- break;
- }
- /* XXX see comment in thr_sched_switch_unlocked */
- curthread->critical_count--;
- }
+ THR_ASSERT(!(curthread->sigbackout), "sigbackout was not cleared.");
+ THR_ASSERT((curthread->state == PS_RUNNING), "state is not PS_RUNNING");
+ thr_sigframe_save(curthread, &psf);
/*
* Lower the priority before calling the handler in case
* it never returns (longjmps back):
*/
crit = _kse_critical_enter();
- curkse = _get_curkse();
+ curkse = curthread->kse;
KSE_SCHED_LOCK(curkse, curkse->k_kseg);
KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
curthread->active_priority &= ~THR_SIGNAL_PRIORITY;
@@ -851,9 +841,8 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
}
}
- if (psf != NULL && psf->psf_valid != 0)
- thr_sigframe_restore(curthread, psf);
- curkse = _get_curkse();
+ /* Don't trust after signal handling */
+ curkse = curthread->kse;
KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
KSE_SCHED_UNLOCK(curkse, curkse->k_kseg);
_kse_critical_leave(&curthread->tcb->tcb_tmbx);
@@ -875,10 +864,10 @@ _thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp,
}
__sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL);
}
- curthread->interrupted = interrupted;
- curthread->timeout = timeout;
-
DBG_MSG("<<< thr_sig_rundown (%p)\n", curthread);
+
+ thr_sigframe_restore(curthread, &psf);
+ errno = err_save;
}
/*
@@ -897,7 +886,15 @@ _thr_sig_check_pending(struct pthread *curthread)
volatile int once;
int errsave;
- if (THR_IN_CRITICAL(curthread))
+ /*
+ * If the thread is in critical region, delay processing signals.
+ * If the thread state is not PS_RUNNING, it might be switching
+ * into UTS and but a THR_LOCK_RELEASE saw check_pending, and it
+ * goes here, in the case we delay processing signals, lets UTS
+ * process complicated things, normally UTS will call _thr_sig_add
+ * to resume the thread, so we needn't repeat doing it here.
+ */
+ if (THR_IN_CRITICAL(curthread) || curthread->state != PS_RUNNING)
return;
errsave = errno;
@@ -906,42 +903,11 @@ _thr_sig_check_pending(struct pthread *curthread)
if (once == 0) {
once = 1;
curthread->check_pending = 0;
- _thr_sig_rundown(curthread, &uc, NULL);
+ _thr_sig_rundown(curthread, &uc);
}
errno = errsave;
}
-#ifndef SYSTEM_SCOPE_ONLY
-/*
- * This must be called with upcalls disabled.
- */
-static void
-handle_special_signals(struct kse *curkse, int sig)
-{
- switch (sig) {
- /*
- * POSIX says that pending SIGCONT signals are
- * discarded when one of these signals occurs.
- */
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- SIGDELSET(_thr_proc_sigpending, SIGCONT);
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- break;
- case SIGCONT:
- KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock);
- SIGDELSET(_thr_proc_sigpending, SIGTSTP);
- SIGDELSET(_thr_proc_sigpending, SIGTTIN);
- SIGDELSET(_thr_proc_sigpending, SIGTTOU);
- KSE_LOCK_RELEASE(curkse, &_thread_signal_lock);
- default:
- break;
- }
-}
-#endif /* ! SYSTEM_SCOPE_ONLY */
-
/*
* Perform thread specific actions in response to a signal.
* This function is only called if there is a handler installed
@@ -979,11 +945,9 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
return (NULL);
}
- if (pthread->curframe == NULL ||
- (pthread->state != PS_SIGWAIT &&
- SIGISMEMBER(pthread->sigmask, sig)) ||
- THR_IN_CRITICAL(pthread)) {
- /* thread is running or signal was being masked */
+ if (pthread->state != PS_SIGWAIT &&
+ SIGISMEMBER(pthread->sigmask, sig)) {
+ /* signal is masked, just add signal to thread. */
if (!fromproc) {
SIGADDSET(pthread->sigpend, sig);
if (info == NULL)
@@ -996,19 +960,6 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
return (NULL);
SIGADDSET(pthread->sigpend, sig);
}
- if (!SIGISMEMBER(pthread->sigmask, sig)) {
- /* A quick path to exit process */
- if (sigfunc == SIG_DFL && sigprop(sig) & SA_KILL) {
- kse_thr_interrupt(NULL, KSE_INTR_SIGEXIT, sig);
- /* Never reach */
- }
- pthread->check_pending = 1;
- if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
- (pthread->blocked != 0) &&
- !THR_IN_CRITICAL(pthread))
- kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
- restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
- }
}
else {
/* if process signal not exists, just return */
@@ -1049,7 +1000,6 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
/* Possible not in RUNQ and has curframe ? */
pthread->active_priority |= THR_SIGNAL_PRIORITY;
}
- suppress_handler = 1;
break;
/*
* States which cannot be interrupted but still require the
@@ -1115,19 +1065,22 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info)
build_siginfo(&pthread->siginfo[sig-1], sig);
else if (info != &pthread->siginfo[sig-1])
memcpy(&pthread->siginfo[sig-1], info, sizeof(*info));
-
+ pthread->check_pending = 1;
+ if (!(pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) &&
+ (pthread->blocked != 0) && !THR_IN_CRITICAL(pthread))
+ kse_thr_interrupt(&pthread->tcb->tcb_tmbx,
+ restart ? KSE_INTR_RESTART : KSE_INTR_INTERRUPT, 0);
if (suppress_handler == 0) {
/*
* Setup a signal frame and save the current threads
* state:
*/
- thr_sigframe_add(pthread);
- if (pthread->flags & THR_FLAGS_IN_RUNQ)
- THR_RUNQ_REMOVE(pthread);
- pthread->active_priority |= THR_SIGNAL_PRIORITY;
- kmbx = _thr_setrunnable_unlocked(pthread);
- } else {
- pthread->check_pending = 1;
+ if (pthread->state != PS_RUNNING) {
+ if (pthread->flags & THR_FLAGS_IN_RUNQ)
+ THR_RUNQ_REMOVE(pthread);
+ pthread->active_priority |= THR_SIGNAL_PRIORITY;
+ kmbx = _thr_setrunnable_unlocked(pthread);
+ }
}
}
return (kmbx);
@@ -1151,6 +1104,10 @@ _thr_sig_send(struct pthread *pthread, int sig)
THR_SCHED_LOCK(curthread, pthread);
if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
kmbx = _thr_sig_add(pthread, sig, NULL);
+ /* Add a preemption point. */
+ if (kmbx == NULL && (curthread->kseg == pthread->kseg) &&
+ (pthread->active_priority > curthread->active_priority))
+ curthread->critical_yield = 1;
THR_SCHED_UNLOCK(curthread, pthread);
if (kmbx != NULL)
kse_wakeup(kmbx);
@@ -1161,52 +1118,55 @@ _thr_sig_send(struct pthread *pthread, int sig)
*/
if (pthread == curthread && curthread->check_pending)
_thr_sig_check_pending(curthread);
+
} else {
THR_SCHED_UNLOCK(curthread, pthread);
}
}
-static void
-thr_sigframe_add(struct pthread *thread)
+static inline void
+thr_sigframe_restore(struct pthread *curthread, struct pthread_sigframe *psf)
{
- if (thread->curframe == NULL)
- PANIC("Thread doesn't have signal frame ");
+ kse_critical_t crit;
+ struct kse *curkse;
- if (thread->curframe->psf_valid == 0) {
- thread->curframe->psf_valid = 1;
- /*
- * Multiple signals can be added to the same signal
- * frame. Only save the thread's state the first time.
- */
- thr_sigframe_save(thread, thread->curframe);
- }
+ THR_THREAD_LOCK(curthread, curthread);
+ curthread->cancelflags = psf->psf_cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
+ curthread->flags = psf->psf_flags;
+ curthread->interrupted = psf->psf_interrupted;
+ curthread->timeout = psf->psf_timeout;
+ curthread->data = psf->psf_wait_data;
+ curthread->wakeup_time = psf->psf_wakeup_time;
+ curthread->continuation = psf->psf_continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
}
-static void
-thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf)
+static inline void
+thr_sigframe_save(struct pthread *curthread, struct pthread_sigframe *psf)
{
- if (psf->psf_valid == 0)
- PANIC("invalid pthread_sigframe\n");
- thread->flags = psf->psf_flags;
- thread->cancelflags = psf->psf_cancelflags;
- thread->interrupted = psf->psf_interrupted;
- thread->timeout = psf->psf_timeout;
- thread->state = psf->psf_state;
- thread->data = psf->psf_wait_data;
- thread->wakeup_time = psf->psf_wakeup_time;
-}
+ kse_critical_t crit;
+ struct kse *curkse;
-static void
-thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf)
-{
+ THR_THREAD_LOCK(curthread, curthread);
+ psf->psf_cancelflags = curthread->cancelflags;
+ crit = _kse_critical_enter();
+ curkse = curthread->kse;
+ KSE_SCHED_LOCK(curkse, curthread->kseg);
/* This has to initialize all members of the sigframe. */
- psf->psf_flags = thread->flags & THR_FLAGS_PRIVATE;
- psf->psf_cancelflags = thread->cancelflags;
- psf->psf_interrupted = thread->interrupted;
- psf->psf_timeout = thread->timeout;
- psf->psf_state = thread->state;
- psf->psf_wait_data = thread->data;
- psf->psf_wakeup_time = thread->wakeup_time;
+ psf->psf_flags = (curthread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_EXITING));
+ psf->psf_interrupted = curthread->interrupted;
+ psf->psf_timeout = curthread->timeout;
+ psf->psf_wait_data = curthread->data;
+ psf->psf_wakeup_time = curthread->wakeup_time;
+ psf->psf_continuation = curthread->continuation;
+ KSE_SCHED_UNLOCK(curkse, curthread->kseg);
+ _kse_critical_leave(crit);
+ THR_THREAD_UNLOCK(curthread, curthread);
}
void
@@ -1266,6 +1226,9 @@ _thr_signal_deinit(void)
int i;
struct pthread *curthread = _get_curthread();
+ /* Clear process pending signals. */
+ sigemptyset(&_thr_proc_sigpending);
+
/* Enter a loop to get the existing signal status: */
for (i = 1; i <= _SIG_MAXSIG; i++) {
/* Check for signals which cannot be trapped: */
diff --git a/lib/libpthread/thread/thr_sigsuspend.c b/lib/libpthread/thread/thr_sigsuspend.c
index b7802e3..ede45b5 100644
--- a/lib/libpthread/thread/thr_sigsuspend.c
+++ b/lib/libpthread/thread/thr_sigsuspend.c
@@ -69,6 +69,7 @@ _sigsuspend(const sigset_t *set)
/* Wait for a signal: */
_thr_sched_switch_unlocked(curthread);
} else {
+ curthread->check_pending = 1;
THR_UNLOCK_SWITCH(curthread);
/* check pending signal I can handle: */
_thr_sig_check_pending(curthread);
diff --git a/lib/libpthread/thread/thr_spinlock.c b/lib/libpthread/thread/thr_spinlock.c
index deaeb9b..2b2b251 100644
--- a/lib/libpthread/thread/thr_spinlock.c
+++ b/lib/libpthread/thread/thr_spinlock.c
@@ -49,6 +49,10 @@ struct spinlock_extra {
static void init_spinlock(spinlock_t *lck);
+static struct pthread_mutex_attr static_mutex_attr =
+ PTHREAD_MUTEXATTR_STATIC_INITIALIZER;
+static pthread_mutexattr_t static_mattr = &static_mutex_attr;
+
static pthread_mutex_t spinlock_static_lock;
static struct spinlock_extra extra[MAX_SPINLOCKS];
static int spinlock_count = 0;
@@ -65,7 +69,7 @@ _spinunlock(spinlock_t *lck)
struct spinlock_extra *extra;
extra = (struct spinlock_extra *)lck->fname;
- pthread_mutex_unlock(&extra->lock);
+ _pthread_mutex_unlock(&extra->lock);
}
/*
@@ -90,7 +94,7 @@ _spinlock(spinlock_t *lck)
if (lck->fname == NULL)
init_spinlock(lck);
extra = (struct spinlock_extra *)lck->fname;
- pthread_mutex_lock(&extra->lock);
+ _pthread_mutex_lock(&extra->lock);
}
/*
@@ -112,13 +116,13 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
static void
init_spinlock(spinlock_t *lck)
{
- pthread_mutex_lock(&spinlock_static_lock);
+ _pthread_mutex_lock(&spinlock_static_lock);
if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
lck->fname = (char *)&extra[spinlock_count];
extra[spinlock_count].owner = lck;
spinlock_count++;
}
- pthread_mutex_unlock(&spinlock_static_lock);
+ _pthread_mutex_unlock(&spinlock_static_lock);
if (lck->fname == NULL)
PANIC("Exceeded max spinlocks");
}
@@ -133,10 +137,10 @@ _thr_spinlock_init(void)
for (i = 0; i < spinlock_count; i++)
_thr_mutex_reinit(&extra[i].lock);
} else {
- if (pthread_mutex_init(&spinlock_static_lock, NULL))
+ if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr))
PANIC("Cannot initialize spinlock_static_lock");
for (i = 0; i < MAX_SPINLOCKS; i++) {
- if (pthread_mutex_init(&extra[i].lock, NULL))
+ if (_pthread_mutex_init(&extra[i].lock, &static_mattr))
PANIC("Cannot initialize spinlock extra");
}
initialized = 1;
OpenPOWER on IntegriCloud