Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linux/linux_futex.c
Show All 40 Lines | |||||
__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $"); | __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $"); | ||||
#endif | #endif | ||||
#include "opt_compat.h" | #include "opt_compat.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/imgact.h> | #include <sys/imgact.h> | ||||
#include <sys/imgact_elf.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | struct linux_futex_args { | ||||
uint32_t *uaddr; | uint32_t *uaddr; | ||||
int32_t op; | int32_t op; | ||||
uint32_t flags; | uint32_t flags; | ||||
bool clockrt; | bool clockrt; | ||||
uint32_t val; | uint32_t val; | ||||
struct timespec *ts; | struct timespec *ts; | ||||
uint32_t *uaddr2; | uint32_t *uaddr2; | ||||
uint32_t val3; | uint32_t val3; | ||||
bool val3_compare; | |||||
struct timespec kts; | struct timespec kts; | ||||
}; | }; | ||||
static int linux_futex(struct thread *, struct linux_futex_args *); | static int linux_futex(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wait(struct thread *, struct linux_futex_args *); | static int linux_futex_wait(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wake(struct thread *, struct linux_futex_args *); | static int linux_futex_wake(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_requeue(struct thread *, struct linux_futex_args *); | static int linux_futex_requeue(struct thread *, struct linux_futex_args *); | ||||
static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); | static int linux_futex_wakeop(struct thread *, struct linux_futex_args *); | ||||
▲ Show 20 Lines • Show All 398 Lines • ▼ Show 20 Lines | futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr) | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
linux_futex(struct thread *td, struct linux_futex_args *args) | linux_futex(struct thread *td, struct linux_futex_args *args) | ||||
{ | { | ||||
struct linux_pemuldata *pem; | struct linux_pemuldata *pem; | ||||
struct proc *p; | |||||
if (args->op & LINUX_FUTEX_PRIVATE_FLAG) { | if (args->op & LINUX_FUTEX_PRIVATE_FLAG) { | ||||
args->flags = 0; | args->flags = 0; | ||||
args->op &= ~LINUX_FUTEX_PRIVATE_FLAG; | args->op &= ~LINUX_FUTEX_PRIVATE_FLAG; | ||||
} else | } else | ||||
args->flags = FUTEX_SHARED; | args->flags = FUTEX_SHARED; | ||||
/* | /* | ||||
Show All 22 Lines | case LINUX_FUTEX_WAIT_BITSET: | ||||
LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x", | LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x", | ||||
args->uaddr, args->val, args->val3); | args->uaddr, args->val, args->val3); | ||||
return (linux_futex_wait(td, args)); | return (linux_futex_wait(td, args)); | ||||
case LINUX_FUTEX_WAKE: | case LINUX_FUTEX_WAKE: | ||||
args->val3 = FUTEX_BITSET_MATCH_ANY; | args->val3 = FUTEX_BITSET_MATCH_ANY; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
dchagin: I think that comment is not needed here | |||||
case LINUX_FUTEX_WAKE_BITSET: | case LINUX_FUTEX_WAKE_BITSET: | ||||
LIN_SDT_PROBE3(futex, linux_futex, debug_wake, args->uaddr, | LIN_SDT_PROBE3(futex, linux_futex, debug_wake, args->uaddr, | ||||
args->val, args->val3); | args->val, args->val3); | ||||
LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x", | LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x", | ||||
args->uaddr, args->val, args->val3); | args->uaddr, args->val, args->val3); | ||||
return (linux_futex_wake(td, args)); | return (linux_futex_wake(td, args)); | ||||
case LINUX_FUTEX_REQUEUE: | |||||
/* | |||||
* Glibc does not use this operation since version 2.3.3, | |||||
* as it is racy and replaced by FUTEX_CMP_REQUEUE operation. | |||||
* Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when | |||||
* FUTEX_REQUEUE returned EINVAL. | |||||
*/ | |||||
pem = pem_find(td->td_proc); | |||||
if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { | |||||
linux_msg(td, "unsupported FUTEX_REQUEUE"); | |||||
pem->flags |= LINUX_XDEPR_REQUEUEOP; | |||||
LIN_SDT_PROBE0(futex, linux_futex, | |||||
deprecated_requeue); | |||||
} | |||||
/* | |||||
* The above is true, however musl libc does make use of the | |||||
* futex requeue operation, allow operation for brands which | |||||
* set LINUX_BI_FUTEX_REQUEUE bit of Brandinfo flags. | |||||
*/ | |||||
p = td->td_proc; | |||||
Elf_Brandinfo *bi = p->p_elf_brandinfo; | |||||
if (bi == NULL || ((bi->flags & LINUX_BI_FUTEX_REQUEUE)) == 0) | |||||
return (EINVAL); | |||||
args->val3_compare = false; | |||||
/* FALLTHROUGH */ | |||||
case LINUX_FUTEX_CMP_REQUEUE: | case LINUX_FUTEX_CMP_REQUEUE: | ||||
LIN_SDT_PROBE5(futex, linux_futex, debug_cmp_requeue, | LIN_SDT_PROBE5(futex, linux_futex, debug_cmp_requeue, | ||||
args->uaddr, args->val, args->val3, args->uaddr2, | args->uaddr, args->val, args->val3, args->uaddr2, | ||||
args->ts); | args->ts); | ||||
LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " | LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " | ||||
"nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x", | "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x", | ||||
args->uaddr, args->val, args->val3, args->uaddr2, | args->uaddr, args->val, args->val3, args->uaddr2, | ||||
args->ts); | args->ts); | ||||
Show All 38 Lines | case LINUX_FUTEX_TRYLOCK_PI: | ||||
if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { | if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { | ||||
linux_msg(td, "unsupported FUTEX_TRYLOCK_PI"); | linux_msg(td, "unsupported FUTEX_TRYLOCK_PI"); | ||||
pem->flags |= LINUX_XUNSUP_FUTEXPIOP; | pem->flags |= LINUX_XUNSUP_FUTEXPIOP; | ||||
LIN_SDT_PROBE0(futex, linux_futex, | LIN_SDT_PROBE0(futex, linux_futex, | ||||
unimplemented_trylock_pi); | unimplemented_trylock_pi); | ||||
} | } | ||||
return (ENOSYS); | return (ENOSYS); | ||||
case LINUX_FUTEX_REQUEUE: | |||||
/* | |||||
* Glibc does not use this operation since version 2.3.3, | |||||
* as it is racy and replaced by FUTEX_CMP_REQUEUE operation. | |||||
* Glibc versions prior to 2.3.3 fall back to FUTEX_WAKE when | |||||
* FUTEX_REQUEUE returned EINVAL. | |||||
*/ | |||||
pem = pem_find(td->td_proc); | |||||
if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { | |||||
linux_msg(td, "unsupported FUTEX_REQUEUE"); | |||||
pem->flags |= LINUX_XDEPR_REQUEUEOP; | |||||
LIN_SDT_PROBE0(futex, linux_futex, | |||||
deprecated_requeue); | |||||
} | |||||
return (EINVAL); | |||||
case LINUX_FUTEX_WAIT_REQUEUE_PI: | case LINUX_FUTEX_WAIT_REQUEUE_PI: | ||||
/* not yet implemented */ | /* not yet implemented */ | ||||
pem = pem_find(td->td_proc); | pem = pem_find(td->td_proc); | ||||
if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { | if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { | ||||
linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI"); | linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI"); | ||||
pem->flags |= LINUX_XUNSUP_FUTEXPIOP; | pem->flags |= LINUX_XUNSUP_FUTEXPIOP; | ||||
LIN_SDT_PROBE0(futex, linux_futex, | LIN_SDT_PROBE0(futex, linux_futex, | ||||
unimplemented_wait_requeue_pi); | unimplemented_wait_requeue_pi); | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | if (error != 0) { | ||||
if (error == 0) | if (error == 0) | ||||
goto retry; | goto retry; | ||||
LIN_SDT_PROBE1(futex, linux_futex, copyin_error, | LIN_SDT_PROBE1(futex, linux_futex, copyin_error, | ||||
error); | error); | ||||
LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d", | LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d", | ||||
error); | error); | ||||
return (error); | return (error); | ||||
} | } | ||||
if (val != args->val3) { | if (args->val3_compare == true && val != args->val3) { | ||||
LIN_SDT_PROBE2(futex, linux_futex, | LIN_SDT_PROBE2(futex, linux_futex, | ||||
debug_cmp_requeue_value_neq, args->val, val); | debug_cmp_requeue_value_neq, args->val, val); | ||||
LINUX_CTR2(sys_futex, "CMP_REQUEUE val 0x%x != uval 0x%x", | LINUX_CTR2(sys_futex, "CMP_REQUEUE val 0x%x != uval 0x%x", | ||||
args->val, val); | args->val, val); | ||||
futex_put(f2, NULL); | futex_put(f2, NULL); | ||||
futex_put(f, NULL); | futex_put(f, NULL); | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct linux_futex_args fargs = { | struct linux_futex_args fargs = { | ||||
.uaddr = args->uaddr, | .uaddr = args->uaddr, | ||||
.op = args->op, | .op = args->op, | ||||
.val = args->val, | .val = args->val, | ||||
.ts = NULL, | .ts = NULL, | ||||
.uaddr2 = args->uaddr2, | .uaddr2 = args->uaddr2, | ||||
.val3 = args->val3, | .val3 = args->val3, | ||||
.val3_compare = true, | |||||
}; | }; | ||||
struct l_timespec lts; | struct l_timespec lts; | ||||
int error; | int error; | ||||
switch (args->op & LINUX_FUTEX_CMD_MASK) { | switch (args->op & LINUX_FUTEX_CMD_MASK) { | ||||
case LINUX_FUTEX_WAIT: | case LINUX_FUTEX_WAIT: | ||||
case LINUX_FUTEX_WAIT_BITSET: | case LINUX_FUTEX_WAIT_BITSET: | ||||
if (args->timeout != NULL) { | if (args->timeout != NULL) { | ||||
▲ Show 20 Lines • Show All 228 Lines • Show Last 20 Lines |
I think that comment is not needed here