Associate a simple count of waiters with each condition variable. The
count is protected by the mutex that protects the condition, so the count does not require any extra locking or atomic operations. It serves as an optimization to avoid calling into the sleepqueue code at all if there are no waiters. Note that the count can get temporarily out of sync when threads sleeping on a condition variable time out or are aborted. However, it doesn't hurt to call the sleepqueue code for either a signal or a broadcast when there are no waiters, and the count is never out of sync in the opposite direction unless we have more than INT_MAX sleeping threads.
This commit is contained in:
parent
535eb30962
commit
9000d57d57
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=127954
@ -65,6 +65,7 @@ cv_init(struct cv *cvp, const char *desc)
|
||||
{
|
||||
|
||||
cvp->cv_description = desc;
|
||||
cvp->cv_waiters = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -119,6 +120,7 @@ cv_wait(struct cv *cvp, struct mtx *mp)
|
||||
|
||||
sq = sleepq_lookup(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
DROP_GIANT();
|
||||
mtx_unlock(mp);
|
||||
|
||||
@ -175,6 +177,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp)
|
||||
|
||||
/* XXX: Missing the threading checks from msleep! */
|
||||
|
||||
cvp->cv_waiters++;
|
||||
DROP_GIANT();
|
||||
mtx_unlock(mp);
|
||||
|
||||
@ -241,6 +244,7 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
|
||||
|
||||
sq = sleepq_lookup(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
DROP_GIANT();
|
||||
mtx_unlock(mp);
|
||||
|
||||
@ -299,6 +303,7 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
|
||||
|
||||
sq = sleepq_lookup(cvp);
|
||||
|
||||
cvp->cv_waiters++;
|
||||
DROP_GIANT();
|
||||
mtx_unlock(mp);
|
||||
|
||||
@ -341,7 +346,10 @@ void
|
||||
cv_signal(struct cv *cvp)
|
||||
{
|
||||
|
||||
sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
|
||||
if (cvp->cv_waiters > 0) {
|
||||
cvp->cv_waiters--;
|
||||
sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -352,5 +360,8 @@ void
|
||||
cv_broadcastpri(struct cv *cvp, int pri)
|
||||
{
|
||||
|
||||
sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
|
||||
if (cvp->cv_waiters > 0) {
|
||||
cvp->cv_waiters = 0;
|
||||
sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
|
||||
}
|
||||
}
|
||||
|
@ -38,10 +38,14 @@ struct thread;
|
||||
TAILQ_HEAD(cv_waitq, thread);
|
||||
|
||||
/*
|
||||
* Condition variable.
|
||||
* Condition variable. The waiters count is protected by the mutex that
|
||||
* protects the condition; that is, the mutex that is passed to cv_wait*()
|
||||
* and is held across calls to cv_signal() and cv_broadcast(). It is an
|
||||
* optimization to avoid looking up the sleep queue if there are no waiters.
|
||||
*/
|
||||
struct cv {
|
||||
const char *cv_description;
|
||||
int cv_waiters;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
Loading…
Reference in New Issue
Block a user