--- b/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -680,19 +680,67 @@ futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr) switch (op) { case FUTEX_OP_SET: - ret = futex_xchgl(oparg, uaddr, &oldval); +// ret = futex_xchgl(oparg, uaddr, &oldval); + + ret = fueword32(uaddr, &oldval); + if (ret != 0) + return (ret); + oldval = atomic_swap_int(&oldval, oparg); + ret = suword32(uaddr, oldval); + if (ret != 0) + return (ret); + break; case FUTEX_OP_ADD: - ret = futex_addl(oparg, uaddr, &oldval); +// ret = futex_addl(oparg, uaddr, &oldval); + + ret = fueword32(uaddr, &oldval); + if (ret != 0) + return (ret); + oldval = atomic_fetchadd_int(&oldval, oparg); + ret = suword32(uaddr, oldval); + if (ret != 0) + return (ret); + break; case FUTEX_OP_OR: - ret = futex_orl(oparg, uaddr, &oldval); +// ret = futex_orl(oparg, uaddr, &oldval); + + ret = fueword32(uaddr, &oldval); + if (ret != 0) + return (ret); + while (!atomic_fcmpset_int(&oldval, &oldval, oldval | oparg)) + ; + ret = suword32(uaddr, oldval); + if (ret != 0) + return (ret); + break; case FUTEX_OP_ANDN: - ret = futex_andl(~oparg, uaddr, &oldval); +// ret = futex_andl(~oparg, uaddr, &oldval); + + ret = fueword32(uaddr, &oldval); + if (ret != 0) + return (ret); + while (!atomic_fcmpset_int(&oldval, &oldval, oldval & (~oparg))) + ; + ret = suword32(uaddr, oldval); + if (ret != 0) + return (ret); + break; case FUTEX_OP_XOR: - ret = futex_xorl(oparg, uaddr, &oldval); +// ret = futex_xorl(oparg, uaddr, &oldval); + + ret = fueword32(uaddr, &oldval); + if (ret != 0) + return (ret); + while (!atomic_fcmpset_int(&oldval, &oldval, oldval ^ oparg)) + ; + ret = suword32(uaddr, oldval); + if (ret != 0) + return (ret); + break; default: LIN_SDT_PROBE1(futex, futex_atomic_op, unimplemented_op, op);