}
int
-_cv_timedwait(struct cv *c, struct lock *l, int timo, int wakesig)
+_cv_timedwait(struct cv *c, struct lock *lk, int timo, int wakesig)
{
int flags = wakesig ? PCATCH : 0;
int error;
- spin_lock(&c->cv_lock);
+ /*
+ * Can interlock without critical section/spinlock as long
+ * as we don't block before calling *sleep(). PINTERLOCKED
+ * must be passed to the *sleep() to use the manual interlock
+ * (else a new one is created which opens a timing race).
+ */
tsleep_interlock(c, flags);
+
+ spin_lock(&c->cv_lock);
c->cv_waiters++;
spin_unlock(&c->cv_lock);
- if (l != NULL)
- lockmgr(l, LK_RELEASE);
- error = tsleep(c, flags, c->cv_desc, timo);
- if (l != NULL)
- lockmgr(l, LK_EXCLUSIVE);
+
+ if (lk)
+ error = lksleep(c, lk, flags | PINTERLOCKED, c->cv_desc, timo);
+ else
+ error = tsleep(c, flags | PINTERLOCKED, c->cv_desc, timo);
return (error);
}
_cv_signal(struct cv *c, int broadcast)
{
spin_lock(&c->cv_lock);
- if (c->cv_waiters == 0)
- goto out;
-
- if (broadcast) {
+ if (c->cv_waiters == 0) {
+ spin_unlock(&c->cv_lock);
+ } else if (broadcast) {
c->cv_waiters = 0;
+ spin_unlock(&c->cv_lock); /* must unlock first */
wakeup(c);
} else {
c->cv_waiters--;
+ spin_unlock(&c->cv_lock); /* must unlock first */
wakeup_one(c);
}
-
-out:
- spin_unlock(&c->cv_lock);
}
int