More work on the interaction between suspending and sleeping threads.

Also clean up some code used with 'single-threading'.

Reviewed by:	davidxu
This commit is contained in:
Julian Elischer 2002-10-25 07:11:12 +00:00
parent d793791855
commit 9d10277721
4 changed files with 66 additions and 48 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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);