summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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