summaryrefslogtreecommitdiff
path: root/sys/kern/kern_condvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_condvar.c')
-rw-r--r--sys/kern/kern_condvar.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c
index 07ed3b733fcd..4e26f2e59b6e 100644
--- a/sys/kern/kern_condvar.c
+++ b/sys/kern/kern_condvar.c
@@ -345,8 +345,17 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
if (p->p_sflag & PS_TIMEOUT) {
p->p_sflag &= ~PS_TIMEOUT;
rval = EWOULDBLOCK;
- } else
- callout_stop(&p->p_slpcallout);
+ } else if (p->p_sflag & PS_TIMOFAIL)
+ p->p_sflag &= ~PS_TIMOFAIL;
+ else if (callout_stop(&p->p_slpcallout) == 0) {
+ /*
+ * Work around race with cv_timedwait_end similar to that
+ * between msleep and endtsleep.
+ */
+ p->p_sflag |= PS_TIMEOUT;
+ p->p_stats->p_ru.ru_nivcsw++;
+ mi_switch();
+ }
mtx_unlock_spin(&sched_lock);
#ifdef KTRACE
@@ -407,8 +416,17 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
if (p->p_sflag & PS_TIMEOUT) {
p->p_sflag &= ~PS_TIMEOUT;
rval = EWOULDBLOCK;
- } else
- callout_stop(&p->p_slpcallout);
+ } else if (p->p_sflag & PS_TIMOFAIL)
+ p->p_sflag &= ~PS_TIMOFAIL;
+ else if (callout_stop(&p->p_slpcallout) == 0) {
+ /*
+ * Work around race with cv_timedwait_end similar to that
+ * between msleep and endtsleep.
+ */
+ p->p_sflag |= PS_TIMEOUT;
+ p->p_stats->p_ru.ru_nivcsw++;
+ mi_switch();
+ }
mtx_unlock_spin(&sched_lock);
PICKUP_GIANT();
@@ -538,12 +556,16 @@ cv_timedwait_end(void *arg)
CTR3(KTR_PROC, "cv_timedwait_end: proc %p (pid %d, %s)", p, p->p_pid,
p->p_comm);
mtx_lock_spin(&sched_lock);
- if (p->p_wchan != NULL) {
+ if (p->p_sflag & PS_TIMEOUT) {
+ p->p_sflag &= ~PS_TIMEOUT;
+ setrunqueue(p);
+ } else if (p->p_wchan != NULL) {
if (p->p_stat == SSLEEP)
setrunnable(p);
else
cv_waitq_remove(p);
p->p_sflag |= PS_TIMEOUT;
- }
+ } else
+ p->p_sflag |= PS_TIMOFAIL;
mtx_unlock_spin(&sched_lock);
}