Rename the cv_*wait*() functions to _cv_*wait*() and change their second

argument from a mutex to a lock_object.  Add cv_*wait*() wrapper macros
that accept either a mutex, rwlock, or sx lock as the second argument and
convert it to a lock_object and then call _cv_*wait*().  Basically, the
visible difference is that you can now use rwlocks and sx locks with
condition variables using the same API as with mutexes.
This commit is contained in:
John Baldwin 2007-03-21 22:22:13 +00:00
parent 73de183262
commit 8f27b08e87
3 changed files with 92 additions and 66 deletions

View File

@ -26,7 +26,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd February 1, 2006 .Dd March 21, 2007
.Dt CONDVAR 9 .Dt CONDVAR 9
.Os .Os
.Sh NAME .Sh NAME
@ -52,15 +52,15 @@
.Ft void .Ft void
.Fn cv_destroy "struct cv *cvp" .Fn cv_destroy "struct cv *cvp"
.Ft void .Ft void
.Fn cv_wait "struct cv *cvp" "struct mtx *mp" .Fn cv_wait "struct cv *cvp" "lock"
.Ft int .Ft int
.Fn cv_wait_sig "struct cv *cvp" "struct mtx *mp" .Fn cv_wait_sig "struct cv *cvp" "lock"
.Ft void .Ft void
.Fn cv_wait_unlock "struct cv *cvp" "struct mtx *mp" .Fn cv_wait_unlock "struct cv *cvp" "lock"
.Ft int .Ft int
.Fn cv_timedwait "struct cv *cvp" "struct mtx *mp" "int timo" .Fn cv_timedwait "struct cv *cvp" "lock" "int timo"
.Ft int .Ft int
.Fn cv_timedwait_sig "struct cv *cvp" "struct mtx *mp" "int timo" .Fn cv_timedwait_sig "struct cv *cvp" "lock" "int timo"
.Ft void .Ft void
.Fn cv_signal "struct cv *cvp" .Fn cv_signal "struct cv *cvp"
.Ft void .Ft void
@ -109,8 +109,16 @@ returns the description string of
as set by the initial call to as set by the initial call to
.Fn cv_init . .Fn cv_init .
.Pp .Pp
The
.Fa lock
argument is a pointer to either a
.Xr mutex 9 ,
.Xr rwlock 9 ,
or
.Xr sx 9
lock.
A thread must hold A thread must hold
.Fa mp .Fa lock
before calling before calling
.Fn cv_wait , .Fn cv_wait ,
.Fn cv_wait_sig , .Fn cv_wait_sig ,
@ -119,14 +127,14 @@ before calling
or or
.Fn cv_timedwait_sig . .Fn cv_timedwait_sig .
When a thread waits on a condition, When a thread waits on a condition,
.Fa mp .Fa lock
is atomically released before the thread is blocked, then reacquired is atomically released before the thread is blocked, then reacquired
before the function call returns. before the function call returns.
The The
.Fn cv_wait_unlock .Fn cv_wait_unlock
function does not reacquire the lock before returning. function does not reacquire the lock before returning.
All waiters must pass the same All waiters must pass the same
.Fa mp .Fa lock
in conjunction with in conjunction with
.Fa cvp . .Fa cvp .
.Pp .Pp

View File

@ -49,12 +49,11 @@ __FBSDID("$FreeBSD$");
/* /*
* Common sanity checks for cv_wait* functions. * Common sanity checks for cv_wait* functions.
*/ */
#define CV_ASSERT(cvp, mp, td) do { \ #define CV_ASSERT(cvp, lock, td) do { \
KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \
KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \
KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \
KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ KASSERT((lock) != NULL, ("%s: lock NULL", __func__)); \
mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \
} while (0) } while (0)
/* /*
@ -93,20 +92,23 @@ cv_destroy(struct cv *cvp)
* held when cv_signal or cv_broadcast are called. * held when cv_signal or cv_broadcast are called.
*/ */
void void
cv_wait(struct cv *cvp, struct mtx *mp) _cv_wait(struct cv *cvp, struct lock_object *lock)
{ {
WITNESS_SAVE_DECL(mp); WITNESS_SAVE_DECL(lock_witness);
struct lock_class *class;
struct thread *td; struct thread *td;
int lock_state;
td = curthread; td = curthread;
#ifdef KTRACE #ifdef KTRACE
if (KTRPOINT(td, KTR_CSW)) if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0); ktrcsw(1, 0);
#endif #endif
CV_ASSERT(cvp, mp, td); CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->lock_object, WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description); "Waiting on \"%s\"", cvp->cv_description);
WITNESS_SAVE(&mp->lock_object, mp); WITNESS_SAVE(lock, lock_witness);
class = LOCK_CLASS(lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -122,10 +124,9 @@ cv_wait(struct cv *cvp, struct mtx *mp)
cvp->cv_waiters++; cvp->cv_waiters++;
DROP_GIANT(); DROP_GIANT();
mtx_unlock(mp); lock_state = class->lc_unlock(lock);
sleepq_add(cvp, &mp->lock_object, cvp->cv_description, SLEEPQ_CONDVAR, sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
0);
sleepq_wait(cvp); sleepq_wait(cvp);
#ifdef KTRACE #ifdef KTRACE
@ -133,8 +134,8 @@ cv_wait(struct cv *cvp, struct mtx *mp)
ktrcsw(0, 0); ktrcsw(0, 0);
#endif #endif
PICKUP_GIANT(); PICKUP_GIANT();
mtx_lock(mp); class->lc_lock(lock, lock_state);
WITNESS_RESTORE(&mp->lock_object, mp); WITNESS_RESTORE(lock, lock_witness);
} }
/* /*
@ -142,8 +143,9 @@ cv_wait(struct cv *cvp, struct mtx *mp)
* not aquiring the mutex after condition variable was signaled. * not aquiring the mutex after condition variable was signaled.
*/ */
void void
cv_wait_unlock(struct cv *cvp, struct mtx *mp) _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
{ {
struct lock_class *class;
struct thread *td; struct thread *td;
td = curthread; td = curthread;
@ -151,9 +153,10 @@ cv_wait_unlock(struct cv *cvp, struct mtx *mp)
if (KTRPOINT(td, KTR_CSW)) if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0); ktrcsw(1, 0);
#endif #endif
CV_ASSERT(cvp, mp, td); CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->lock_object, WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description); "Waiting on \"%s\"", cvp->cv_description);
class = LOCK_CLASS(lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -162,7 +165,7 @@ cv_wait_unlock(struct cv *cvp, struct mtx *mp)
* thread or panic below, in case this is the idle * thread or panic below, in case this is the idle
* process and already asleep. * process and already asleep.
*/ */
mtx_unlock(mp); class->lc_unlock(lock);
return; return;
} }
@ -170,10 +173,9 @@ cv_wait_unlock(struct cv *cvp, struct mtx *mp)
cvp->cv_waiters++; cvp->cv_waiters++;
DROP_GIANT(); DROP_GIANT();
mtx_unlock(mp); class->lc_unlock(lock);
sleepq_add(cvp, &mp->lock_object, cvp->cv_description, SLEEPQ_CONDVAR, sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
0);
sleepq_wait(cvp); sleepq_wait(cvp);
#ifdef KTRACE #ifdef KTRACE
@ -190,12 +192,13 @@ cv_wait_unlock(struct cv *cvp, struct mtx *mp)
* restarted if possible. * restarted if possible.
*/ */
int int
cv_wait_sig(struct cv *cvp, struct mtx *mp) _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
{ {
WITNESS_SAVE_DECL(lock_witness);
struct lock_class *class;
struct thread *td; struct thread *td;
struct proc *p; struct proc *p;
int rval; int lock_state, rval;
WITNESS_SAVE_DECL(mp);
td = curthread; td = curthread;
p = td->td_proc; p = td->td_proc;
@ -203,10 +206,11 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp)
if (KTRPOINT(td, KTR_CSW)) if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0); ktrcsw(1, 0);
#endif #endif
CV_ASSERT(cvp, mp, td); CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->lock_object, WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description); "Waiting on \"%s\"", cvp->cv_description);
WITNESS_SAVE(&mp->lock_object, mp); WITNESS_SAVE(lock, lock_witness);
class = LOCK_CLASS(lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -222,9 +226,9 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp)
cvp->cv_waiters++; cvp->cv_waiters++;
DROP_GIANT(); DROP_GIANT();
mtx_unlock(mp); lock_state = class->lc_unlock(lock);
sleepq_add(cvp, &mp->lock_object, cvp->cv_description, SLEEPQ_CONDVAR | sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
SLEEPQ_INTERRUPTIBLE, 0); SLEEPQ_INTERRUPTIBLE, 0);
rval = sleepq_wait_sig(cvp); rval = sleepq_wait_sig(cvp);
@ -233,8 +237,8 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp)
ktrcsw(0, 0); ktrcsw(0, 0);
#endif #endif
PICKUP_GIANT(); PICKUP_GIANT();
mtx_lock(mp); class->lc_lock(lock, lock_state);
WITNESS_RESTORE(&mp->lock_object, mp); WITNESS_RESTORE(lock, lock_witness);
return (rval); return (rval);
} }
@ -245,11 +249,12 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp)
* expires. * expires.
*/ */
int int
cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
{ {
WITNESS_SAVE_DECL(lock_witness);
struct lock_class *class;
struct thread *td; struct thread *td;
int rval; int lock_state, rval;
WITNESS_SAVE_DECL(mp);
td = curthread; td = curthread;
rval = 0; rval = 0;
@ -257,10 +262,11 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
if (KTRPOINT(td, KTR_CSW)) if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0); ktrcsw(1, 0);
#endif #endif
CV_ASSERT(cvp, mp, td); CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->lock_object, WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description); "Waiting on \"%s\"", cvp->cv_description);
WITNESS_SAVE(&mp->lock_object, mp); WITNESS_SAVE(lock, lock_witness);
class = LOCK_CLASS(lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -276,10 +282,9 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
cvp->cv_waiters++; cvp->cv_waiters++;
DROP_GIANT(); DROP_GIANT();
mtx_unlock(mp); lock_state = class->lc_unlock(lock);
sleepq_add(cvp, &mp->lock_object, cvp->cv_description, SLEEPQ_CONDVAR, sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
0);
sleepq_set_timeout(cvp, timo); sleepq_set_timeout(cvp, timo);
rval = sleepq_timedwait(cvp); rval = sleepq_timedwait(cvp);
@ -288,8 +293,8 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
ktrcsw(0, 0); ktrcsw(0, 0);
#endif #endif
PICKUP_GIANT(); PICKUP_GIANT();
mtx_lock(mp); class->lc_lock(lock, lock_state);
WITNESS_RESTORE(&mp->lock_object, mp); WITNESS_RESTORE(lock, lock_witness);
return (rval); return (rval);
} }
@ -301,12 +306,13 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
* a signal was caught. * a signal was caught.
*/ */
int int
cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
{ {
WITNESS_SAVE_DECL(lock_witness);
struct lock_class *class;
struct thread *td; struct thread *td;
struct proc *p; struct proc *p;
int rval; int lock_state, rval;
WITNESS_SAVE_DECL(mp);
td = curthread; td = curthread;
p = td->td_proc; p = td->td_proc;
@ -315,10 +321,11 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
if (KTRPOINT(td, KTR_CSW)) if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0); ktrcsw(1, 0);
#endif #endif
CV_ASSERT(cvp, mp, td); CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->lock_object, WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description); "Waiting on \"%s\"", cvp->cv_description);
WITNESS_SAVE(&mp->lock_object, mp); WITNESS_SAVE(lock, lock_witness);
class = LOCK_CLASS(lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -334,9 +341,9 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
cvp->cv_waiters++; cvp->cv_waiters++;
DROP_GIANT(); DROP_GIANT();
mtx_unlock(mp); lock_state = class->lc_unlock(lock);
sleepq_add(cvp, &mp->lock_object, cvp->cv_description, SLEEPQ_CONDVAR | sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
SLEEPQ_INTERRUPTIBLE, 0); SLEEPQ_INTERRUPTIBLE, 0);
sleepq_set_timeout(cvp, timo); sleepq_set_timeout(cvp, timo);
rval = sleepq_timedwait_sig(cvp); rval = sleepq_timedwait_sig(cvp);
@ -346,8 +353,8 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
ktrcsw(0, 0); ktrcsw(0, 0);
#endif #endif
PICKUP_GIANT(); PICKUP_GIANT();
mtx_lock(mp); class->lc_lock(lock, lock_state);
WITNESS_RESTORE(&mp->lock_object, mp); WITNESS_RESTORE(lock, lock_witness);
return (rval); return (rval);
} }

View File

@ -32,7 +32,7 @@
#ifndef LOCORE #ifndef LOCORE
#include <sys/queue.h> #include <sys/queue.h>
struct mtx; struct lock_object;
struct thread; struct thread;
TAILQ_HEAD(cv_waitq, thread); TAILQ_HEAD(cv_waitq, thread);
@ -52,15 +52,26 @@ struct cv {
void cv_init(struct cv *cvp, const char *desc); void cv_init(struct cv *cvp, const char *desc);
void cv_destroy(struct cv *cvp); void cv_destroy(struct cv *cvp);
void cv_wait(struct cv *cvp, struct mtx *mp); void _cv_wait(struct cv *cvp, struct lock_object *lock);
void cv_wait_unlock(struct cv *cvp, struct mtx *mp); void _cv_wait_unlock(struct cv *cvp, struct lock_object *lock);
int cv_wait_sig(struct cv *cvp, struct mtx *mp); int _cv_wait_sig(struct cv *cvp, struct lock_object *lock);
int cv_timedwait(struct cv *cvp, struct mtx *mp, int timo); int _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo);
int cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo); int _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo);
void cv_signal(struct cv *cvp); void cv_signal(struct cv *cvp);
void cv_broadcastpri(struct cv *cvp, int pri); void cv_broadcastpri(struct cv *cvp, int pri);
#define cv_wait(cvp, lock) \
_cv_wait((cvp), &(lock)->lock_object)
#define cv_wait_unlock(cvp, lock) \
_cv_wait_unlock((cvp), &(lock)->lock_object)
#define cv_wait_sig(cvp, lock) \
_cv_wait_sig((cvp), &(lock)->lock_object)
#define cv_timedwait(cvp, lock, timo) \
_cv_timedwait((cvp), &(lock)->lock_object, (timo))
#define cv_timedwait_sig(cvp, lock, timo) \
_cv_timedwait_sig((cvp), &(lock)->lock_object, (timo))
#define cv_broadcast(cvp) cv_broadcastpri(cvp, -1) #define cv_broadcast(cvp) cv_broadcastpri(cvp, -1)
#define cv_wmesg(cvp) ((cvp)->cv_description) #define cv_wmesg(cvp) ((cvp)->cv_description)