make umtx timeout relative so userland can select different clock type,

e.g, CLOCK_REALTIME or CLOCK_MONOTONIC.
merge umtx_wait and umtx_timedwait into single function.
This commit is contained in:
David Xu 2005-01-14 13:38:15 +00:00
parent 665fc054fd
commit b7be40d612
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=140245
2 changed files with 55 additions and 56 deletions

View File

@ -525,28 +525,30 @@ _do_lock(struct thread *td, struct umtx *umtx, long id, int timo)
static int static int
do_lock(struct thread *td, struct umtx *umtx, long id, 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; struct timeval tv;
int timo, error; int error;
if (abstime == NULL) { if (timeout == NULL) {
error = _do_lock(td, umtx, id, 0); error = _do_lock(td, umtx, id, 0);
} else { } else {
getnanouptime(&ts);
timespecadd(&ts, timeout);
TIMESPEC_TO_TIMEVAL(&tv, timeout);
for (;;) { for (;;) {
ts1 = *abstime; error = _do_lock(td, umtx, id, tvtohz(&tv));
getnanotime(&ts2); if (error != ETIMEDOUT)
timespecsub(&ts1, &ts2); break;
TIMESPEC_TO_TIMEVAL(&tv, &ts1); getnanouptime(&ts2);
if (tv.tv_sec < 0) { if (timespeccmp(&ts2, &ts, >=)) {
error = ETIMEDOUT; error = ETIMEDOUT;
break; break;
} }
timo = tvtohz(&tv); ts3 = ts;
error = _do_lock(td, umtx, id, timo); timespecsub(&ts3, &ts2);
if (error != ETIMEDOUT) TIMESPEC_TO_TIMEVAL(&tv, &ts3);
break;
} }
} }
/* /*
@ -610,13 +612,13 @@ do_unlock(struct thread *td, struct umtx *umtx, long id)
} }
static int 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 umtx_q uq;
struct timespec ts1, ts2; struct timespec ts, ts2, ts3;
struct timeval tv; struct timeval tv;
long tmp; long tmp;
int timo, error = 0; int error = 0;
if ((error = umtxq_queue_me(td, umtx, &uq)) != 0) if ((error = umtxq_queue_me(td, umtx, &uq)) != 0)
return (error); 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_lock(&uq.uq_key);
umtxq_remove(&uq); umtxq_remove(&uq);
umtxq_unlock(&uq.uq_key); umtxq_unlock(&uq.uq_key);
} else if (abstime == NULL) { } else if (timeout == NULL) {
umtxq_lock(&uq.uq_key); umtxq_lock(&uq.uq_key);
if (td->td_flags & TDF_UMTXQ) if (td->td_flags & TDF_UMTXQ)
error = umtxq_sleep(td, &uq.uq_key, 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_remove(&uq);
umtxq_unlock(&uq.uq_key); umtxq_unlock(&uq.uq_key);
} else { } else {
getnanouptime(&ts);
timespecadd(&ts, timeout);
TIMESPEC_TO_TIMEVAL(&tv, timeout);
for (;;) { for (;;) {
ts1 = *abstime;
getnanotime(&ts2);
timespecsub(&ts1, &ts2);
TIMESPEC_TO_TIMEVAL(&tv, &ts1);
umtxq_lock(&uq.uq_key); 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; error = ETIMEDOUT;
break; break;
} }
timo = tvtohz(&tv); ts3 = ts;
if (td->td_flags & TDF_UMTXQ) timespecsub(&ts3, &ts2);
error = umtxq_sleep(td, &uq.uq_key, TIMESPEC_TO_TIMEVAL(&tv, &ts3);
td->td_priority | PCATCH,
"ucond", timo);
if (error != ETIMEDOUT || !(td->td_flags & TDF_UMTXQ))
break;
umtxq_unlock(&uq.uq_key);
} }
if (!(td->td_flags & TDF_UMTXQ)) umtxq_lock(&uq.uq_key);
error = 0; umtxq_remove(&uq);
else
umtxq_remove(&uq);
umtxq_unlock(&uq.uq_key); umtxq_unlock(&uq.uq_key);
} }
out:
umtx_key_release(&uq.uq_key); umtx_key_release(&uq.uq_key);
if (error == ERESTART) if (error == ERESTART)
error = EINTR; error = EINTR;
@ -699,7 +707,7 @@ _umtx_unlock(struct thread *td, struct _umtx_unlock_args *uap)
int int
_umtx_op(struct thread *td, struct _umtx_op_args *uap) _umtx_op(struct thread *td, struct _umtx_op_args *uap)
{ {
struct timespec abstime; struct timespec timeout;
struct timespec *ts; struct timespec *ts;
int error; int error;
@ -709,18 +717,15 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap)
if (uap->uaddr2 == NULL) if (uap->uaddr2 == NULL)
ts = NULL; ts = NULL;
else { else {
error = copyin(uap->uaddr2, &abstime, sizeof(abstime)); error = copyin(uap->uaddr2, &timeout, sizeof(timeout));
if (error != 0) if (error != 0)
break; break;
#if 0 if (timeout.tv_nsec >= 1000000000 ||
printf("uap->abstime: %d.%ld\n", abstime.tv_sec, abstime.tv_nsec); timeout.tv_nsec < 0) {
#endif
if (abstime.tv_nsec >= 1000000000 ||
abstime.tv_nsec < 0) {
error = EINVAL; error = EINVAL;
break; break;
} }
ts = &abstime; ts = &timeout;
} }
error = do_lock(td, uap->umtx, uap->id, ts); error = do_lock(td, uap->umtx, uap->id, ts);
break; break;
@ -732,15 +737,15 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap)
if (uap->uaddr2 == NULL) if (uap->uaddr2 == NULL)
ts = NULL; ts = NULL;
else { else {
error = copyin(uap->uaddr2, &abstime, sizeof(abstime)); error = copyin(uap->uaddr2, &timeout, sizeof(timeout));
if (error != 0) if (error != 0)
break; break;
if (abstime.tv_nsec >= 1000000000 || if (timeout.tv_nsec >= 1000000000 ||
abstime.tv_nsec < 0) { timeout.tv_nsec < 0) {
error = EINVAL; error = EINVAL;
break; break;
} }
ts = &abstime; ts = &timeout;
} }
error = do_wait(td, uap->umtx, uap->id, ts); error = do_wait(td, uap->umtx, uap->id, ts);
break; break;

View File

@ -95,11 +95,11 @@ umtx_trylock(struct umtx *umtx, long id)
} }
static __inline int 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, if (atomic_cmpset_acq_ptr(&umtx->u_owner, (void *)UMTX_UNOWNED,
(void *)id) == 0) (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); return (0);
} }
@ -113,15 +113,9 @@ umtx_unlock(struct umtx *umtx, long id)
} }
static __inline int 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)); return (- _umtx_op(umtx, UMTX_OP_WAIT, id, 0, timeout));
}
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));
} }
/* Wake threads waiting on a user address. */ /* Wake threads waiting on a user address. */