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:
parent
d793791855
commit
9d10277721
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=105911
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user