diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b5f669e282..673eed4ece 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4026,14 +4026,16 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, target_ulong uaddr2, int val3) { struct timespec ts, *pts; + int base_op; /* ??? We assume FUTEX_* constants are the same on both host and target. */ #ifdef FUTEX_CMD_MASK - switch ((op&FUTEX_CMD_MASK)) { + base_op = op & FUTEX_CMD_MASK; #else - switch (op) { + base_op = op; #endif + switch (base_op) { case FUTEX_WAIT: if (timeout) { pts = &ts; @@ -4045,16 +4047,22 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, pts, NULL, 0)); case FUTEX_WAKE: return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); - case FUTEX_WAKE_OP: - return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), val3 )); case FUTEX_FD: return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); case FUTEX_REQUEUE: - return get_errno(sys_futex(g2h(uaddr), op, val, - NULL, g2h(uaddr2), 0)); case FUTEX_CMP_REQUEUE: - return get_errno(sys_futex(g2h(uaddr), op, val, - NULL, g2h(uaddr2), tswap32(val3))); + case FUTEX_WAKE_OP: + /* For FUTEX_REQUEUE, FUTEX_CMP_REQUEUE, and FUTEX_WAKE_OP, the + TIMEOUT parameter is interpreted as a uint32_t by the kernel. + But the prototype takes a `struct timespec *'; insert casts + to satisfy the compiler. We do not need to tswap TIMEOUT + since it's not compared to guest memory. */ + pts = (struct timespec *)(uintptr_t) timeout; + return get_errno(sys_futex(g2h(uaddr), op, val, pts, + g2h(uaddr2), + (base_op == FUTEX_CMP_REQUEUE + ? tswap32(val3) + : val3))); default: return -TARGET_ENOSYS; } |