diff options
author | deischen <deischen@FreeBSD.org> | 2003-07-23 02:11:07 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 2003-07-23 02:11:07 +0000 |
commit | 9f8651cad61cf131bd07594ac25f3cd102fe0159 (patch) | |
tree | 2ba938226cb9f3c751737df74c5cdf8e63cf8eba | |
parent | a8317490154f61e26d775ebd4480ec6333f94a75 (diff) | |
download | FreeBSD-src-9f8651cad61cf131bd07594ac25f3cd102fe0159.zip FreeBSD-src-9f8651cad61cf131bd07594ac25f3cd102fe0159.tar.gz |
Move idle kse wakeup to outside of regions where locks are held.
This eliminates ping-ponging of locks, where the idle KSE wakes
up only to find the lock it needs is being held. This gives
little or no gain to M:N mode but greatly speeds up 1:1 mode.
Reviewed & Tested by: davidxu
-rw-r--r-- | lib/libkse/thread/thr_cancel.c | 9 | ||||
-rw-r--r-- | lib/libkse/thread/thr_cond.c | 10 | ||||
-rw-r--r-- | lib/libkse/thread/thr_detach.c | 8 | ||||
-rw-r--r-- | lib/libkse/thread/thr_kern.c | 92 | ||||
-rw-r--r-- | lib/libkse/thread/thr_mutex.c | 18 | ||||
-rw-r--r-- | lib/libkse/thread/thr_private.h | 4 | ||||
-rw-r--r-- | lib/libkse/thread/thr_resume_np.c | 18 | ||||
-rw-r--r-- | lib/libkse/thread/thr_sig.c | 44 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_cancel.c | 9 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_cond.c | 10 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_detach.c | 8 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_kern.c | 92 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_mutex.c | 18 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_private.h | 4 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_resume_np.c | 18 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_sig.c | 44 |
16 files changed, 260 insertions, 146 deletions
diff --git a/lib/libkse/thread/thr_cancel.c b/lib/libkse/thread/thr_cancel.c index 731a9aa..581b719 100644 --- a/lib/libkse/thread/thr_cancel.c +++ b/lib/libkse/thread/thr_cancel.c @@ -20,6 +20,7 @@ _pthread_cancel(pthread_t pthread) { struct pthread *curthread = _get_curthread(); struct pthread *joinee = NULL; + struct kse_mailbox *kmbx = NULL; int ret; if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) { @@ -65,7 +66,7 @@ _pthread_cancel(pthread_t pthread) /* Interrupt and resume: */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCELLING; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); break; case PS_JOIN: @@ -73,7 +74,7 @@ _pthread_cancel(pthread_t pthread) joinee = pthread->join_status.thread; pthread->join_status.thread = NULL; pthread->cancelflags |= THR_CANCELLING; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); if ((joinee != NULL) && (pthread->kseg == joinee->kseg)) { /* Remove the joiner from the joinee. */ @@ -97,7 +98,7 @@ _pthread_cancel(pthread_t pthread) */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCEL_NEEDED; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); pthread->continuation = finish_cancellation; break; @@ -120,6 +121,8 @@ _pthread_cancel(pthread_t pthread) */ THR_SCHED_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); if ((joinee != NULL) && (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) { diff --git a/lib/libkse/thread/thr_cond.c b/lib/libkse/thread/thr_cond.c index 9703da6..0d6d914 100644 --- a/lib/libkse/thread/thr_cond.c +++ b/lib/libkse/thread/thr_cond.c @@ -584,6 +584,7 @@ _pthread_cond_signal(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; + struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, @@ -619,8 +620,10 @@ _pthread_cond_signal(pthread_cond_t * cond) (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Check for no more waiters: */ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) @@ -649,6 +652,7 @@ _pthread_cond_broadcast(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; + struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, @@ -682,8 +686,10 @@ _pthread_cond_broadcast(pthread_cond_t * cond) (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* There are no more waiting threads: */ diff --git a/lib/libkse/thread/thr_detach.c b/lib/libkse/thread/thr_detach.c index 0b63dac..0159e53 100644 --- a/lib/libkse/thread/thr_detach.c +++ b/lib/libkse/thread/thr_detach.c @@ -43,6 +43,7 @@ int _pthread_detach(pthread_t pthread) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx = NULL; struct pthread *joiner; int rval = 0; @@ -83,12 +84,11 @@ _pthread_detach(pthread_t pthread) joiner->join_status.ret = NULL; joiner->join_status.thread = NULL; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } joiner = NULL; } THR_SCHED_UNLOCK(curthread, pthread); - /* See if there is a thread waiting in pthread_join(): */ if ((joiner != NULL) && (_thr_ref_add(curthread, joiner, 0) == 0)) { @@ -102,12 +102,14 @@ _pthread_detach(pthread_t pthread) joiner->join_status.ret = NULL; joiner->join_status.thread = NULL; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } THR_SCHED_UNLOCK(curthread, joiner); _thr_ref_delete(curthread, joiner); } _thr_ref_delete(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Return the completion status: */ diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c index 51aab62..a08c677 100644 --- a/lib/libkse/thread/thr_kern.c +++ b/lib/libkse/thread/thr_kern.c @@ -142,7 +142,7 @@ static void kseg_init(struct kse_group *kseg); static void kseg_reinit(struct kse_group *kseg); static void kse_waitq_insert(struct pthread *thread); static void kse_wakeup_multi(struct kse *curkse); -static void kse_wakeup_one(struct pthread *thread); +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 *); @@ -341,7 +341,7 @@ _kse_single_thread(struct pthread *curthread) #else if (__isthreaded) _thr_signal_deinit(); - _ksd_readandclear_tmbx(); + _ksd_set_tmbx(NULL); __isthreaded = 0; active_threads = 0; #endif @@ -505,10 +505,9 @@ _thr_lock_wait(struct lock *lock, struct lockuser *lu) struct pthread *curthread = (struct pthread *)lu->lu_private; do { - THR_SCHED_LOCK(curthread, curthread); + THR_LOCK_SWITCH(curthread); THR_SET_STATE(curthread, PS_LOCKWAIT); - THR_SCHED_UNLOCK(curthread, curthread); - _thr_sched_switch(curthread); + _thr_sched_switch_unlocked(curthread); } while (!_LCK_GRANTED(lu)); } @@ -517,14 +516,17 @@ _thr_lock_wakeup(struct lock *lock, struct lockuser *lu) { struct pthread *thread; struct pthread *curthread; + struct kse_mailbox *kmbx; curthread = _get_curthread(); thread = (struct pthread *)_LCK_GET_PRIVATE(lu); THR_SCHED_LOCK(curthread, thread); _lock_grant(lock, lu); - _thr_setrunnable_unlocked(thread); + kmbx = _thr_setrunnable_unlocked(thread); THR_SCHED_UNLOCK(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } kse_critical_t @@ -532,7 +534,8 @@ _kse_critical_enter(void) { kse_critical_t crit; - crit = _ksd_readandclear_tmbx(); + crit = _ksd_get_tmbx(); + _ksd_set_tmbx(NULL); return (crit); } @@ -841,8 +844,8 @@ kse_sched_single(struct kse *curkse) if (SIGISMEMBER(curthread->sigmask, i)) continue; if (SIGISMEMBER(curthread->sigpend, i)) - _thr_sig_add(curthread, i, - &curthread->siginfo[i-1]); + (void)_thr_sig_add(curthread, i, + &curthread->siginfo[i-1]); } __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); @@ -1142,6 +1145,7 @@ static void thr_cleanup(struct kse *curkse, struct pthread *thread) { struct pthread *joiner; + struct kse_mailbox *kmbx = NULL; int sys_scope; if ((joiner = thread->joiner) != NULL) { @@ -1150,7 +1154,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread) if (joiner->join_status.thread == thread) { joiner->join_status.thread = NULL; joiner->join_status.ret = thread->ret; - _thr_setrunnable_unlocked(joiner); + (void)_thr_setrunnable_unlocked(joiner); } } else { KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); @@ -1160,10 +1164,12 @@ thr_cleanup(struct kse *curkse, struct pthread *thread) if (joiner->join_status.thread == thread) { joiner->join_status.thread = NULL; joiner->join_status.ret = thread->ret; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } KSE_SCHED_UNLOCK(curkse, joiner->kseg); _thr_ref_delete(thread, joiner); + if (kmbx != NULL) + kse_wakeup(kmbx); } KSE_SCHED_LOCK(curkse, curkse->k_kseg); } @@ -1436,7 +1442,8 @@ kse_check_completed(struct kse *kse) if (SIGISMEMBER(thread->sigmask, sig)) SIGADDSET(thread->sigpend, sig); else - _thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig); + (void)_thr_sig_add(thread, sig, + &thread->tmbx.tm_syncsig); thread->tmbx.tm_syncsig.si_signo = 0; } completed = completed->tm_next; @@ -1653,10 +1660,11 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread) if (SIGISMEMBER(thread->sigmask, i)) continue; if (SIGISMEMBER(thread->sigpend, i)) - _thr_sig_add(thread, i, &thread->siginfo[i-1]); + (void)_thr_sig_add(thread, i, + &thread->siginfo[i-1]); else if (SIGISMEMBER(_thr_proc_sigpending, i) && _thr_getprocsig_unlocked(i, &siginfo)) { - _thr_sig_add(thread, i, &siginfo); + (void)_thr_sig_add(thread, i, &siginfo); } } KSE_LOCK_RELEASE(kse, &_thread_signal_lock); @@ -1823,23 +1831,31 @@ void _thr_setrunnable(struct pthread *curthread, struct pthread *thread) { kse_critical_t crit; + struct kse_mailbox *kmbx; crit = _kse_critical_enter(); KSE_SCHED_LOCK(curthread->kse, thread->kseg); - _thr_setrunnable_unlocked(thread); + kmbx = _thr_setrunnable_unlocked(thread); KSE_SCHED_UNLOCK(curthread->kse, thread->kseg); _kse_critical_leave(crit); + if (kmbx != NULL) + kse_wakeup(kmbx); } -void +struct kse_mailbox * _thr_setrunnable_unlocked(struct pthread *thread) { + struct kse_mailbox *kmbx = NULL; + if ((thread->kseg->kg_flags & KGF_SINGLE_THREAD) != 0) { /* No silly queues for these threads. */ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0) THR_SET_STATE(thread, PS_SUSPENDED); - else + else { THR_SET_STATE(thread, PS_RUNNING); + kmbx = kse_wakeup_one(thread); + } + } else if (thread->state != PS_RUNNING) { if ((thread->flags & THR_FLAGS_IN_WAITQ) != 0) KSE_WAITQ_REMOVE(thread->kse, thread); @@ -1850,25 +1866,31 @@ _thr_setrunnable_unlocked(struct pthread *thread) if ((thread->blocked == 0) && (thread->active == 0) && (thread->flags & THR_FLAGS_IN_RUNQ) == 0) THR_RUNQ_INSERT_TAIL(thread); + /* + * XXX - Threads are not yet assigned to specific + * KSEs; they are assigned to the KSEG. So + * the fact that a thread's KSE is waiting + * doesn't necessarily mean that it will be + * the KSE that runs the thread after the + * lock is granted. But we don't know if the + * other KSEs within the same KSEG are also + * in a waiting state or not so we err on the + * side of caution and wakeup the thread's + * last known KSE. We ensure that the + * threads KSE doesn't change while it's + * scheduling lock is held so it is safe to + * reference it (the KSE). If the KSE wakes + * up and doesn't find any more work it will + * again go back to waiting so no harm is + * done. + */ + kmbx = kse_wakeup_one(thread); } } - /* - * XXX - Threads are not yet assigned to specific KSEs; they are - * assigned to the KSEG. So the fact that a thread's KSE is - * waiting doesn't necessarily mean that it will be the KSE - * that runs the thread after the lock is granted. But we - * don't know if the other KSEs within the same KSEG are - * also in a waiting state or not so we err on the side of - * caution and wakeup the thread's last known KSE. We - * ensure that the threads KSE doesn't change while it's - * scheduling lock is held so it is safe to reference it - * (the KSE). If the KSE wakes up and doesn't find any more - * work it will again go back to waiting so no harm is done. - */ - kse_wakeup_one(thread); + return (kmbx); } -static void +static struct kse_mailbox * kse_wakeup_one(struct pthread *thread) { struct kse *ke; @@ -1876,17 +1898,17 @@ kse_wakeup_one(struct pthread *thread) if (KSE_IS_IDLE(thread->kse)) { KSE_CLEAR_IDLE(thread->kse); thread->kseg->kg_idle_kses--; - KSE_WAKEUP(thread->kse); + return (&thread->kse->k_mbx); } else { TAILQ_FOREACH(ke, &thread->kseg->kg_kseq, k_kgqe) { if (KSE_IS_IDLE(ke)) { KSE_CLEAR_IDLE(ke); ke->k_kseg->kg_idle_kses--; - KSE_WAKEUP(ke); - return; + return (&ke->k_mbx); } } } + return (NULL); } static void diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c index c2c28e0..7e8de44 100644 --- a/lib/libkse/thread/thr_mutex.c +++ b/lib/libkse/thread/thr_mutex.c @@ -67,7 +67,8 @@ /* * Prototypes */ -static void mutex_handoff(struct pthread *, struct pthread_mutex *); +static struct kse_mailbox *mutex_handoff(struct pthread *, + struct pthread_mutex *); static inline int mutex_self_trylock(struct pthread *, pthread_mutex_t); static inline int mutex_self_lock(struct pthread *, pthread_mutex_t); static int mutex_unlock_common(pthread_mutex_t *, int); @@ -860,6 +861,7 @@ static int mutex_unlock_common(pthread_mutex_t *m, int add_reference) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx = NULL; int ret = 0; if (m == NULL || *m == NULL) @@ -904,7 +906,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -961,7 +963,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -1017,7 +1019,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -1034,6 +1036,8 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) /* Unlock the mutex structure: */ THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Return the completion status: */ @@ -1460,9 +1464,10 @@ _mutex_lock_backout(struct pthread *curthread) * is necessary to lock the thread's scheduling queue while also * holding the mutex lock. */ -static void +static struct kse_mailbox * mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) { + struct kse_mailbox *kmbx = NULL; struct pthread *pthread; /* Keep dequeueing until we find a valid thread: */ @@ -1564,7 +1569,7 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) } /* Make the thread runnable and unlock the scheduling queue: */ - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); /* Add a preemption point. */ if ((curthread->kseg == pthread->kseg) && @@ -1583,6 +1588,7 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT)) /* This mutex has no priority: */ mutex->m_prio = 0; + return (kmbx); } /* diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index 21026b7..90dbed7 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/thread/thr_private.h @@ -1106,8 +1106,8 @@ void _thr_ref_delete(struct pthread *, struct pthread *); int _thr_schedule_add(struct pthread *, struct pthread *); void _thr_schedule_remove(struct pthread *, struct pthread *); void _thr_setrunnable(struct pthread *curthread, struct pthread *thread); -void _thr_setrunnable_unlocked(struct pthread *thread); -void _thr_sig_add(struct pthread *, int, siginfo_t *); +struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread); +struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *); void _thr_sig_dispatch(struct kse *, int, siginfo_t *); int _thr_stack_alloc(struct pthread_attr *); void _thr_stack_free(struct pthread_attr *); diff --git a/lib/libkse/thread/thr_resume_np.c b/lib/libkse/thread/thr_resume_np.c index 1276311..ba9b911 100644 --- a/lib/libkse/thread/thr_resume_np.c +++ b/lib/libkse/thread/thr_resume_np.c @@ -35,7 +35,7 @@ #include <pthread.h> #include "thr_private.h" -static void resume_common(struct pthread *); +static struct kse_mailbox *resume_common(struct pthread *); __weak_reference(_pthread_resume_np, pthread_resume_np); __weak_reference(_pthread_resume_all_np, pthread_resume_all_np); @@ -46,15 +46,18 @@ int _pthread_resume_np(pthread_t thread) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx; int ret; /* Add a reference to the thread: */ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) { /* Lock the threads scheduling queue: */ THR_SCHED_LOCK(curthread, thread); - resume_common(thread); + kmbx = resume_common(thread); THR_SCHED_UNLOCK(curthread, thread); _thr_ref_delete(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } return (ret); } @@ -64,6 +67,7 @@ _pthread_resume_all_np(void) { struct pthread *curthread = _get_curthread(); struct pthread *thread; + struct kse_mailbox *kmbx; kse_critical_t crit; /* Take the thread list lock: */ @@ -73,8 +77,10 @@ _pthread_resume_all_np(void) TAILQ_FOREACH(thread, &_thread_list, tle) { if (thread != curthread) { THR_SCHED_LOCK(curthread, thread); - resume_common(thread); + kmbx = resume_common(thread); THR_SCHED_UNLOCK(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } } @@ -83,7 +89,7 @@ _pthread_resume_all_np(void) _kse_critical_leave(crit); } -static void +static struct kse_mailbox * resume_common(struct pthread *thread) { /* Clear the suspend flag: */ @@ -95,5 +101,7 @@ resume_common(struct pthread *thread) * state to running and insert it into the run queue. */ if (thread->state == PS_SUSPENDED) - _thr_setrunnable_unlocked(thread); + return (_thr_setrunnable_unlocked(thread)); + else + return (NULL); } diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c index 1211ba3..fc075af 100644 --- a/lib/libkse/thread/thr_sig.c +++ b/lib/libkse/thread/thr_sig.c @@ -249,6 +249,7 @@ _thr_start_sig_daemon(void) void _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) { + struct kse_mailbox *kmbx; struct pthread *thread; DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); @@ -280,9 +281,11 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) KSE_SCHED_UNLOCK(curkse, thread->kseg); _thr_ref_delete(NULL, thread); } else { - _thr_sig_add(thread, sig, info); + kmbx = _thr_sig_add(thread, sig, info); KSE_SCHED_UNLOCK(curkse, thread->kseg); _thr_ref_delete(NULL, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); break; } } @@ -533,6 +536,7 @@ _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) struct pthread * thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) { + struct kse_mailbox *kmbx = NULL; struct pthread *pthread; struct pthread *suspended_thread, *signaled_thread; __siginfohandler_t *sigfunc; @@ -582,7 +586,7 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) /* where to put siginfo ? */ *(pthread->data.sigwaitinfo) = si; pthread->sigmask = pthread->oldsigmask; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } KSE_SCHED_UNLOCK(curkse, pthread->kseg); /* @@ -596,6 +600,8 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) * to the process pending set. */ KSE_LOCK_RELEASE(curkse, &_thread_list_lock); + if (kmbx != NULL) + kse_wakeup(kmbx); return (NULL); } else if (!SIGISMEMBER(pthread->sigmask, sig) || (!SIGISMEMBER(pthread->oldsigmask, sig) && @@ -811,15 +817,16 @@ handle_special_signals(struct kse *curkse, int sig) * * This must be called with the thread's scheduling lock held. */ -void +struct kse_mailbox * _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) { + siginfo_t siginfo; + struct kse *curkse; + struct kse_mailbox *kmbx = NULL; + struct pthread *curthread = _get_curthread(); int restart; int suppress_handler = 0; int fromproc = 0; - struct pthread *curthread = _get_curthread(); - struct kse *curkse; - siginfo_t siginfo; DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig); @@ -829,12 +836,12 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || pthread->state == PS_STATE_MAX) - return; /* return false */ + return (NULL); /* return false */ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && (curthread != pthread)) { PANIC("Please use _thr_send_sig for bound thread"); - return; + return (NULL); } if (pthread->curframe == NULL || @@ -851,7 +858,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) sizeof(*info)); } else { if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1])) - return; + return (NULL); SIGADDSET(pthread->sigpend, sig); } if (!SIGISMEMBER(pthread->sigmask, sig)) { @@ -867,7 +874,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) /* if process signal not exists, just return */ if (fromproc) { if (!_thr_getprocsig(sig, &siginfo)) - return; + return (NULL); info = &siginfo; } /* @@ -877,7 +884,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) case PS_DEAD: case PS_DEADLOCK: case PS_STATE_MAX: - return; /* XXX return false */ + return (NULL); /* XXX return false */ case PS_LOCKWAIT: case PS_SUSPENDED: /* @@ -937,7 +944,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; pthread->sigmask = pthread->oldsigmask; /* Make the thread runnable: */ - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } else { /* Increment the pending signal count. */ SIGADDSET(pthread->sigpend, sig); @@ -945,11 +952,10 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) pthread->check_pending = 1; pthread->interrupted = 1; pthread->sigmask = pthread->oldsigmask; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } } - - return; + return (kmbx); } SIGADDSET(pthread->sigpend, sig); @@ -967,11 +973,12 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) if (pthread->flags & THR_FLAGS_IN_RUNQ) THR_RUNQ_REMOVE(pthread); pthread->active_priority |= THR_SIGNAL_PRIORITY; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } else { pthread->check_pending = 1; } } + return (kmbx); } /* @@ -981,6 +988,7 @@ void _thr_sig_send(struct pthread *pthread, int sig) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx; if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { kse_thr_interrupt(&pthread->tmbx, KSE_INTR_SENDSIG, sig); @@ -990,8 +998,10 @@ _thr_sig_send(struct pthread *pthread, int sig) /* Lock the scheduling queue of the target thread. */ THR_SCHED_LOCK(curthread, pthread); if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { - _thr_sig_add(pthread, sig, NULL); + kmbx = _thr_sig_add(pthread, sig, NULL); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); /* XXX * If thread sent signal to itself, check signals now. * It is not really needed, _kse_critical_leave should diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c index 731a9aa..581b719 100644 --- a/lib/libpthread/thread/thr_cancel.c +++ b/lib/libpthread/thread/thr_cancel.c @@ -20,6 +20,7 @@ _pthread_cancel(pthread_t pthread) { struct pthread *curthread = _get_curthread(); struct pthread *joinee = NULL; + struct kse_mailbox *kmbx = NULL; int ret; if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) == 0) { @@ -65,7 +66,7 @@ _pthread_cancel(pthread_t pthread) /* Interrupt and resume: */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCELLING; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); break; case PS_JOIN: @@ -73,7 +74,7 @@ _pthread_cancel(pthread_t pthread) joinee = pthread->join_status.thread; pthread->join_status.thread = NULL; pthread->cancelflags |= THR_CANCELLING; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); if ((joinee != NULL) && (pthread->kseg == joinee->kseg)) { /* Remove the joiner from the joinee. */ @@ -97,7 +98,7 @@ _pthread_cancel(pthread_t pthread) */ pthread->interrupted = 1; pthread->cancelflags |= THR_CANCEL_NEEDED; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); pthread->continuation = finish_cancellation; break; @@ -120,6 +121,8 @@ _pthread_cancel(pthread_t pthread) */ THR_SCHED_UNLOCK(curthread, pthread); _thr_ref_delete(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); if ((joinee != NULL) && (_thr_ref_add(curthread, joinee, /* include dead */1) == 0)) { diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c index 9703da6..0d6d914 100644 --- a/lib/libpthread/thread/thr_cond.c +++ b/lib/libpthread/thread/thr_cond.c @@ -584,6 +584,7 @@ _pthread_cond_signal(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; + struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, @@ -619,8 +620,10 @@ _pthread_cond_signal(pthread_cond_t * cond) (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Check for no more waiters: */ if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) @@ -649,6 +652,7 @@ _pthread_cond_broadcast(pthread_cond_t * cond) { struct pthread *curthread = _get_curthread(); struct pthread *pthread; + struct kse_mailbox *kmbx; int rval = 0; THR_ASSERT(curthread->locklevel == 0, @@ -682,8 +686,10 @@ _pthread_cond_broadcast(pthread_cond_t * cond) (pthread->active_priority > curthread->active_priority)) curthread->critical_yield = 1; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* There are no more waiting threads: */ diff --git a/lib/libpthread/thread/thr_detach.c b/lib/libpthread/thread/thr_detach.c index 0b63dac..0159e53 100644 --- a/lib/libpthread/thread/thr_detach.c +++ b/lib/libpthread/thread/thr_detach.c @@ -43,6 +43,7 @@ int _pthread_detach(pthread_t pthread) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx = NULL; struct pthread *joiner; int rval = 0; @@ -83,12 +84,11 @@ _pthread_detach(pthread_t pthread) joiner->join_status.ret = NULL; joiner->join_status.thread = NULL; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } joiner = NULL; } THR_SCHED_UNLOCK(curthread, pthread); - /* See if there is a thread waiting in pthread_join(): */ if ((joiner != NULL) && (_thr_ref_add(curthread, joiner, 0) == 0)) { @@ -102,12 +102,14 @@ _pthread_detach(pthread_t pthread) joiner->join_status.ret = NULL; joiner->join_status.thread = NULL; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } THR_SCHED_UNLOCK(curthread, joiner); _thr_ref_delete(curthread, joiner); } _thr_ref_delete(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Return the completion status: */ diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 51aab62..a08c677 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -142,7 +142,7 @@ static void kseg_init(struct kse_group *kseg); static void kseg_reinit(struct kse_group *kseg); static void kse_waitq_insert(struct pthread *thread); static void kse_wakeup_multi(struct kse *curkse); -static void kse_wakeup_one(struct pthread *thread); +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 *); @@ -341,7 +341,7 @@ _kse_single_thread(struct pthread *curthread) #else if (__isthreaded) _thr_signal_deinit(); - _ksd_readandclear_tmbx(); + _ksd_set_tmbx(NULL); __isthreaded = 0; active_threads = 0; #endif @@ -505,10 +505,9 @@ _thr_lock_wait(struct lock *lock, struct lockuser *lu) struct pthread *curthread = (struct pthread *)lu->lu_private; do { - THR_SCHED_LOCK(curthread, curthread); + THR_LOCK_SWITCH(curthread); THR_SET_STATE(curthread, PS_LOCKWAIT); - THR_SCHED_UNLOCK(curthread, curthread); - _thr_sched_switch(curthread); + _thr_sched_switch_unlocked(curthread); } while (!_LCK_GRANTED(lu)); } @@ -517,14 +516,17 @@ _thr_lock_wakeup(struct lock *lock, struct lockuser *lu) { struct pthread *thread; struct pthread *curthread; + struct kse_mailbox *kmbx; curthread = _get_curthread(); thread = (struct pthread *)_LCK_GET_PRIVATE(lu); THR_SCHED_LOCK(curthread, thread); _lock_grant(lock, lu); - _thr_setrunnable_unlocked(thread); + kmbx = _thr_setrunnable_unlocked(thread); THR_SCHED_UNLOCK(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } kse_critical_t @@ -532,7 +534,8 @@ _kse_critical_enter(void) { kse_critical_t crit; - crit = _ksd_readandclear_tmbx(); + crit = _ksd_get_tmbx(); + _ksd_set_tmbx(NULL); return (crit); } @@ -841,8 +844,8 @@ kse_sched_single(struct kse *curkse) if (SIGISMEMBER(curthread->sigmask, i)) continue; if (SIGISMEMBER(curthread->sigpend, i)) - _thr_sig_add(curthread, i, - &curthread->siginfo[i-1]); + (void)_thr_sig_add(curthread, i, + &curthread->siginfo[i-1]); } __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); @@ -1142,6 +1145,7 @@ static void thr_cleanup(struct kse *curkse, struct pthread *thread) { struct pthread *joiner; + struct kse_mailbox *kmbx = NULL; int sys_scope; if ((joiner = thread->joiner) != NULL) { @@ -1150,7 +1154,7 @@ thr_cleanup(struct kse *curkse, struct pthread *thread) if (joiner->join_status.thread == thread) { joiner->join_status.thread = NULL; joiner->join_status.ret = thread->ret; - _thr_setrunnable_unlocked(joiner); + (void)_thr_setrunnable_unlocked(joiner); } } else { KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); @@ -1160,10 +1164,12 @@ thr_cleanup(struct kse *curkse, struct pthread *thread) if (joiner->join_status.thread == thread) { joiner->join_status.thread = NULL; joiner->join_status.ret = thread->ret; - _thr_setrunnable_unlocked(joiner); + kmbx = _thr_setrunnable_unlocked(joiner); } KSE_SCHED_UNLOCK(curkse, joiner->kseg); _thr_ref_delete(thread, joiner); + if (kmbx != NULL) + kse_wakeup(kmbx); } KSE_SCHED_LOCK(curkse, curkse->k_kseg); } @@ -1436,7 +1442,8 @@ kse_check_completed(struct kse *kse) if (SIGISMEMBER(thread->sigmask, sig)) SIGADDSET(thread->sigpend, sig); else - _thr_sig_add(thread, sig, &thread->tmbx.tm_syncsig); + (void)_thr_sig_add(thread, sig, + &thread->tmbx.tm_syncsig); thread->tmbx.tm_syncsig.si_signo = 0; } completed = completed->tm_next; @@ -1653,10 +1660,11 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread) if (SIGISMEMBER(thread->sigmask, i)) continue; if (SIGISMEMBER(thread->sigpend, i)) - _thr_sig_add(thread, i, &thread->siginfo[i-1]); + (void)_thr_sig_add(thread, i, + &thread->siginfo[i-1]); else if (SIGISMEMBER(_thr_proc_sigpending, i) && _thr_getprocsig_unlocked(i, &siginfo)) { - _thr_sig_add(thread, i, &siginfo); + (void)_thr_sig_add(thread, i, &siginfo); } } KSE_LOCK_RELEASE(kse, &_thread_signal_lock); @@ -1823,23 +1831,31 @@ void _thr_setrunnable(struct pthread *curthread, struct pthread *thread) { kse_critical_t crit; + struct kse_mailbox *kmbx; crit = _kse_critical_enter(); KSE_SCHED_LOCK(curthread->kse, thread->kseg); - _thr_setrunnable_unlocked(thread); + kmbx = _thr_setrunnable_unlocked(thread); KSE_SCHED_UNLOCK(curthread->kse, thread->kseg); _kse_critical_leave(crit); + if (kmbx != NULL) + kse_wakeup(kmbx); } -void +struct kse_mailbox * _thr_setrunnable_unlocked(struct pthread *thread) { + struct kse_mailbox *kmbx = NULL; + if ((thread->kseg->kg_flags & KGF_SINGLE_THREAD) != 0) { /* No silly queues for these threads. */ if ((thread->flags & THR_FLAGS_SUSPENDED) != 0) THR_SET_STATE(thread, PS_SUSPENDED); - else + else { THR_SET_STATE(thread, PS_RUNNING); + kmbx = kse_wakeup_one(thread); + } + } else if (thread->state != PS_RUNNING) { if ((thread->flags & THR_FLAGS_IN_WAITQ) != 0) KSE_WAITQ_REMOVE(thread->kse, thread); @@ -1850,25 +1866,31 @@ _thr_setrunnable_unlocked(struct pthread *thread) if ((thread->blocked == 0) && (thread->active == 0) && (thread->flags & THR_FLAGS_IN_RUNQ) == 0) THR_RUNQ_INSERT_TAIL(thread); + /* + * XXX - Threads are not yet assigned to specific + * KSEs; they are assigned to the KSEG. So + * the fact that a thread's KSE is waiting + * doesn't necessarily mean that it will be + * the KSE that runs the thread after the + * lock is granted. But we don't know if the + * other KSEs within the same KSEG are also + * in a waiting state or not so we err on the + * side of caution and wakeup the thread's + * last known KSE. We ensure that the + * threads KSE doesn't change while it's + * scheduling lock is held so it is safe to + * reference it (the KSE). If the KSE wakes + * up and doesn't find any more work it will + * again go back to waiting so no harm is + * done. + */ + kmbx = kse_wakeup_one(thread); } } - /* - * XXX - Threads are not yet assigned to specific KSEs; they are - * assigned to the KSEG. So the fact that a thread's KSE is - * waiting doesn't necessarily mean that it will be the KSE - * that runs the thread after the lock is granted. But we - * don't know if the other KSEs within the same KSEG are - * also in a waiting state or not so we err on the side of - * caution and wakeup the thread's last known KSE. We - * ensure that the threads KSE doesn't change while it's - * scheduling lock is held so it is safe to reference it - * (the KSE). If the KSE wakes up and doesn't find any more - * work it will again go back to waiting so no harm is done. - */ - kse_wakeup_one(thread); + return (kmbx); } -static void +static struct kse_mailbox * kse_wakeup_one(struct pthread *thread) { struct kse *ke; @@ -1876,17 +1898,17 @@ kse_wakeup_one(struct pthread *thread) if (KSE_IS_IDLE(thread->kse)) { KSE_CLEAR_IDLE(thread->kse); thread->kseg->kg_idle_kses--; - KSE_WAKEUP(thread->kse); + return (&thread->kse->k_mbx); } else { TAILQ_FOREACH(ke, &thread->kseg->kg_kseq, k_kgqe) { if (KSE_IS_IDLE(ke)) { KSE_CLEAR_IDLE(ke); ke->k_kseg->kg_idle_kses--; - KSE_WAKEUP(ke); - return; + return (&ke->k_mbx); } } } + return (NULL); } static void diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c index c2c28e0..7e8de44 100644 --- a/lib/libpthread/thread/thr_mutex.c +++ b/lib/libpthread/thread/thr_mutex.c @@ -67,7 +67,8 @@ /* * Prototypes */ -static void mutex_handoff(struct pthread *, struct pthread_mutex *); +static struct kse_mailbox *mutex_handoff(struct pthread *, + struct pthread_mutex *); static inline int mutex_self_trylock(struct pthread *, pthread_mutex_t); static inline int mutex_self_lock(struct pthread *, pthread_mutex_t); static int mutex_unlock_common(pthread_mutex_t *, int); @@ -860,6 +861,7 @@ static int mutex_unlock_common(pthread_mutex_t *m, int add_reference) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx = NULL; int ret = 0; if (m == NULL || *m == NULL) @@ -904,7 +906,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -961,7 +963,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -1017,7 +1019,7 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) * Hand off the mutex to the next waiting * thread: */ - mutex_handoff(curthread, *m); + kmbx = mutex_handoff(curthread, *m); } break; @@ -1034,6 +1036,8 @@ mutex_unlock_common(pthread_mutex_t *m, int add_reference) /* Unlock the mutex structure: */ THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + if (kmbx != NULL) + kse_wakeup(kmbx); } /* Return the completion status: */ @@ -1460,9 +1464,10 @@ _mutex_lock_backout(struct pthread *curthread) * is necessary to lock the thread's scheduling queue while also * holding the mutex lock. */ -static void +static struct kse_mailbox * mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) { + struct kse_mailbox *kmbx = NULL; struct pthread *pthread; /* Keep dequeueing until we find a valid thread: */ @@ -1564,7 +1569,7 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) } /* Make the thread runnable and unlock the scheduling queue: */ - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); /* Add a preemption point. */ if ((curthread->kseg == pthread->kseg) && @@ -1583,6 +1588,7 @@ mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT)) /* This mutex has no priority: */ mutex->m_prio = 0; + return (kmbx); } /* diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index 21026b7..90dbed7 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -1106,8 +1106,8 @@ void _thr_ref_delete(struct pthread *, struct pthread *); int _thr_schedule_add(struct pthread *, struct pthread *); void _thr_schedule_remove(struct pthread *, struct pthread *); void _thr_setrunnable(struct pthread *curthread, struct pthread *thread); -void _thr_setrunnable_unlocked(struct pthread *thread); -void _thr_sig_add(struct pthread *, int, siginfo_t *); +struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread); +struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *); void _thr_sig_dispatch(struct kse *, int, siginfo_t *); int _thr_stack_alloc(struct pthread_attr *); void _thr_stack_free(struct pthread_attr *); diff --git a/lib/libpthread/thread/thr_resume_np.c b/lib/libpthread/thread/thr_resume_np.c index 1276311..ba9b911 100644 --- a/lib/libpthread/thread/thr_resume_np.c +++ b/lib/libpthread/thread/thr_resume_np.c @@ -35,7 +35,7 @@ #include <pthread.h> #include "thr_private.h" -static void resume_common(struct pthread *); +static struct kse_mailbox *resume_common(struct pthread *); __weak_reference(_pthread_resume_np, pthread_resume_np); __weak_reference(_pthread_resume_all_np, pthread_resume_all_np); @@ -46,15 +46,18 @@ int _pthread_resume_np(pthread_t thread) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx; int ret; /* Add a reference to the thread: */ if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) { /* Lock the threads scheduling queue: */ THR_SCHED_LOCK(curthread, thread); - resume_common(thread); + kmbx = resume_common(thread); THR_SCHED_UNLOCK(curthread, thread); _thr_ref_delete(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } return (ret); } @@ -64,6 +67,7 @@ _pthread_resume_all_np(void) { struct pthread *curthread = _get_curthread(); struct pthread *thread; + struct kse_mailbox *kmbx; kse_critical_t crit; /* Take the thread list lock: */ @@ -73,8 +77,10 @@ _pthread_resume_all_np(void) TAILQ_FOREACH(thread, &_thread_list, tle) { if (thread != curthread) { THR_SCHED_LOCK(curthread, thread); - resume_common(thread); + kmbx = resume_common(thread); THR_SCHED_UNLOCK(curthread, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); } } @@ -83,7 +89,7 @@ _pthread_resume_all_np(void) _kse_critical_leave(crit); } -static void +static struct kse_mailbox * resume_common(struct pthread *thread) { /* Clear the suspend flag: */ @@ -95,5 +101,7 @@ resume_common(struct pthread *thread) * state to running and insert it into the run queue. */ if (thread->state == PS_SUSPENDED) - _thr_setrunnable_unlocked(thread); + return (_thr_setrunnable_unlocked(thread)); + else + return (NULL); } diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c index 1211ba3..fc075af 100644 --- a/lib/libpthread/thread/thr_sig.c +++ b/lib/libpthread/thread/thr_sig.c @@ -249,6 +249,7 @@ _thr_start_sig_daemon(void) void _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) { + struct kse_mailbox *kmbx; struct pthread *thread; DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); @@ -280,9 +281,11 @@ _thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) KSE_SCHED_UNLOCK(curkse, thread->kseg); _thr_ref_delete(NULL, thread); } else { - _thr_sig_add(thread, sig, info); + kmbx = _thr_sig_add(thread, sig, info); KSE_SCHED_UNLOCK(curkse, thread->kseg); _thr_ref_delete(NULL, thread); + if (kmbx != NULL) + kse_wakeup(kmbx); break; } } @@ -533,6 +536,7 @@ _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) struct pthread * thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) { + struct kse_mailbox *kmbx = NULL; struct pthread *pthread; struct pthread *suspended_thread, *signaled_thread; __siginfohandler_t *sigfunc; @@ -582,7 +586,7 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) /* where to put siginfo ? */ *(pthread->data.sigwaitinfo) = si; pthread->sigmask = pthread->oldsigmask; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } KSE_SCHED_UNLOCK(curkse, pthread->kseg); /* @@ -596,6 +600,8 @@ thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) * to the process pending set. */ KSE_LOCK_RELEASE(curkse, &_thread_list_lock); + if (kmbx != NULL) + kse_wakeup(kmbx); return (NULL); } else if (!SIGISMEMBER(pthread->sigmask, sig) || (!SIGISMEMBER(pthread->oldsigmask, sig) && @@ -811,15 +817,16 @@ handle_special_signals(struct kse *curkse, int sig) * * This must be called with the thread's scheduling lock held. */ -void +struct kse_mailbox * _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) { + siginfo_t siginfo; + struct kse *curkse; + struct kse_mailbox *kmbx = NULL; + struct pthread *curthread = _get_curthread(); int restart; int suppress_handler = 0; int fromproc = 0; - struct pthread *curthread = _get_curthread(); - struct kse *curkse; - siginfo_t siginfo; DBG_MSG(">>> _thr_sig_add %p (%d)\n", pthread, sig); @@ -829,12 +836,12 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || pthread->state == PS_STATE_MAX) - return; /* return false */ + return (NULL); /* return false */ if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) && (curthread != pthread)) { PANIC("Please use _thr_send_sig for bound thread"); - return; + return (NULL); } if (pthread->curframe == NULL || @@ -851,7 +858,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) sizeof(*info)); } else { if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1])) - return; + return (NULL); SIGADDSET(pthread->sigpend, sig); } if (!SIGISMEMBER(pthread->sigmask, sig)) { @@ -867,7 +874,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) /* if process signal not exists, just return */ if (fromproc) { if (!_thr_getprocsig(sig, &siginfo)) - return; + return (NULL); info = &siginfo; } /* @@ -877,7 +884,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) case PS_DEAD: case PS_DEADLOCK: case PS_STATE_MAX: - return; /* XXX return false */ + return (NULL); /* XXX return false */ case PS_LOCKWAIT: case PS_SUSPENDED: /* @@ -937,7 +944,7 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; pthread->sigmask = pthread->oldsigmask; /* Make the thread runnable: */ - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } else { /* Increment the pending signal count. */ SIGADDSET(pthread->sigpend, sig); @@ -945,11 +952,10 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) pthread->check_pending = 1; pthread->interrupted = 1; pthread->sigmask = pthread->oldsigmask; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } } - - return; + return (kmbx); } SIGADDSET(pthread->sigpend, sig); @@ -967,11 +973,12 @@ _thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) if (pthread->flags & THR_FLAGS_IN_RUNQ) THR_RUNQ_REMOVE(pthread); pthread->active_priority |= THR_SIGNAL_PRIORITY; - _thr_setrunnable_unlocked(pthread); + kmbx = _thr_setrunnable_unlocked(pthread); } else { pthread->check_pending = 1; } } + return (kmbx); } /* @@ -981,6 +988,7 @@ void _thr_sig_send(struct pthread *pthread, int sig) { struct pthread *curthread = _get_curthread(); + struct kse_mailbox *kmbx; if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) { kse_thr_interrupt(&pthread->tmbx, KSE_INTR_SENDSIG, sig); @@ -990,8 +998,10 @@ _thr_sig_send(struct pthread *pthread, int sig) /* Lock the scheduling queue of the target thread. */ THR_SCHED_LOCK(curthread, pthread); if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { - _thr_sig_add(pthread, sig, NULL); + kmbx = _thr_sig_add(pthread, sig, NULL); THR_SCHED_UNLOCK(curthread, pthread); + if (kmbx != NULL) + kse_wakeup(kmbx); /* XXX * If thread sent signal to itself, check signals now. * It is not really needed, _kse_critical_leave should |