summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-07 21:00:13 +0000
committerjhb <jhb@FreeBSD.org>2008-08-07 21:00:13 +0000
commite306c86e1b6376905ae8d21091509cbe1f61fba8 (patch)
tree5341583d2eecb5e89baa3cba762d2f3739e4856a
parent9f16e510b9a765d8caed7f31ebaf16b600540db4 (diff)
downloadFreeBSD-src-e306c86e1b6376905ae8d21091509cbe1f61fba8.zip
FreeBSD-src-e306c86e1b6376905ae8d21091509cbe1f61fba8.tar.gz
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
-rw-r--r--share/man/man9/condvar.918
-rw-r--r--share/man/man9/sleep.96
-rw-r--r--sys/kern/kern_condvar.c78
-rw-r--r--sys/kern/kern_synch.c8
4 files changed, 80 insertions, 30 deletions
diff --git a/share/man/man9/condvar.9 b/share/man/man9/condvar.9
index 2ac8906..db3eab1 100644
--- a/share/man/man9/condvar.9
+++ b/share/man/man9/condvar.9
@@ -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
diff --git a/share/man/man9/sleep.9 b/share/man/man9/sleep.9
index aa87642..a9f0873 100644
--- a/share/man/man9/sleep.9
+++ b/share/man/man9/sleep.9
@@ -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,
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c
index 5ee40a3..8b002b1 100644
--- a/sys/kern/kern_condvar.c
+++ b/sys/kern/kern_condvar.c
@@ -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);
}
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 6c10ba4..ef682f4 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -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);
}
OpenPOWER on IntegriCloud