diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 007b3a89ccbc..1e93a66805b1 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -525,28 +525,30 @@ _do_lock(struct thread *td, struct umtx *umtx, long id, int timo) static int do_lock(struct thread *td, struct umtx *umtx, long id, - struct timespec *abstime) + struct timespec *timeout) { - struct timespec ts1, ts2; + struct timespec ts, ts2, ts3; struct timeval tv; - int timo, error; + int error; - if (abstime == NULL) { + if (timeout == NULL) { error = _do_lock(td, umtx, id, 0); } else { + getnanouptime(&ts); + timespecadd(&ts, timeout); + TIMESPEC_TO_TIMEVAL(&tv, timeout); for (;;) { - ts1 = *abstime; - getnanotime(&ts2); - timespecsub(&ts1, &ts2); - TIMESPEC_TO_TIMEVAL(&tv, &ts1); - if (tv.tv_sec < 0) { + error = _do_lock(td, umtx, id, tvtohz(&tv)); + if (error != ETIMEDOUT) + break; + getnanouptime(&ts2); + if (timespeccmp(&ts2, &ts, >=)) { error = ETIMEDOUT; break; } - timo = tvtohz(&tv); - error = _do_lock(td, umtx, id, timo); - if (error != ETIMEDOUT) - break; + ts3 = ts; + timespecsub(&ts3, &ts2); + TIMESPEC_TO_TIMEVAL(&tv, &ts3); } } /* @@ -610,13 +612,13 @@ do_unlock(struct thread *td, struct umtx *umtx, long id) } static int -do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *abstime) +do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *timeout) { struct umtx_q uq; - struct timespec ts1, ts2; + struct timespec ts, ts2, ts3; struct timeval tv; long tmp; - int timo, error = 0; + int error = 0; if ((error = umtxq_queue_me(td, umtx, &uq)) != 0) return (error); @@ -625,7 +627,7 @@ do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *abstime) umtxq_lock(&uq.uq_key); umtxq_remove(&uq); umtxq_unlock(&uq.uq_key); - } else if (abstime == NULL) { + } else if (timeout == NULL) { umtxq_lock(&uq.uq_key); if (td->td_flags & TDF_UMTXQ) error = umtxq_sleep(td, &uq.uq_key, @@ -636,31 +638,37 @@ do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *abstime) umtxq_remove(&uq); umtxq_unlock(&uq.uq_key); } else { + getnanouptime(&ts); + timespecadd(&ts, timeout); + TIMESPEC_TO_TIMEVAL(&tv, timeout); for (;;) { - ts1 = *abstime; - getnanotime(&ts2); - timespecsub(&ts1, &ts2); - TIMESPEC_TO_TIMEVAL(&tv, &ts1); umtxq_lock(&uq.uq_key); - if (tv.tv_sec < 0) { + if (td->td_flags & TDF_UMTXQ) { + error = umtxq_sleep(td, &uq.uq_key, + td->td_priority | PCATCH, + "ucond", tvtohz(&tv)); + } + if (!(td->td_flags & TDF_UMTXQ)) { + umtxq_unlock(&uq.uq_key); + goto out; + } + umtxq_unlock(&uq.uq_key); + if (error != ETIMEDOUT) + break; + getnanouptime(&ts2); + if (timespeccmp(&ts2, &ts, >=)) { error = ETIMEDOUT; break; } - timo = tvtohz(&tv); - if (td->td_flags & TDF_UMTXQ) - error = umtxq_sleep(td, &uq.uq_key, - td->td_priority | PCATCH, - "ucond", timo); - if (error != ETIMEDOUT || !(td->td_flags & TDF_UMTXQ)) - break; - umtxq_unlock(&uq.uq_key); + ts3 = ts; + timespecsub(&ts3, &ts2); + TIMESPEC_TO_TIMEVAL(&tv, &ts3); } - if (!(td->td_flags & TDF_UMTXQ)) - error = 0; - else - umtxq_remove(&uq); + umtxq_lock(&uq.uq_key); + umtxq_remove(&uq); umtxq_unlock(&uq.uq_key); } +out: umtx_key_release(&uq.uq_key); if (error == ERESTART) error = EINTR; @@ -699,7 +707,7 @@ _umtx_unlock(struct thread *td, struct _umtx_unlock_args *uap) int _umtx_op(struct thread *td, struct _umtx_op_args *uap) { - struct timespec abstime; + struct timespec timeout; struct timespec *ts; int error; @@ -709,18 +717,15 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap) if (uap->uaddr2 == NULL) ts = NULL; else { - error = copyin(uap->uaddr2, &abstime, sizeof(abstime)); + error = copyin(uap->uaddr2, &timeout, sizeof(timeout)); if (error != 0) break; -#if 0 - printf("uap->abstime: %d.%ld\n", abstime.tv_sec, abstime.tv_nsec); -#endif - if (abstime.tv_nsec >= 1000000000 || - abstime.tv_nsec < 0) { + if (timeout.tv_nsec >= 1000000000 || + timeout.tv_nsec < 0) { error = EINVAL; break; } - ts = &abstime; + ts = &timeout; } error = do_lock(td, uap->umtx, uap->id, ts); break; @@ -732,15 +737,15 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap) if (uap->uaddr2 == NULL) ts = NULL; else { - error = copyin(uap->uaddr2, &abstime, sizeof(abstime)); + error = copyin(uap->uaddr2, &timeout, sizeof(timeout)); if (error != 0) break; - if (abstime.tv_nsec >= 1000000000 || - abstime.tv_nsec < 0) { + if (timeout.tv_nsec >= 1000000000 || + timeout.tv_nsec < 0) { error = EINVAL; break; } - ts = &abstime; + ts = &timeout; } error = do_wait(td, uap->umtx, uap->id, ts); break; diff --git a/sys/sys/umtx.h b/sys/sys/umtx.h index 383829c687c5..4664c4ee1d7c 100644 --- a/sys/sys/umtx.h +++ b/sys/sys/umtx.h @@ -95,11 +95,11 @@ umtx_trylock(struct umtx *umtx, long id) } static __inline int -umtx_timedlock(struct umtx *umtx, long id, const struct timespec *abstime) +umtx_timedlock(struct umtx *umtx, long id, const struct timespec *timeout) { if (atomic_cmpset_acq_ptr(&umtx->u_owner, (void *)UMTX_UNOWNED, (void *)id) == 0) - return (- _umtx_op(umtx, UMTX_OP_LOCK, id, 0, (void *)abstime)); + return (- _umtx_op(umtx, UMTX_OP_LOCK, id, 0, (void *)timeout)); return (0); } @@ -113,15 +113,9 @@ umtx_unlock(struct umtx *umtx, long id) } static __inline int -umtx_wait(struct umtx *umtx, long id) +umtx_wait(struct umtx *umtx, long id, const struct timespec *timeout) { - return (- _umtx_op(umtx, UMTX_OP_WAIT, id, 0, 0)); -} - -static __inline int -umtx_timedwait(struct umtx *umtx, long id, const struct timespec *abstime) -{ - return (- _umtx_op(umtx, UMTX_OP_WAIT, id, 0, (void *)abstime)); + return (- _umtx_op(umtx, UMTX_OP_WAIT, id, 0, timeout)); } /* Wake threads waiting on a user address. */