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:
parent
665fc054fd
commit
b7be40d612
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=140245
@ -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;
|
|
||||||
else
|
|
||||||
umtxq_remove(&uq);
|
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;
|
||||||
|
@ -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. */
|
||||||
|
Loading…
Reference in New Issue
Block a user