diff options
author | julian <julian@FreeBSD.org> | 2002-10-25 07:11:12 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 2002-10-25 07:11:12 +0000 |
commit | 4ea837f673e35a1bd44b7a3a83d08c96d42e1b81 (patch) | |
tree | 45eb9c5b87d56720d1194f404349dd8746e61573 /sys | |
parent | 59e43a0396de61b22eadda85d6d3d4586710c0b9 (diff) | |
download | FreeBSD-src-4ea837f673e35a1bd44b7a3a83d08c96d42e1b81.zip FreeBSD-src-4ea837f673e35a1bd44b7a3a83d08c96d42e1b81.tar.gz |
More work on the interaction between suspending and sleeping threads.
Also clean up some code used with 'single-threading'.
Reviewed by: davidxu
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_condvar.c | 21 | ||||
-rw-r--r-- | sys/kern/kern_kse.c | 38 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 17 | ||||
-rw-r--r-- | sys/kern/kern_thread.c | 38 |
4 files changed, 66 insertions, 48 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index 3ce9aff..e2bb544 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -82,7 +82,6 @@ #endif static void cv_timedwait_end(void *arg); -static void cv_check_upcall(struct thread *td); /* * Initialize a condition variable. Must be called before use. @@ -112,11 +111,10 @@ cv_destroy(struct cv *cvp) */ /* - * Decide if we need to queue an upcall. - * This is copied from msleep(), perhaps this should be a common function. + * Switch context. */ -static void -cv_check_upcall(struct thread *td) +static __inline void +cv_switch(struct thread *td) { /* @@ -127,8 +125,7 @@ cv_check_upcall(struct thread *td) * the thread (recursion here might be bad). * Hence the TDF_INMSLEEP flag. */ - if ((td->td_proc->p_flag & P_KSES) && td->td_mailbox && - (td->td_flags & TDF_INMSLEEP) == 0) { + if ((td->td_flags & (TDF_UNBOUND|TDF_INMSLEEP)) == TDF_UNBOUND) { /* * We don't need to upcall now, just queue it. * The upcall will happen when other n-kernel work @@ -139,16 +136,6 @@ cv_check_upcall(struct thread *td) thread_schedule_upcall(td, td->td_kse); td->td_flags &= ~TDF_INMSLEEP; } -} - -/* - * Switch context. - */ -static __inline void -cv_switch(struct thread *td) -{ - - cv_check_upcall(td); TD_SET_SLEEPING(td); td->td_proc->p_stats->p_ru.ru_nvcsw++; mi_switch(); diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index f8c99d0..258267b 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -1185,7 +1185,7 @@ thread_user_enter(struct proc *p, struct thread *td) * but for now do it every time. */ ke = td->td_kse; - if (ke->ke_mailbox != NULL) { + if ((ke->ke_mailbox) != NULL) { #if 0 td->td_mailbox = (void *)fuword((caddr_t)ke->ke_mailbox + offsetof(struct kse_mailbox, km_curthread)); @@ -1445,28 +1445,41 @@ thread_single(int force_exit) p->p_flag &= ~P_SINGLE_EXIT; p->p_flag |= P_STOPPED_SINGLE; p->p_singlethread = td; + /* XXXKSE Which lock protects the below values? */ while ((p->p_numthreads - p->p_suspcount) != 1) { mtx_lock_spin(&sched_lock); FOREACH_THREAD_IN_PROC(p, td2) { if (td2 == td) continue; if (TD_IS_INHIBITED(td2)) { - if (TD_IS_SUSPENDED(td2)) { - if (force_exit == SINGLE_EXIT) { + if (force_exit == SINGLE_EXIT) { + if (TD_IS_SUSPENDED(td2)) { thread_unsuspend_one(td2); - } else { - continue; } - } - if (TD_ON_SLEEPQ(td2) && - (td2->td_flags & TDF_SINTR)) { - if (td2->td_flags & TDF_CVWAITQ) - cv_abort(td2); - else - abortsleep(td2); + if (TD_ON_SLEEPQ(td2) && + (td2->td_flags & TDF_SINTR)) { + if (td2->td_flags & TDF_CVWAITQ) + cv_abort(td2); + else + abortsleep(td2); + } + } else { + if (TD_IS_SUSPENDED(td2)) + continue; + /* maybe other inhibitted states too? */ + if (TD_IS_SLEEPING(td2)) + thread_suspend_one(td2); } } } + /* + * Maybe we suspended some threads.. was it enough? + */ + if ((p->p_numthreads - p->p_suspcount) == 1) { + mtx_unlock_spin(&sched_lock); + break; + } + /* * Wake us up when everyone else has suspended. * In the mean time we suspend as well. @@ -1622,6 +1635,7 @@ thread_suspend_one(struct thread *td) * Hack: If we are suspending but are on the sleep queue * then we are in msleep or the cv equivalent. We * want to look like we have two Inhibitors. + * May already be set.. doesn't matter. */ if (TD_ON_SLEEPQ(td)) TD_SET_SLEEPING(td); diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index b758c96..abbd7b5 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -155,26 +155,29 @@ msleep(ident, mtx, priority, wmesg, timo) * Hence the TDF_INMSLEEP flag. */ if (p->p_flag & P_KSES) { - /* Just don't bother if we are exiting - and not the exiting thread. */ - if ((p->p_flag & P_WEXIT) && catch && p->p_singlethread != td) + /* + * Just don't bother if we are exiting + * and not the exiting thread. + */ + if ((p->p_flag & P_WEXIT) && catch && (p->p_singlethread != td)) return (EINTR); - if (td->td_mailbox && (!(td->td_flags & TDF_INMSLEEP))) { + mtx_lock_spin(&sched_lock); + if ((td->td_flags & (TDF_UNBOUND|TDF_INMSLEEP)) == + TDF_UNBOUND) { /* * Arrange for an upcall to be readied. * it will not actually happen until all * pending in-kernel work for this KSEGRP * has been done. */ - mtx_lock_spin(&sched_lock); /* Don't recurse here! */ td->td_flags |= TDF_INMSLEEP; thread_schedule_upcall(td, td->td_kse); td->td_flags &= ~TDF_INMSLEEP; - mtx_unlock_spin(&sched_lock); } + } else { + mtx_lock_spin(&sched_lock); } - mtx_lock_spin(&sched_lock); if (cold ) { /* * During autoconfiguration, just give interrupts diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index f8c99d0..258267b 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -1185,7 +1185,7 @@ thread_user_enter(struct proc *p, struct thread *td) * but for now do it every time. */ ke = td->td_kse; - if (ke->ke_mailbox != NULL) { + if ((ke->ke_mailbox) != NULL) { #if 0 td->td_mailbox = (void *)fuword((caddr_t)ke->ke_mailbox + offsetof(struct kse_mailbox, km_curthread)); @@ -1445,28 +1445,41 @@ thread_single(int force_exit) p->p_flag &= ~P_SINGLE_EXIT; p->p_flag |= P_STOPPED_SINGLE; p->p_singlethread = td; + /* XXXKSE Which lock protects the below values? */ while ((p->p_numthreads - p->p_suspcount) != 1) { mtx_lock_spin(&sched_lock); FOREACH_THREAD_IN_PROC(p, td2) { if (td2 == td) continue; if (TD_IS_INHIBITED(td2)) { - if (TD_IS_SUSPENDED(td2)) { - if (force_exit == SINGLE_EXIT) { + if (force_exit == SINGLE_EXIT) { + if (TD_IS_SUSPENDED(td2)) { thread_unsuspend_one(td2); - } else { - continue; } - } - if (TD_ON_SLEEPQ(td2) && - (td2->td_flags & TDF_SINTR)) { - if (td2->td_flags & TDF_CVWAITQ) - cv_abort(td2); - else - abortsleep(td2); + if (TD_ON_SLEEPQ(td2) && + (td2->td_flags & TDF_SINTR)) { + if (td2->td_flags & TDF_CVWAITQ) + cv_abort(td2); + else + abortsleep(td2); + } + } else { + if (TD_IS_SUSPENDED(td2)) + continue; + /* maybe other inhibitted states too? */ + if (TD_IS_SLEEPING(td2)) + thread_suspend_one(td2); } } } + /* + * Maybe we suspended some threads.. was it enough? + */ + if ((p->p_numthreads - p->p_suspcount) == 1) { + mtx_unlock_spin(&sched_lock); + break; + } + /* * Wake us up when everyone else has suspended. * In the mean time we suspend as well. @@ -1622,6 +1635,7 @@ thread_suspend_one(struct thread *td) * Hack: If we are suspending but are on the sleep queue * then we are in msleep or the cv equivalent. We * want to look like we have two Inhibitors. + * May already be set.. doesn't matter. */ if (TD_ON_SLEEPQ(td)) TD_SET_SLEEPING(td); |