diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 534a3c3f9e7f..e5994c861bb6 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -587,11 +587,10 @@ abs_timeout_init2(struct abs_timeout *timo, const struct _umtx_time *umtxtime) &umtxtime->_timeout); } -static int +static void abs_timeout_update(struct abs_timeout *timo) { kern_clock_gettime(curthread, timo->clockid, &timo->cur); - return (timespeccmp(&timo->cur, &timo->end, >=)); } static int @@ -601,6 +600,8 @@ abs_timeout_gethz(struct abs_timeout *timo) tts = timo->end; timespecsub(&tts, &timo->cur); + if (tts.tv_sec < 0 || (tts.tv_sec == 0 && tts.tv_nsec == 0)) + return (-1); return (tstohz(&tts)); } @@ -613,22 +614,25 @@ umtxq_sleep(struct umtx_q *uq, const char *wmesg, struct abs_timeout *timo) { struct umtxq_chain *uc; int error; + int pulse; uc = umtxq_getchain(&uq->uq_key); UMTXQ_LOCKED_ASSERT(uc); for (;;) { if (!(uq->uq_flags & UQF_UMTXQ)) return (0); - error = msleep(uq, &uc->uc_lock, PCATCH, wmesg, - timo == NULL ? 0 : abs_timeout_gethz(timo)); - if (error != EWOULDBLOCK) - break; - umtxq_unlock(&uq->uq_key); - if (abs_timeout_update(timo)) { - error = ETIMEDOUT; + if (timo != NULL) { + pulse = abs_timeout_gethz(timo); + if (pulse < 0) + return (ETIMEDOUT); + } else + pulse = 0; + error = msleep(uq, &uc->uc_lock, PCATCH|PDROP, wmesg, pulse); + if (error != EWOULDBLOCK) { umtxq_lock(&uq->uq_key); break; } + abs_timeout_update(timo); umtxq_lock(&uq->uq_key); } return (error);