Permit Giant to be passed as the explicit interlock either to

msleep/mtx_sleep or the various cv_*wait*() routines.  Currently, the
"unlock" behavior of PDROP and cv_wait_unlock() with Giant is not
permitted as it is will be confusing since Giant is fully unrecursed and
unlocked during a thread sleep.

This is handy for subsystems which wish to allow unlocked drivers to
continue to use Giant such as CAM, the new TTY layer, and the new USB
stack.  CAM currently uses a hack that I told Scott to use because I
really didn't want to permit this behavior, and the TTY and USB patches
both have various patches to permit this.

MFC after:	2 weeks
This commit is contained in:
John Baldwin 2008-08-07 21:00:13 +00:00
parent 95469daac8
commit 414e7679cb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=181394
4 changed files with 80 additions and 30 deletions

View File

@ -136,9 +136,27 @@ When a thread waits on a condition,
.Fa lock
is atomically released before the thread is blocked, then reacquired
before the function call returns.
In addition, the thread will fully drop the
.Va Giant
mutex
(even if recursed)
while the it is suspended and will reacquire the
.Va Giant
mutex before the function returns.
The
.Fn cv_wait_unlock
function does not reacquire the lock before returning.
Note that the
.Va Giant
mutex may be specified as
.Fa lock .
However,
.Va Giant
may not be used as
.Fa lock
for the
.Fn cv_wait_unlock
function.
All waiters must pass the same
.Fa lock
in conjunction with

View File

@ -157,6 +157,12 @@ mutex
while the thread is suspended and will reacquire the
.Va Giant
mutex before the function returns.
Note that the
.Va Giant
mutex may be specified as the lock to drop.
In that case, however, the
.Dv PDROP
flag is not allowed.
.Pp
To avoid lost wakeups,
either a lock should be used to protect against races,

View File

@ -100,6 +100,7 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
int lock_state;
td = curthread;
lock_state = 0;
#ifdef KTRACE
if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0);
@ -126,11 +127,13 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
DROP_GIANT();
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
if (lock != &Giant.lock_object) {
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
}
sleepq_wait(cvp, 0);
#ifdef KTRACE
@ -138,8 +141,10 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
ktrcsw(0, 0);
#endif
PICKUP_GIANT();
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
if (lock != &Giant.lock_object) {
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
}
}
/*
@ -160,6 +165,8 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
CV_ASSERT(cvp, lock, td);
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
"Waiting on \"%s\"", cvp->cv_description);
KASSERT(lock != &Giant.lock_object,
("cv_wait_unlock cannot be used with Giant"));
class = LOCK_CLASS(lock);
if (cold || panicstr) {
@ -210,6 +217,7 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
td = curthread;
p = td->td_proc;
lock_state = 0;
#ifdef KTRACE
if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0);
@ -237,11 +245,13 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
SLEEPQ_INTERRUPTIBLE, 0);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
if (lock != &Giant.lock_object) {
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
}
rval = sleepq_wait_sig(cvp, 0);
#ifdef KTRACE
@ -249,8 +259,10 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
ktrcsw(0, 0);
#endif
PICKUP_GIANT();
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
if (lock != &Giant.lock_object) {
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
}
return (rval);
}
@ -270,6 +282,7 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
td = curthread;
rval = 0;
lock_state = 0;
#ifdef KTRACE
if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0);
@ -297,11 +310,13 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
sleepq_set_timeout(cvp, timo);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
if (lock != &Giant.lock_object) {
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
}
rval = sleepq_timedwait(cvp, 0);
#ifdef KTRACE
@ -309,8 +324,10 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
ktrcsw(0, 0);
#endif
PICKUP_GIANT();
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
if (lock != &Giant.lock_object) {
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
}
return (rval);
}
@ -333,6 +350,7 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
td = curthread;
p = td->td_proc;
rval = 0;
lock_state = 0;
#ifdef KTRACE
if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0);
@ -361,11 +379,13 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
SLEEPQ_INTERRUPTIBLE, 0);
sleepq_set_timeout(cvp, timo);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
if (lock != &Giant.lock_object) {
if (class->lc_flags & LC_SLEEPABLE)
sleepq_release(cvp);
lock_state = class->lc_unlock(lock);
if (class->lc_flags & LC_SLEEPABLE)
sleepq_lock(cvp);
}
rval = sleepq_timedwait_sig(cvp, 0);
#ifdef KTRACE
@ -373,8 +393,10 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
ktrcsw(0, 0);
#endif
PICKUP_GIANT();
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
if (lock != &Giant.lock_object) {
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
}
return (rval);
}

View File

@ -140,6 +140,9 @@ _sleep(void *ident, struct lock_object *lock, int priority,
ident == &lbolt, ("sleeping without a lock"));
KASSERT(p != NULL, ("msleep1"));
KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep"));
if (priority & PDROP)
KASSERT(lock != NULL && lock != &Giant.lock_object,
("PDROP requires a non-Giant lock"));
if (lock != NULL)
class = LOCK_CLASS(lock);
else
@ -182,7 +185,8 @@ _sleep(void *ident, struct lock_object *lock, int priority,
td->td_tid, p->p_pid, td->td_name, wmesg, ident);
DROP_GIANT();
if (lock != NULL && !(class->lc_flags & LC_SLEEPABLE)) {
if (lock != NULL && lock != &Giant.lock_object &&
!(class->lc_flags & LC_SLEEPABLE)) {
WITNESS_SAVE(lock, lock_witness);
lock_state = class->lc_unlock(lock);
} else
@ -222,7 +226,7 @@ _sleep(void *ident, struct lock_object *lock, int priority,
ktrcsw(0, 0);
#endif
PICKUP_GIANT();
if (lock != NULL && !(priority & PDROP)) {
if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) {
class->lc_lock(lock, lock_state);
WITNESS_RESTORE(lock, lock_witness);
}