summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_futex.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-05-23 08:33:06 +0000
committerkib <kib@FreeBSD.org>2007-05-23 08:33:06 +0000
commitcdee790df9aefa589048c813a730fb95c714bd3a (patch)
tree9e0211f55a99ffc4fef4f84e9c3b74e63cc9cbc6 /sys/compat/linux/linux_futex.c
parent253a9fb8b6b9af702912dffa3b9addcd79d4618b (diff)
downloadFreeBSD-src-cdee790df9aefa589048c813a730fb95c714bd3a.zip
FreeBSD-src-cdee790df9aefa589048c813a730fb95c714bd3a.tar.gz
Move futex support code from <arch>/support.s into linux compat directory.
Implement all futex atomic operations in assembler to not depend on the fuword() that does not allow to distinguish between -1 and failure return. Correctly return 0 from atomic operations on success. In collaboration with: rdivacky Tested by: Scot Hetzel <swhetzel gmail com>, Milos Vyletel <mvyletel mzm cz> Sponsored by: Google SoC 2007
Diffstat (limited to 'sys/compat/linux/linux_futex.c')
-rw-r--r--sys/compat/linux/linux_futex.c113
1 files changed, 38 insertions, 75 deletions
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c
index f3fe997..be719b8 100644
--- a/sys/compat/linux/linux_futex.c
+++ b/sys/compat/linux/linux_futex.c
@@ -90,13 +90,13 @@ static void futex_put(struct futex *);
static int futex_sleep(struct futex *, struct thread *, unsigned long);
static int futex_wake(struct futex *, int, struct futex *, int);
static int futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr);
-static int futex_orl(int oparg, caddr_t uaddr, int *oldval);
-static int futex_andl(int oparg, caddr_t uaddr, int *oldval);
-static int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
/* support.s */
int futex_xchgl(int oparg, caddr_t uaddr, int *oldval);
int futex_addl(int oparg, caddr_t uaddr, int *oldval);
+int futex_orl(int oparg, caddr_t uaddr, int *oldval);
+int futex_andl(int oparg, caddr_t uaddr, int *oldval);
+int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
int
linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
@@ -114,8 +114,8 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
#ifdef DEBUG
if (ldebug(sys_futex))
- printf(ARGS(futex, "%p, %i, %i"), args->uaddr, args->op,
- args->val);
+ printf(ARGS(futex, "%p, %i, %i, *, %p, %i"), args->uaddr, args->op,
+ args->val, args->uaddr2, args->val3);
#endif
switch (args->op) {
@@ -274,7 +274,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
#ifdef DEBUG
if (ldebug(sys_futex))
printf("FUTEX_WAKE_OP: %d: uaddr = %p, op = %d, "
- "val = %d, uaddr2 = %p, val3 = %d\n",
+ "val = %x, uaddr2 = %p, val3 = %x\n",
td->td_proc->p_pid, args->uaddr, args->op,
args->val, args->uaddr2, args->val3);
#endif
@@ -286,8 +286,11 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
* negative as errors
*/
op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
+#ifdef DEBUG
+ if (ldebug(sys_futex))
+ printf("futex_atomic_op ret %d\n", op_ret);
+#endif
if (op_ret < 0) {
-
/* XXX: We don't handle the EFAULT yet. */
if (op_ret != -EFAULT) {
futex_put(f);
@@ -301,7 +304,6 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
FUTEX_SYSTEM_UNLOCK;
return (EFAULT);
-
}
ret = futex_wake(f, args->val, NULL, 0);
@@ -327,7 +329,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
args->op);
break;
}
- return 0;
+ return (0);
}
static struct futex *
@@ -401,9 +403,12 @@ futex_sleep(struct futex *f, struct thread *td, unsigned long timeout)
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
FUTEX_UNLOCK;
+ /* if we got woken up in futex_wake */
if ((ret == 0) && (wp->wp_new_futex != NULL)) {
+ /* suspend us on the new futex */
ret = futex_sleep(wp->wp_new_futex, td, timeout);
- futex_put(wp->wp_new_futex); /* futex_get called in wakeup */
+ /* and release the old one */
+ futex_put(wp->wp_new_futex);
}
free(wp, M_LINUX);
@@ -458,8 +463,10 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
oparg = 1 << oparg;
#ifdef DEBUG
- printf("futex_atomic_op: op = %d, cmp = %d, oparg = %d, cmparg = %d, "
- "uaddr = %p\n", op, cmp, oparg, cmparg, uaddr);
+ if (ldebug(sys_futex))
+ printf("futex_atomic_op: op = %d, cmp = %d, oparg = %x, "
+ "cmparg = %x, uaddr = %p\n",
+ op, cmp, oparg, cmparg, uaddr);
#endif
/* XXX: linux verifies access here and returns EFAULT */
@@ -481,70 +488,26 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
break;
default:
ret = -ENOSYS;
+ break;
}
- if (!ret)
- switch (cmp) {
- case FUTEX_OP_CMP_EQ:
- ret = (oldval == cmparg);
- break;
- case FUTEX_OP_CMP_NE:
- ret = (oldval != cmparg);
- break;
- case FUTEX_OP_CMP_LT:
- ret = (oldval < cmparg);
- break;
- case FUTEX_OP_CMP_GE:
- ret = (oldval >= cmparg);
- break;
- case FUTEX_OP_CMP_LE:
- ret = (oldval <= cmparg);
- break;
- case FUTEX_OP_CMP_GT:
- ret = (oldval > cmparg);
- break;
- default:
- ret = -ENOSYS;
- }
-
- return (ret);
-}
-
-static int
-futex_orl(int oparg, caddr_t uaddr, int *oldval)
-{
- uint32_t ua, ua_old;
-
- for (;;) {
- ua = ua_old = fuword32(uaddr);
- ua |= oparg;
- if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
- return ua_old;
- }
-}
-
-static int
-futex_andl(int oparg, caddr_t uaddr, int *oldval)
-{
- uint32_t ua, ua_old;
-
- for (;;) {
- ua = ua_old = fuword32(uaddr);
- ua &= oparg;
- if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
- return ua_old;
- }
-}
-
-static int
-futex_xorl(int oparg, caddr_t uaddr, int *oldval)
-{
- uint32_t ua, ua_old;
-
- for (;;) {
- ua = ua_old = fuword32(uaddr);
- ua ^= oparg;
- if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
- return ua_old;
+ if (ret)
+ return (ret);
+
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ:
+ return (oldval == cmparg);
+ case FUTEX_OP_CMP_NE:
+ return (oldval != cmparg);
+ case FUTEX_OP_CMP_LT:
+ return (oldval < cmparg);
+ case FUTEX_OP_CMP_GE:
+ return (oldval >= cmparg);
+ case FUTEX_OP_CMP_LE:
+ return (oldval <= cmparg);
+ case FUTEX_OP_CMP_GT:
+ return (oldval > cmparg);
+ default:
+ return (-ENOSYS);
}
}
OpenPOWER on IntegriCloud