Apply the cluebat to myself and undo the await() -> mawait() rename. The

asleep() and await() functions split the functionality of msleep() up into
two halves.  Only the asleep() half (which is what puts the process on the
sleep queue) actually needs the lock usually passed to msleep() held to
prevent lost wakeups.  await() does not need the lock held, so the lock
can be released prior to calling await() and does not need to be passed in
to the await() function.  Typical usage of these functions would be as
follows:

        mtx_lock(&foo_mtx);
        ... do stuff ...
        asleep(&foo_cond, PRIxx, "foowt", hz);
        ...
        mtx_unlock&foo_mtx);
        ...
        await(-1, -1);

Inspired by:	dillon on the couch at Usenix
This commit is contained in:
jhb 2001-07-31 22:06:56 +00:00
parent 394c3bbe7d
commit 3df0102bec
2 changed files with 16 additions and 33 deletions

View File

@ -488,16 +488,16 @@ msleep(ident, mtx, priority, wmesg, timo)
/* /*
* asleep() - async sleep call. Place process on wait queue and return * asleep() - async sleep call. Place process on wait queue and return
* immediately without blocking. The process stays runnable until mawait() * immediately without blocking. The process stays runnable until await()
* is called. If ident is NULL, remove process from wait queue if it is still * is called. If ident is NULL, remove process from wait queue if it is still
* on one. * on one.
* *
* Only the most recent sleep condition is effective when making successive * Only the most recent sleep condition is effective when making successive
* calls to asleep() or when calling msleep(). * calls to asleep() or when calling msleep().
* *
* The timeout, if any, is not initiated until mawait() is called. The sleep * The timeout, if any, is not initiated until await() is called. The sleep
* priority, signal, and timeout is specified in the asleep() call but may be * priority, signal, and timeout is specified in the asleep() call but may be
* overriden in the mawait() call. * overriden in the await() call.
* *
* <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>> * <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
*/ */
@ -532,27 +532,24 @@ asleep(void *ident, int priority, const char *wmesg, int timo)
} }
/* /*
* mawait() - wait for async condition to occur. The process blocks until * await() - wait for async condition to occur. The process blocks until
* wakeup() is called on the most recent asleep() address. If wakeup is called * wakeup() is called on the most recent asleep() address. If wakeup is called
* prior to mawait(), mawait() winds up being a NOP. * prior to await(), await() winds up being a NOP.
* *
* If mawait() is called more then once (without an intervening asleep() call), * If await() is called more then once (without an intervening asleep() call),
* mawait() is still effectively a NOP but it calls mi_switch() to give other * await() is still effectively a NOP but it calls mi_switch() to give other
* processes some cpu before returning. The process is left runnable. * processes some cpu before returning. The process is left runnable.
* *
* <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>> * <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
*/ */
int int
mawait(struct mtx *mtx, int priority, int timo) await(int priority, int timo)
{ {
struct proc *p = curproc; struct proc *p = curproc;
int rval = 0; int rval = 0;
WITNESS_SAVE_DECL(mtx);
WITNESS_SLEEP(0, &mtx->mtx_object); WITNESS_SLEEP(0, NULL);
KASSERT(timo > 0 || mtx_owned(&Giant) || mtx != NULL,
("sleeping without a mutex"));
mtx_lock_spin(&sched_lock); mtx_lock_spin(&sched_lock);
if (cold || panicstr) { if (cold || panicstr) {
/* /*
@ -561,19 +558,10 @@ mawait(struct mtx *mtx, int priority, int timo)
* don't run any other procs or panic below, * don't run any other procs or panic below,
* in case this is the idle process and already asleep. * in case this is the idle process and already asleep.
*/ */
if (mtx != NULL && priority & PDROP)
mtx_unlock_flags(mtx, MTX_NOSWITCH);
mtx_unlock_spin(&sched_lock); mtx_unlock_spin(&sched_lock);
return (0); return (0);
} }
DROP_GIANT_NOSWITCH(); DROP_GIANT_NOSWITCH();
if (mtx != NULL) {
mtx_assert(mtx, MA_OWNED | MA_NOTRECURSED);
WITNESS_SAVE(&mtx->mtx_object, mtx);
mtx_unlock_flags(mtx, MTX_NOSWITCH);
if (priority & PDROP)
mtx = NULL;
}
if (p->p_wchan != NULL) { if (p->p_wchan != NULL) {
int sig; int sig;
@ -584,7 +572,7 @@ mawait(struct mtx *mtx, int priority, int timo)
ktrcsw(p->p_tracep, 1, 0); ktrcsw(p->p_tracep, 1, 0);
#endif #endif
/* /*
* The call to mawait() can override defaults specified in * The call to await() can override defaults specified in
* the original asleep(). * the original asleep().
*/ */
if (priority < 0) if (priority < 0)
@ -647,7 +635,7 @@ mawait(struct mtx *mtx, int priority, int timo)
#endif #endif
} else { } else {
/* /*
* If as_priority is 0, mawait() has been called without an * If as_priority is 0, await() has been called without an
* intervening asleep(). We are still effectively a NOP, * intervening asleep(). We are still effectively a NOP,
* but we call mi_switch() for safety. * but we call mi_switch() for safety.
*/ */
@ -660,24 +648,20 @@ mawait(struct mtx *mtx, int priority, int timo)
} }
/* /*
* clear p_asleep.as_priority as an indication that mawait() has been * clear p_asleep.as_priority as an indication that await() has been
* called. If mawait() is called again without an intervening asleep(), * called. If await() is called again without an intervening asleep(),
* mawait() is still effectively a NOP but the above mi_switch() code * await() is still effectively a NOP but the above mi_switch() code
* is triggered as a safety. * is triggered as a safety.
*/ */
if (rval == 0) if (rval == 0)
p->p_asleep.as_priority = 0; p->p_asleep.as_priority = 0;
PICKUP_GIANT(); PICKUP_GIANT();
if (mtx != NULL) {
mtx_lock(mtx);
WITNESS_RESTORE(&mtx->mtx_object, mtx);
}
return (rval); return (rval);
} }
/* /*
* Implement timeout for msleep or asleep()/mawait() * Implement timeout for msleep or asleep()/await()
* *
* If process hasn't been awakened (wchan non-zero), * If process hasn't been awakened (wchan non-zero),
* set timeout flag and undo the sleep. If proc * set timeout flag and undo the sleep. If proc

View File

@ -263,8 +263,7 @@ int msleep __P((void *chan, struct mtx *mtx, int pri, const char *wmesg,
int timo)); int timo));
#define tsleep(chan, pri, wmesg, timo) msleep(chan, NULL, pri, wmesg, timo) #define tsleep(chan, pri, wmesg, timo) msleep(chan, NULL, pri, wmesg, timo)
int asleep __P((void *chan, int pri, const char *wmesg, int timo)); int asleep __P((void *chan, int pri, const char *wmesg, int timo));
#define await(pri, timo) mawait(NULL, pri, timo) int await __P((int pri, int timo));
int mawait __P((struct mtx *mtx, int pri, int timo));
void wakeup __P((void *chan)); void wakeup __P((void *chan));
void wakeup_one __P((void *chan)); void wakeup_one __P((void *chan));