From cc1000ac5b235516dd312340fca34e8847add3d0 Mon Sep 17 00:00:00 2001 From: David Xu Date: Thu, 30 Dec 2004 02:56:17 +0000 Subject: [PATCH] Make umtx_wait and umtx_wake more like linux futex does, it is more general than previous. It also lets me implement cancelable point in thread library. Also in theory, umtx_lock and umtx_unlock can be implemented by using umtx_wait and umtx_wake, all atomic operations can be done in userland without kernel's casuptr() function. --- sys/kern/kern_umtx.c | 50 ++++++++------------------------------------ sys/sys/umtx.h | 16 +++++++------- 2 files changed, 16 insertions(+), 50 deletions(-) diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index e0502b8e74ef..3c45ddc0af4e 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -608,53 +608,22 @@ do_unlock(struct thread *td, struct umtx *umtx, long id) } static int -do_unlock_and_wait(struct thread *td, struct umtx *umtx, long id, void *uaddr, - struct timespec *abstime) +do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *abstime) { struct umtx_q uq; - intptr_t owner; - intptr_t old; struct timespec ts1, ts2; struct timeval tv; + long tmp; int timo, error = 0; - if (umtx == uaddr) - return (EINVAL); - - /* - * Make sure we own this mtx. - * - * XXX Need a {fu,su}ptr this is not correct on arch where - * sizeof(intptr_t) != sizeof(long). - */ - if ((owner = fuword(&umtx->u_owner)) == -1) - return (EFAULT); - - if ((owner & ~UMTX_CONTESTED) != id) - return (EPERM); - - if ((error = umtxq_queue_me(td, uaddr, &uq)) != 0) + if ((error = umtxq_queue_me(td, umtx, &uq)) != 0) return (error); - - old = casuptr((intptr_t *)&umtx->u_owner, id, UMTX_UNOWNED); - if (old == -1) { + tmp = fuword(&umtx->u_owner); + if (tmp != id) { umtxq_lock(&uq.uq_key); umtxq_remove(&uq); umtxq_unlock(&uq.uq_key); - umtx_key_release(&uq.uq_key); - return (EFAULT); - } - if (old != id) { - error = do_unlock(td, umtx, id); - if (error) { - umtxq_lock(&uq.uq_key); - umtxq_remove(&uq); - umtxq_unlock(&uq.uq_key); - umtx_key_release(&uq.uq_key); - return (error); - } - } - if (abstime == NULL) { + } else if (abstime == NULL) { umtxq_lock(&uq.uq_key); if (td->td_flags & TDF_UMTXQ) error = umtxq_sleep(td, &uq.uq_key, @@ -750,7 +719,7 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap) return do_lock(td, uap->umtx, uap->id, ts); case UMTX_OP_UNLOCK: return do_unlock(td, uap->umtx, uap->id); - case UMTX_OP_UNLOCK_AND_WAIT: + case UMTX_OP_WAIT: /* Allow a null timespec (wait forever). */ if (uap->uaddr2 == NULL) ts = NULL; @@ -763,10 +732,9 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap) return (EINVAL); ts = &abstime; } - return do_unlock_and_wait(td, uap->umtx, uap->id, - uap->uaddr, ts); + return do_wait(td, uap->umtx, uap->id, ts); case UMTX_OP_WAKE: - return do_wake(td, uap->uaddr, uap->id); + return do_wake(td, uap->umtx, uap->id); default: return (EINVAL); } diff --git a/sys/sys/umtx.h b/sys/sys/umtx.h index cfac53187cd7..dad0f18e0ce9 100644 --- a/sys/sys/umtx.h +++ b/sys/sys/umtx.h @@ -46,7 +46,7 @@ struct umtx { /* op code for _umtx_op */ #define UMTX_OP_LOCK 0 #define UMTX_OP_UNLOCK 1 -#define UMTX_OP_UNLOCK_AND_WAIT 2 +#define UMTX_OP_WAIT 2 #define UMTX_OP_WAKE 3 #ifndef _KERNEL @@ -118,29 +118,27 @@ umtx_unlock(struct umtx *umtx, long id) /* Unlock umtx and wait on a user address. */ static __inline int -umtx_wait(struct umtx *umtx, long id, void *uaddr) +umtx_wait(struct umtx *umtx, long id) { - if (_umtx_op(umtx, UMTX_OP_UNLOCK_AND_WAIT, id, uaddr, 0) == -1) + if (_umtx_op(umtx, UMTX_OP_WAIT, id, 0, 0) == -1) return (errno); return (0); } static __inline int -umtx_timedwait(struct umtx *umtx, long id, void *uaddr, - const struct timespec *abstime) +umtx_timedwait(struct umtx *umtx, long id, const struct timespec *abstime) { - if (_umtx_op(umtx, UMTX_OP_UNLOCK_AND_WAIT, id, uaddr, - (void *)abstime) == -1) + if (_umtx_op(umtx, UMTX_OP_WAIT, id, 0, (void *)abstime) == -1) return (errno); return (0); } /* Wake threads waiting on a user address. */ static __inline int -umtx_wake(void *uaddr, int nr_wakeup) +umtx_wake(struct umtx *umtx, int nr_wakeup) { /* return how many threads were woke up, -1 if error */ - return _umtx_op(0, UMTX_OP_WAKE, nr_wakeup, uaddr, 0); + return _umtx_op(umtx, UMTX_OP_WAKE, nr_wakeup, 0, 0); } #endif /* !_KERNEL */