diff options
author | davidxu <davidxu@FreeBSD.org> | 2004-12-30 02:56:17 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2004-12-30 02:56:17 +0000 |
commit | 6724b46563fef45d02a9e243cc4a5cca18c47929 (patch) | |
tree | 22d29dee9179f84cb0e723a7232fab95ee560834 /sys/kern | |
parent | 3306580a191d802777ad3770ab16eb6e40ac98e9 (diff) | |
download | FreeBSD-src-6724b46563fef45d02a9e243cc4a5cca18c47929.zip FreeBSD-src-6724b46563fef45d02a9e243cc4a5cca18c47929.tar.gz |
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.
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_umtx.c | 50 |
1 files changed, 9 insertions, 41 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index e0502b8..3c45ddc 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); } |