Index: sys/thr_error.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/sys/thr_error.c,v retrieving revision 1.7 diff -u -r1.7 thr_error.c --- sys/thr_error.c 23 Apr 2003 21:46:50 -0000 1.7 +++ sys/thr_error.c 6 Nov 2004 05:51:40 -0000 @@ -37,6 +37,7 @@ #include "libc_private.h" #include "thr_private.h" +#undef errno extern int errno; int * Index: thread/thr_cancel.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_cancel.c,v retrieving revision 1.31 diff -u -r1.31 thr_cancel.c --- thread/thr_cancel.c 9 Dec 2003 02:20:56 -0000 1.31 +++ thread/thr_cancel.c 6 Nov 2004 05:51:41 -0000 @@ -14,15 +14,24 @@ 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); Index: thread/thr_concurrency.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_concurrency.c,v retrieving revision 1.8 diff -u -r1.8 thr_concurrency.c --- thread/thr_concurrency.c 14 Mar 2004 05:24:27 -0000 1.8 +++ thread/thr_concurrency.c 6 Nov 2004 05:51:41 -0000 @@ -84,6 +84,13 @@ 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. */ Index: thread/thr_cond.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_cond.c,v retrieving revision 1.51 diff -u -r1.51 thr_cond.c --- thread/thr_cond.c 9 Dec 2003 02:20:56 -0000 1.51 +++ thread/thr_cond.c 6 Nov 2004 05:51:41 -0000 @@ -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 @@ 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 @@ * 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 @@ 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,15 @@ */ cond_queue_enq(*cond, curthread); - /* Remember the mutex and sequence number: */ + /* Remember the mutex: */ (*cond)->c_mutex = *mutex; - seqno = (*cond)->c_seqno; + curthread->sigbackout = cond_wait_backout; /* 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,13 +249,11 @@ * variable queue: */ cond_queue_remove(*cond, curthread); + curthread->sigbackout = NULL; /* 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 { /* @@ -264,7 +262,7 @@ * thread has to be requeued after * handling a signal). */ - unlock_mutex = 0; + mutex_locked = 0; /* * This thread is active and is in a @@ -286,8 +284,6 @@ /* 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 +295,39 @@ * 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 this. */ - 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 +335,21 @@ /* 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 +375,7 @@ 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 +403,11 @@ * 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 +425,6 @@ ((*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; @@ -449,10 +443,10 @@ /* Remember the mutex and sequence number: */ (*cond)->c_mutex = *mutex; - seqno = (*cond)->c_seqno; + curthread->sigbackout = cond_wait_backout; /* Unlock the mutex: */ - if ((unlock_mutex != 0) && + if (mutex_locked && ((rval = _mutex_cv_unlock(mutex)) != 0)) { /* * Cannot unlock the mutex; remove the @@ -460,13 +454,11 @@ * variable queue: */ cond_queue_remove(*cond, curthread); + curthread->sigbackout = NULL; /* 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 { /* * Don't unlock the mutex the next @@ -474,7 +466,7 @@ * thread has to be requeued after * handling a signal). */ - unlock_mutex = 0; + mutex_locked = 0; /* * This thread is active and is in a @@ -496,8 +488,6 @@ /* 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 +499,45 @@ * 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 this. */ - 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 +545,21 @@ /* 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 +615,7 @@ != 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 +682,7 @@ != 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,15 +714,38 @@ __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; if (cond != NULL) { /* Lock the condition variable structure: */ THR_LOCK_ACQUIRE(curthread, &cond->c_lock); + curthread->data.cond = NULL; /* Process according to condition variable type: */ switch (cond->c_type) { @@ -740,6 +765,8 @@ /* Unlock the condition variable structure: */ THR_LOCK_RELEASE(curthread, &cond->c_lock); } + /* No need to call this again. */ + curthread->sigbackout = NULL; } /* Index: thread/thr_create.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_create.c,v retrieving revision 1.58 diff -u -r1.58 thr_create.c --- thread/thr_create.c 23 Oct 2004 23:28:36 -0000 1.58 +++ thread/thr_create.c 6 Nov 2004 05:51:41 -0000 @@ -171,9 +171,6 @@ /* 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 @@ 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; Index: thread/thr_init.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_init.c,v retrieving revision 1.66 diff -u -r1.66 thr_init.c --- thread/thr_init.c 21 Aug 2004 11:49:19 -0000 1.66 +++ thread/thr_init.c 6 Nov 2004 05:51:41 -0000 @@ -391,6 +391,7 @@ thread->specific = NULL; thread->cleanup = NULL; thread->flags = 0; + thread->sigbackout = NULL; thread->continuation = NULL; thread->state = PS_RUNNING; Index: thread/thr_kern.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_kern.c,v retrieving revision 1.115 diff -u -r1.115 thr_kern.c --- thread/thr_kern.c 23 Oct 2004 23:28:36 -0000 1.115 +++ thread/thr_kern.c 6 Nov 2004 05:51:42 -0000 @@ -165,8 +165,7 @@ 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); @@ -615,13 +614,12 @@ 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 +627,6 @@ /* 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 +648,11 @@ } /* - * 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 +661,14 @@ /* * 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 +869,6 @@ } } - /* 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 +903,6 @@ { struct kse *curkse; struct pthread *curthread, *td_wait; - struct pthread_sigframe *curframe; int ret; curkse = (struct kse *)kmbx->km_udata; @@ -1085,10 +1062,6 @@ /* 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 +1069,7 @@ * 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 +1109,10 @@ 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 +1122,9 @@ } 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(); Index: thread/thr_mutex.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_mutex.c,v retrieving revision 1.46 diff -u -r1.46 thr_mutex.c --- thread/thr_mutex.c 31 Oct 2004 05:03:50 -0000 1.46 +++ thread/thr_mutex.c 6 Nov 2004 05:51:43 -0000 @@ -85,7 +85,7 @@ 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; @@ -539,6 +539,7 @@ */ 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 +555,17 @@ /* 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; @@ -613,6 +619,7 @@ */ 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 +640,17 @@ /* 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; @@ -702,6 +714,7 @@ */ mutex_queue_enq(*m, curthread); curthread->data.mutex = *m; + curthread->sigbackout = mutex_lock_backout; /* Clear any previous error: */ curthread->error = 0; @@ -728,6 +741,12 @@ 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 @@ -1511,9 +1530,10 @@ * 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) { @@ -1530,7 +1550,7 @@ /* Lock the mutex structure: */ THR_LOCK_ACQUIRE(curthread, &m->m_lock); - + curthread->data.mutex = NULL; /* * Check to make sure this thread doesn't already own @@ -1554,6 +1574,8 @@ THR_LOCK_RELEASE(curthread, &m->m_lock); } } + /* No need to call this again. */ + curthread->sigbackout = NULL; } /* Index: thread/thr_private.h =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_private.h,v retrieving revision 1.120 diff -u -r1.120 thr_private.h --- thread/thr_private.h 1 Nov 2004 10:49:34 -0000 1.120 +++ thread/thr_private.h 6 Nov 2004 05:51:43 -0000 @@ -573,6 +573,7 @@ sigset_t psf_sigset; sigset_t psf_sigmask; int psf_seqno; + thread_continuation_t psf_continuation; }; struct join_status { @@ -645,8 +646,8 @@ /* * 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 +1071,6 @@ */ __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 +1085,6 @@ 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 +1147,7 @@ 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); Index: thread/thr_sig.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_sig.c,v retrieving revision 1.82 diff -u -r1.82 thr_sig.c --- thread/thr_sig.c 1 Nov 2004 10:49:34 -0000 1.82 +++ thread/thr_sig.c 6 Nov 2004 05:51:44 -0000 @@ -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 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ #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 @@ 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 @@ _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 @@ } #endif /* ! SYSTEM_SCOPE_ONLY */ -static void +static inline void build_siginfo(siginfo_t *info, int signo) { bzero(info, sizeof(*info)); @@ -765,54 +774,35 @@ * 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 @@ } } - 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 @@ } __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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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_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 @@ */ 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 Index: thread/thr_sigsuspend.c =================================================================== RCS file: /home/ncvs/src/lib/libpthread/thread/thr_sigsuspend.c,v retrieving revision 1.24 diff -u -r1.24 thr_sigsuspend.c --- thread/thr_sigsuspend.c 12 Jun 2004 07:40:01 -0000 1.24 +++ thread/thr_sigsuspend.c 6 Nov 2004 05:51:44 -0000 @@ -69,9 +69,8 @@ /* 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); } THR_ASSERT(curthread->oldsigmask == NULL, "oldsigmask is not cleared");