Changeset View
Standalone View
sys/kern/kern_umtx.c
Show First 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | |||||
struct abs_timeout { | struct abs_timeout { | ||||
int clockid; | int clockid; | ||||
bool is_abs_real; /* TIMER_ABSTIME && CLOCK_REALTIME* */ | bool is_abs_real; /* TIMER_ABSTIME && CLOCK_REALTIME* */ | ||||
struct timespec cur; | struct timespec cur; | ||||
struct timespec end; | struct timespec end; | ||||
}; | }; | ||||
#ifdef COMPAT_FREEBSD32 | |||||
struct umutex32 { | |||||
volatile __lwpid_t m_owner; /* Owner of the mutex */ | |||||
__uint32_t m_flags; /* Flags of the mutex */ | |||||
__uint32_t m_ceilings[2]; /* Priority protect ceiling */ | |||||
__uint32_t m_rb_lnk; /* Robust linkage */ | |||||
__uint32_t m_pad; | |||||
__uint32_t m_spare[2]; | |||||
}; | |||||
_Static_assert(sizeof(struct umutex) == sizeof(struct umutex32), "umutex32"); | _Static_assert(sizeof(struct umutex) == sizeof(struct umutex32), "umutex32"); | ||||
_Static_assert(__offsetof(struct umutex, m_spare[0]) == | _Static_assert(__offsetof(struct umutex, m_spare[0]) == | ||||
__offsetof(struct umutex32, m_spare[0]), "m_spare32"); | __offsetof(struct umutex32, m_spare[0]), "m_spare32"); | ||||
#endif | |||||
kib: Why is NEED_UMTX32 needed ?
Can't you continue to use COMPAT_FREEBSD32 ? Or even drop this… | |||||
Done Inline ActionsThis one ended up looking weird because of how the patch evolved and I had to split this part back up, but the next patch (D27223) will add LP64 here as it wants the compat32 definitions as well as the equivalents for "other" compat32 (i.e. non-i386 vs. i386). I think the end result ended up using it in few enough places that there's no problem with just changing those to || defined(__LP64__) kevans: This one ended up looking weird because of how the patch evolved and I had to split this part… | |||||
int umtx_shm_vnobj_persistent = 0; | int umtx_shm_vnobj_persistent = 0; | ||||
SYSCTL_INT(_kern_ipc, OID_AUTO, umtx_vnode_persistent, CTLFLAG_RWTUN, | SYSCTL_INT(_kern_ipc, OID_AUTO, umtx_vnode_persistent, CTLFLAG_RWTUN, | ||||
Done Inline ActionsI assume all addr are user addresses ? Might be call parameters uaddr ? kib: I assume all `addr` are user addresses ? Might be call parameters `uaddr` ? | |||||
&umtx_shm_vnobj_persistent, 0, | &umtx_shm_vnobj_persistent, 0, | ||||
"False forces destruction of umtx attached to file, on last close"); | "False forces destruction of umtx attached to file, on last close"); | ||||
static int umtx_max_rb = 1000; | static int umtx_max_rb = 1000; | ||||
SYSCTL_INT(_kern_ipc, OID_AUTO, umtx_max_robust, CTLFLAG_RWTUN, | SYSCTL_INT(_kern_ipc, OID_AUTO, umtx_max_robust, CTLFLAG_RWTUN, | ||||
&umtx_max_rb, 0, | &umtx_max_rb, 0, | ||||
"Maximum number of robust mutexes allowed for each thread"); | "Maximum number of robust mutexes allowed for each thread"); | ||||
static uma_zone_t umtx_pi_zone; | static uma_zone_t umtx_pi_zone; | ||||
▲ Show 20 Lines • Show All 3,148 Lines • ▼ Show 20 Lines | do_sem2_wake(struct thread *td, struct _usem2 *sem) | ||||
} | } | ||||
umtxq_unbusy(&key); | umtxq_unbusy(&key); | ||||
umtxq_unlock(&key); | umtxq_unlock(&key); | ||||
umtx_key_release(&key); | umtx_key_release(&key); | ||||
return (error); | return (error); | ||||
} | } | ||||
inline int | inline int | ||||
umtx_copyin_timeout(const void *addr, struct timespec *tsp) | umtx_copyin_timeout(const void *uaddr, struct timespec *tsp) | ||||
{ | { | ||||
int error; | int error; | ||||
error = copyin(addr, tsp, sizeof(struct timespec)); | error = copyin(uaddr, tsp, sizeof(*tsp)); | ||||
if (error == 0) { | if (error == 0) { | ||||
if (tsp->tv_sec < 0 || | if (tsp->tv_sec < 0 || | ||||
tsp->tv_nsec >= 1000000000 || | tsp->tv_nsec >= 1000000000 || | ||||
tsp->tv_nsec < 0) | tsp->tv_nsec < 0) | ||||
error = EINVAL; | error = EINVAL; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static inline int | static inline int | ||||
umtx_copyin_umtx_time(const void *addr, size_t size, struct _umtx_time *tp) | umtx_copyin_umtx_time(const void *uaddr, size_t size, struct _umtx_time *tp) | ||||
{ | { | ||||
int error; | int error; | ||||
if (size <= sizeof(struct timespec)) { | if (size <= sizeof(tp->_timeout)) { | ||||
tp->_clockid = CLOCK_REALTIME; | tp->_clockid = CLOCK_REALTIME; | ||||
tp->_flags = 0; | tp->_flags = 0; | ||||
error = copyin(addr, &tp->_timeout, sizeof(struct timespec)); | error = copyin(uaddr, &tp->_timeout, sizeof(tp->_timeout)); | ||||
} else | } else | ||||
error = copyin(addr, tp, sizeof(struct _umtx_time)); | error = copyin(uaddr, tp, sizeof(*tp)); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (tp->_timeout.tv_sec < 0 || | if (tp->_timeout.tv_sec < 0 || | ||||
tp->_timeout.tv_nsec >= 1000000000 || tp->_timeout.tv_nsec < 0) | tp->_timeout.tv_nsec >= 1000000000 || tp->_timeout.tv_nsec < 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_unimpl(struct thread *td, struct _umtx_op_args *uap) | umtx_copyin_robust_lists(const void *uaddr, size_t size, | ||||
struct umtx_robust_lists_params *rb) | |||||
{ | { | ||||
if (size > sizeof(*rb)) | |||||
return (EINVAL); | |||||
return (copyin(uaddr, &rb, size)); | |||||
} | |||||
static int | |||||
umtx_copyout_timeout(void *uaddr, size_t sz, struct timespec *tsp) | |||||
{ | |||||
KASSERT(sz >= sizeof(*tsp), | |||||
("_umtx_copyops specifies incorrect sizes")); | |||||
return (copyout(tsp, uaddr, sizeof(*tsp))); | |||||
} | |||||
static int | |||||
__umtx_op_unimpl(struct thread *td, struct _umtx_op_args *uap, | |||||
const struct _umtx_copyops *ops __unused) | |||||
{ | |||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wait(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wait(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time timeout, *tm_p; | struct _umtx_time timeout, *tm_p; | ||||
int error; | int error; | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_wait(td, uap->obj, uap->val, tm_p, 0, 0)); | return (do_wait(td, uap->obj, uap->val, tm_p, ops->compat32, 0)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wait_uint(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wait_uint(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time timeout, *tm_p; | struct _umtx_time timeout, *tm_p; | ||||
int error; | int error; | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_wait(td, uap->obj, uap->val, tm_p, 1, 0)); | return (do_wait(td, uap->obj, uap->val, tm_p, 1, 0)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wait_uint_private(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wait_uint_private(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct _umtx_time *tm_p, timeout; | ||||
int error; | int error; | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_wait(td, uap->obj, uap->val, tm_p, 1, 1)); | return (do_wait(td, uap->obj, uap->val, tm_p, 1, 1)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wake(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wake(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (kern_umtx_wake(td, uap->obj, uap->val, 0)); | return (kern_umtx_wake(td, uap->obj, uap->val, 0)); | ||||
} | } | ||||
#define BATCH_SIZE 128 | #define BATCH_SIZE 128 | ||||
static int | static int | ||||
__umtx_op_nwake_private(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_nwake_private_native(struct thread *td, struct _umtx_op_args *uap) | ||||
{ | { | ||||
char *uaddrs[BATCH_SIZE], **upp; | char *uaddrs[BATCH_SIZE], **upp; | ||||
int count, error, i, pos, tocopy; | int count, error, i, pos, tocopy; | ||||
upp = (char **)uap->obj; | upp = (char **)uap->obj; | ||||
error = 0; | error = 0; | ||||
for (count = uap->val, pos = 0; count > 0; count -= tocopy, | for (count = uap->val, pos = 0; count > 0; count -= tocopy, | ||||
pos += tocopy) { | pos += tocopy) { | ||||
tocopy = MIN(count, BATCH_SIZE); | tocopy = MIN(count, BATCH_SIZE); | ||||
error = copyin(upp + pos, uaddrs, tocopy * sizeof(char *)); | error = copyin(upp + pos, uaddrs, tocopy * sizeof(char *)); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
for (i = 0; i < tocopy; ++i) | for (i = 0; i < tocopy; ++i) | ||||
kern_umtx_wake(td, uaddrs[i], INT_MAX, 1); | kern_umtx_wake(td, uaddrs[i], INT_MAX, 1); | ||||
maybe_yield(); | maybe_yield(); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wake_private(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_nwake_private_compat32(struct thread *td, struct _umtx_op_args *uap) | ||||
{ | { | ||||
uint32_t uaddrs[BATCH_SIZE], **upp; | |||||
int count, error, i, pos, tocopy; | |||||
upp = (uint32_t **)uap->obj; | |||||
error = 0; | |||||
for (count = uap->val, pos = 0; count > 0; count -= tocopy, | |||||
pos += tocopy) { | |||||
tocopy = MIN(count, BATCH_SIZE); | |||||
error = copyin(upp + pos, uaddrs, tocopy * sizeof(uint32_t)); | |||||
if (error != 0) | |||||
break; | |||||
for (i = 0; i < tocopy; ++i) | |||||
kibUnsubmitted Done Inline ActionsCould you please add {} around loop body ? It is multi-line. kib: Could you please add {} around loop body ? It is multi-line. | |||||
kern_umtx_wake(td, (void *)(uintptr_t)uaddrs[i], | |||||
INT_MAX, 1); | |||||
maybe_yield(); | |||||
} | |||||
return (error); | |||||
} | |||||
static int | |||||
__umtx_op_nwake_private(struct thread *td, struct _umtx_op_args *uap, | |||||
const struct _umtx_copyops *ops) | |||||
{ | |||||
if (ops->compat32) | |||||
return (__umtx_op_nwake_private_compat32(td, uap)); | |||||
return (__umtx_op_nwake_private_native(td, uap)); | |||||
} | |||||
static int | |||||
__umtx_op_wake_private(struct thread *td, struct _umtx_op_args *uap, | |||||
const struct _umtx_copyops *ops __unused) | |||||
{ | |||||
return (kern_umtx_wake(td, uap->obj, uap->val, 1)); | return (kern_umtx_wake(td, uap->obj, uap->val, 1)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_lock_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_lock_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct _umtx_time *tm_p, timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_lock_umutex(td, uap->obj, tm_p, 0)); | return (do_lock_umutex(td, uap->obj, tm_p, 0)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_trylock_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_trylock_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_lock_umutex(td, uap->obj, NULL, _UMUTEX_TRY)); | return (do_lock_umutex(td, uap->obj, NULL, _UMUTEX_TRY)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wait_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wait_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct _umtx_time *tm_p, timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_lock_umutex(td, uap->obj, tm_p, _UMUTEX_WAIT)); | return (do_lock_umutex(td, uap->obj, tm_p, _UMUTEX_WAIT)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wake_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wake_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_wake_umutex(td, uap->obj)); | return (do_wake_umutex(td, uap->obj)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_unlock_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_unlock_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_unlock_umutex(td, uap->obj, false)); | return (do_unlock_umutex(td, uap->obj, false)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_set_ceiling(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_set_ceiling(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_set_ceiling(td, uap->obj, uap->val, uap->uaddr1)); | return (do_set_ceiling(td, uap->obj, uap->val, uap->uaddr1)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_cv_wait(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_cv_wait(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct timespec *ts, timeout; | struct timespec *ts, timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
ts = NULL; | ts = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_timeout(uap->uaddr2, &timeout); | error = ops->copyin_timeout(uap->uaddr2, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
ts = &timeout; | ts = &timeout; | ||||
} | } | ||||
return (do_cv_wait(td, uap->obj, uap->uaddr1, ts, uap->val)); | return (do_cv_wait(td, uap->obj, uap->uaddr1, ts, uap->val)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_cv_signal(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_cv_signal(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_cv_signal(td, uap->obj)); | return (do_cv_signal(td, uap->obj)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_cv_broadcast(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_cv_broadcast(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_cv_broadcast(td, uap->obj)); | return (do_cv_broadcast(td, uap->obj)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_rw_rdlock(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_rw_rdlock(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time timeout; | struct _umtx_time timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) { | if (uap->uaddr2 == NULL) { | ||||
error = do_rw_rdlock(td, uap->obj, uap->val, 0); | error = do_rw_rdlock(td, uap->obj, uap->val, 0); | ||||
} else { | } else { | ||||
error = umtx_copyin_umtx_time(uap->uaddr2, | error = ops->copyin_umtx_time(uap->uaddr2, | ||||
(size_t)uap->uaddr1, &timeout); | (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = do_rw_rdlock(td, uap->obj, uap->val, &timeout); | error = do_rw_rdlock(td, uap->obj, uap->val, &timeout); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_rw_wrlock(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_rw_wrlock(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time timeout; | struct _umtx_time timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) { | if (uap->uaddr2 == NULL) { | ||||
error = do_rw_wrlock(td, uap->obj, 0); | error = do_rw_wrlock(td, uap->obj, 0); | ||||
} else { | } else { | ||||
error = umtx_copyin_umtx_time(uap->uaddr2, | error = ops->copyin_umtx_time(uap->uaddr2, | ||||
(size_t)uap->uaddr1, &timeout); | (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = do_rw_wrlock(td, uap->obj, &timeout); | error = do_rw_wrlock(td, uap->obj, &timeout); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_rw_unlock(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_rw_unlock(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_rw_unlock(td, uap->obj)); | return (do_rw_unlock(td, uap->obj)); | ||||
} | } | ||||
#if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | #if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | ||||
static int | static int | ||||
__umtx_op_sem_wait(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_sem_wait(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct _umtx_time *tm_p, timeout; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) | if (uap->uaddr2 == NULL) | ||||
tm_p = NULL; | tm_p = NULL; | ||||
else { | else { | ||||
error = umtx_copyin_umtx_time( | error = ops->copyin_umtx_time( | ||||
uap->uaddr2, (size_t)uap->uaddr1, &timeout); | uap->uaddr2, (size_t)uap->uaddr1, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
return (do_sem_wait(td, uap->obj, tm_p)); | return (do_sem_wait(td, uap->obj, tm_p)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_sem_wake(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_sem_wake(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_sem_wake(td, uap->obj)); | return (do_sem_wake(td, uap->obj)); | ||||
} | } | ||||
#endif | #endif | ||||
static int | static int | ||||
__umtx_op_wake2_umutex(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_wake2_umutex(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_wake2_umutex(td, uap->obj, uap->val)); | return (do_wake2_umutex(td, uap->obj, uap->val)); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_sem2_wait(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_sem2_wait(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct _umtx_time *tm_p, timeout; | ||||
size_t uasize; | size_t uasize; | ||||
int error; | int error; | ||||
/* Allow a null timespec (wait forever). */ | /* Allow a null timespec (wait forever). */ | ||||
if (uap->uaddr2 == NULL) { | if (uap->uaddr2 == NULL) { | ||||
uasize = 0; | uasize = 0; | ||||
tm_p = NULL; | tm_p = NULL; | ||||
} else { | } else { | ||||
uasize = (size_t)uap->uaddr1; | uasize = (size_t)uap->uaddr1; | ||||
error = umtx_copyin_umtx_time(uap->uaddr2, uasize, &timeout); | error = ops->copyin_umtx_time(uap->uaddr2, uasize, &timeout); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | tm_p = &timeout; | ||||
} | } | ||||
error = do_sem2_wait(td, uap->obj, tm_p); | error = do_sem2_wait(td, uap->obj, tm_p); | ||||
if (error == EINTR && uap->uaddr2 != NULL && | if (error == EINTR && uap->uaddr2 != NULL && | ||||
(timeout._flags & UMTX_ABSTIME) == 0 && | (timeout._flags & UMTX_ABSTIME) == 0 && | ||||
uasize >= sizeof(struct _umtx_time) + sizeof(struct timespec)) { | uasize >= ops->umtx_time_sz + ops->timespec_sz) { | ||||
error = copyout(&timeout._timeout, | error = ops->copyout_timeout( | ||||
(struct _umtx_time *)uap->uaddr2 + 1, | (void *)((uintptr_t)uap->uaddr2 + ops->umtx_time_sz), | ||||
sizeof(struct timespec)); | uasize - ops->umtx_time_sz, &timeout._timeout); | ||||
if (error == 0) { | if (error == 0) { | ||||
error = EINTR; | error = EINTR; | ||||
} | } | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_sem2_wake(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_sem2_wake(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (do_sem2_wake(td, uap->obj)); | return (do_sem2_wake(td, uap->obj)); | ||||
} | } | ||||
#define USHM_OBJ_UMTX(o) \ | #define USHM_OBJ_UMTX(o) \ | ||||
((struct umtx_shm_obj_list *)(&(o)->umtx_data)) | ((struct umtx_shm_obj_list *)(&(o)->umtx_data)) | ||||
▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | if (error == 0) { | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
} | } | ||||
} | } | ||||
umtx_shm_unref_reg(reg, false); | umtx_shm_unref_reg(reg, false); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_shm(struct thread *td, struct _umtx_op_args *uap) | __umtx_op_shm(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops __unused) | |||||
{ | { | ||||
return (umtx_shm(td, uap->uaddr1, uap->val)); | return (umtx_shm(td, uap->uaddr1, uap->val)); | ||||
} | } | ||||
static int | static int | ||||
umtx_robust_lists(struct thread *td, struct umtx_robust_lists_params *rbp) | __umtx_op_robust_lists(struct thread *td, struct _umtx_op_args *uap, | ||||
const struct _umtx_copyops *ops) | |||||
{ | { | ||||
td->td_rb_list = rbp->robust_list_offset; | |||||
td->td_rbp_list = rbp->robust_priv_list_offset; | |||||
td->td_rb_inact = rbp->robust_inact_offset; | |||||
return (0); | |||||
} | |||||
static int | |||||
__umtx_op_robust_lists(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct umtx_robust_lists_params rb; | struct umtx_robust_lists_params rb; | ||||
int error; | int error; | ||||
if (uap->val > sizeof(rb)) | |||||
return (EINVAL); | |||||
bzero(&rb, sizeof(rb)); | bzero(&rb, sizeof(rb)); | ||||
error = copyin(uap->uaddr1, &rb, uap->val); | error = ops->copyin_robust_lists(uap->uaddr1, uap->val, &rb); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
return (umtx_robust_lists(td, &rb)); | |||||
} | |||||
typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap); | if (ops->compat32) | ||||
td->td_pflags2 |= TDP2_COMPAT32RB; | |||||
kibUnsubmitted Done Inline ActionsWhere is this flag cleared ? kib: Where is this flag cleared ? | |||||
static const _umtx_op_func op_table[] = { | else if ((td->td_pflags2 & TDP2_COMPAT32RB) != 0) | ||||
[UMTX_OP_RESERVED0] = __umtx_op_unimpl, | |||||
[UMTX_OP_RESERVED1] = __umtx_op_unimpl, | |||||
[UMTX_OP_WAIT] = __umtx_op_wait, | |||||
[UMTX_OP_WAKE] = __umtx_op_wake, | |||||
[UMTX_OP_MUTEX_TRYLOCK] = __umtx_op_trylock_umutex, | |||||
[UMTX_OP_MUTEX_LOCK] = __umtx_op_lock_umutex, | |||||
[UMTX_OP_MUTEX_UNLOCK] = __umtx_op_unlock_umutex, | |||||
[UMTX_OP_SET_CEILING] = __umtx_op_set_ceiling, | |||||
[UMTX_OP_CV_WAIT] = __umtx_op_cv_wait, | |||||
[UMTX_OP_CV_SIGNAL] = __umtx_op_cv_signal, | |||||
[UMTX_OP_CV_BROADCAST] = __umtx_op_cv_broadcast, | |||||
[UMTX_OP_WAIT_UINT] = __umtx_op_wait_uint, | |||||
[UMTX_OP_RW_RDLOCK] = __umtx_op_rw_rdlock, | |||||
[UMTX_OP_RW_WRLOCK] = __umtx_op_rw_wrlock, | |||||
[UMTX_OP_RW_UNLOCK] = __umtx_op_rw_unlock, | |||||
[UMTX_OP_WAIT_UINT_PRIVATE] = __umtx_op_wait_uint_private, | |||||
[UMTX_OP_WAKE_PRIVATE] = __umtx_op_wake_private, | |||||
[UMTX_OP_MUTEX_WAIT] = __umtx_op_wait_umutex, | |||||
[UMTX_OP_MUTEX_WAKE] = __umtx_op_wake_umutex, | |||||
#if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | |||||
[UMTX_OP_SEM_WAIT] = __umtx_op_sem_wait, | |||||
[UMTX_OP_SEM_WAKE] = __umtx_op_sem_wake, | |||||
#else | |||||
[UMTX_OP_SEM_WAIT] = __umtx_op_unimpl, | |||||
[UMTX_OP_SEM_WAKE] = __umtx_op_unimpl, | |||||
#endif | |||||
[UMTX_OP_NWAKE_PRIVATE] = __umtx_op_nwake_private, | |||||
[UMTX_OP_MUTEX_WAKE2] = __umtx_op_wake2_umutex, | |||||
[UMTX_OP_SEM2_WAIT] = __umtx_op_sem2_wait, | |||||
[UMTX_OP_SEM2_WAKE] = __umtx_op_sem2_wake, | |||||
[UMTX_OP_SHM] = __umtx_op_shm, | |||||
[UMTX_OP_ROBUST_LISTS] = __umtx_op_robust_lists, | |||||
}; | |||||
int | |||||
sys__umtx_op(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
if ((unsigned)uap->op < nitems(op_table)) | |||||
return (*op_table[uap->op])(td, uap); | |||||
return (EINVAL); | return (EINVAL); | ||||
td->td_rb_list = rb.robust_list_offset; | |||||
td->td_rbp_list = rb.robust_priv_list_offset; | |||||
td->td_rb_inact = rb.robust_inact_offset; | |||||
return (0); | |||||
} | } | ||||
Not Done Inline ActionsIsn't sz user-controlled ? Or I am missing something. kib: Isn't sz user-controlled ? Or I am missing something. | |||||
Done Inline ActionsI might remove this altogether or at least add a coment- the caller passes in uasize - ops->umtx_time_sz after checking that uasize >= ops->umtx_time_sz + ops->timespec_sz, so the result will always be greater than ops->timespec_sz -- the intention of this was to catch where ops->timespec_sz, which is filled out directly in the copyops and actually const now locally, was populated incorrectly. kevans: I might remove this altogether or at least add a coment- the caller passes in `uasize - ops… | |||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
struct umtx_time32 { | |||||
struct timespec32 timeout; | |||||
uint32_t flags; | |||||
uint32_t clockid; | |||||
}; | |||||
static inline int | static inline int | ||||
umtx_copyin_timeout32(void *addr, struct timespec *tsp) | umtx_copyin_timeout32(const void *uaddr, struct timespec *tsp) | ||||
{ | { | ||||
struct timespec32 ts32; | struct timespec32 ts32; | ||||
int error; | int error; | ||||
Done Inline ActionsMight be use the opportunity and move both umtx_time32 and umtx_robust*32 to compat/freebsd32/freebsd32.h ? kib: Might be use the opportunity and move both umtx_time32 and umtx_robust*32 to… | |||||
error = copyin(addr, &ts32, sizeof(struct timespec32)); | error = copyin(uaddr, &ts32, sizeof(ts32)); | ||||
if (error == 0) { | if (error == 0) { | ||||
if (ts32.tv_sec < 0 || | if (ts32.tv_sec < 0 || | ||||
ts32.tv_nsec >= 1000000000 || | ts32.tv_nsec >= 1000000000 || | ||||
ts32.tv_nsec < 0) | ts32.tv_nsec < 0) | ||||
error = EINVAL; | error = EINVAL; | ||||
else { | else { | ||||
tsp->tv_sec = ts32.tv_sec; | CP(ts32, *tsp, tv_sec); | ||||
tsp->tv_nsec = ts32.tv_nsec; | CP(ts32, *tsp, tv_nsec); | ||||
} | } | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static inline int | static inline int | ||||
umtx_copyin_umtx_time32(const void *addr, size_t size, struct _umtx_time *tp) | umtx_copyin_umtx_time32(const void *uaddr, size_t size, struct _umtx_time *tp) | ||||
{ | { | ||||
struct umtx_time32 t32; | struct umtx_time32 t32; | ||||
int error; | int error; | ||||
t32.clockid = CLOCK_REALTIME; | t32._clockid = CLOCK_REALTIME; | ||||
t32.flags = 0; | t32._flags = 0; | ||||
if (size <= sizeof(struct timespec32)) | if (size <= sizeof(t32._timeout)) | ||||
error = copyin(addr, &t32.timeout, sizeof(struct timespec32)); | error = copyin(uaddr, &t32._timeout, sizeof(t32._timeout)); | ||||
else | else | ||||
error = copyin(addr, &t32, sizeof(struct umtx_time32)); | error = copyin(uaddr, &t32, sizeof(t32)); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (t32.timeout.tv_sec < 0 || | if (t32._timeout.tv_sec < 0 || | ||||
t32.timeout.tv_nsec >= 1000000000 || t32.timeout.tv_nsec < 0) | t32._timeout.tv_nsec >= 1000000000 || t32._timeout.tv_nsec < 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
tp->_timeout.tv_sec = t32.timeout.tv_sec; | TS_CP(t32, *tp, _timeout); | ||||
tp->_timeout.tv_nsec = t32.timeout.tv_nsec; | CP(t32, *tp, _flags); | ||||
tp->_flags = t32.flags; | CP(t32, *tp, _clockid); | ||||
tp->_clockid = t32.clockid; | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
__umtx_op_wait_compat32(struct thread *td, struct _umtx_op_args *uap) | umtx_copyin_robust_lists32(const void *uaddr, size_t size, | ||||
struct umtx_robust_lists_params *rbp) | |||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | struct umtx_robust_lists_params_compat32 rb32; | ||||
int error; | int error; | ||||
if (uap->uaddr2 == NULL) | if (size > sizeof(rb32)) | ||||
tm_p = NULL; | return (EINVAL); | ||||
else { | bzero(&rb32, sizeof(rb32)); | ||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | error = copyin(uaddr, &rb32, size); | ||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
tm_p = &timeout; | CP(rb32, *rbp, robust_list_offset); | ||||
Done Inline Actionssys/abi_compat.h has a lot of macros to both make this more compact and obscure. kib: sys/abi_compat.h has a lot of macros to both make this more compact and obscure. | |||||
CP(rb32, *rbp, robust_priv_list_offset); | |||||
CP(rb32, *rbp, robust_inact_offset); | |||||
return (0); | |||||
} | } | ||||
return (do_wait(td, uap->obj, uap->val, tm_p, 1, 0)); | |||||
} | |||||
static int | static int | ||||
__umtx_op_lock_umutex_compat32(struct thread *td, struct _umtx_op_args *uap) | umtx_copyout_timeout32(void *uaddr, size_t sz, struct timespec *tsp) | ||||
{ | { | ||||
struct _umtx_time *tm_p, timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) | |||||
tm_p = NULL; | |||||
else { | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | |||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
tm_p = &timeout; | |||||
} | |||||
return (do_lock_umutex(td, uap->obj, tm_p, 0)); | |||||
} | |||||
static int | |||||
__umtx_op_wait_umutex_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time *tm_p, timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) | |||||
tm_p = NULL; | |||||
else { | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | |||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
tm_p = &timeout; | |||||
} | |||||
return (do_lock_umutex(td, uap->obj, tm_p, _UMUTEX_WAIT)); | |||||
} | |||||
static int | |||||
__umtx_op_cv_wait_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct timespec *ts, timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) | |||||
ts = NULL; | |||||
else { | |||||
error = umtx_copyin_timeout32(uap->uaddr2, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
ts = &timeout; | |||||
} | |||||
return (do_cv_wait(td, uap->obj, uap->uaddr1, ts, uap->val)); | |||||
} | |||||
static int | |||||
__umtx_op_rw_rdlock_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) { | |||||
error = do_rw_rdlock(td, uap->obj, uap->val, 0); | |||||
} else { | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | |||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
error = do_rw_rdlock(td, uap->obj, uap->val, &timeout); | |||||
} | |||||
return (error); | |||||
} | |||||
static int | |||||
__umtx_op_rw_wrlock_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) { | |||||
error = do_rw_wrlock(td, uap->obj, 0); | |||||
} else { | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | |||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
error = do_rw_wrlock(td, uap->obj, &timeout); | |||||
} | |||||
return (error); | |||||
} | |||||
static int | |||||
__umtx_op_wait_uint_private_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time *tm_p, timeout; | |||||
int error; | |||||
if (uap->uaddr2 == NULL) | |||||
tm_p = NULL; | |||||
else { | |||||
error = umtx_copyin_umtx_time32( | |||||
uap->uaddr2, (size_t)uap->uaddr1,&timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
tm_p = &timeout; | |||||
} | |||||
return (do_wait(td, uap->obj, uap->val, tm_p, 1, 1)); | |||||
} | |||||
#if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | |||||
static int | |||||
__umtx_op_sem_wait_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time *tm_p, timeout; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) | |||||
tm_p = NULL; | |||||
else { | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, | |||||
(size_t)uap->uaddr1, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
tm_p = &timeout; | |||||
} | |||||
return (do_sem_wait(td, uap->obj, tm_p)); | |||||
} | |||||
#endif | |||||
static int | |||||
__umtx_op_sem2_wait_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_time *tm_p, timeout; | |||||
size_t uasize; | |||||
int error; | |||||
/* Allow a null timespec (wait forever). */ | |||||
if (uap->uaddr2 == NULL) { | |||||
uasize = 0; | |||||
tm_p = NULL; | |||||
} else { | |||||
uasize = (size_t)uap->uaddr1; | |||||
error = umtx_copyin_umtx_time32(uap->uaddr2, uasize, &timeout); | |||||
if (error != 0) | |||||
return (error); | |||||
tm_p = &timeout; | |||||
} | |||||
error = do_sem2_wait(td, uap->obj, tm_p); | |||||
if (error == EINTR && uap->uaddr2 != NULL && | |||||
(timeout._flags & UMTX_ABSTIME) == 0 && | |||||
uasize >= sizeof(struct umtx_time32) + sizeof(struct timespec32)) { | |||||
struct timespec32 remain32 = { | struct timespec32 remain32 = { | ||||
.tv_sec = timeout._timeout.tv_sec, | .tv_sec = tsp->tv_sec, | ||||
.tv_nsec = timeout._timeout.tv_nsec | .tv_nsec = tsp->tv_nsec, | ||||
}; | }; | ||||
error = copyout(&remain32, | |||||
(struct umtx_time32 *)uap->uaddr2 + 1, | |||||
sizeof(struct timespec32)); | |||||
if (error == 0) { | |||||
error = EINTR; | |||||
} | |||||
} | |||||
return (error); | KASSERT(sz >= sizeof(remain32), | ||||
} | ("_umtx_copyops specifies incorrect sizes")); | ||||
static int | return (copyout(&remain32, uaddr, sizeof(remain32))); | ||||
__umtx_op_nwake_private32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
uint32_t uaddrs[BATCH_SIZE], **upp; | |||||
int count, error, i, pos, tocopy; | |||||
upp = (uint32_t **)uap->obj; | |||||
error = 0; | |||||
for (count = uap->val, pos = 0; count > 0; count -= tocopy, | |||||
pos += tocopy) { | |||||
tocopy = MIN(count, BATCH_SIZE); | |||||
error = copyin(upp + pos, uaddrs, tocopy * sizeof(uint32_t)); | |||||
if (error != 0) | |||||
break; | |||||
for (i = 0; i < tocopy; ++i) | |||||
kern_umtx_wake(td, (void *)(intptr_t)uaddrs[i], | |||||
INT_MAX, 1); | |||||
maybe_yield(); | |||||
} | } | ||||
return (error); | #endif /* COMPAT_FREEBSD32 */ | ||||
} | |||||
struct umtx_robust_lists_params_compat32 { | typedef int (*_umtx_op_func)(struct thread *td, struct _umtx_op_args *uap, | ||||
uint32_t robust_list_offset; | const struct _umtx_copyops *umtx_ops); | ||||
uint32_t robust_priv_list_offset; | |||||
uint32_t robust_inact_offset; | |||||
}; | |||||
static int | static const _umtx_op_func op_table[] = { | ||||
__umtx_op_robust_lists_compat32(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct umtx_robust_lists_params rb; | |||||
struct umtx_robust_lists_params_compat32 rb32; | |||||
int error; | |||||
if (uap->val > sizeof(rb32)) | |||||
return (EINVAL); | |||||
bzero(&rb, sizeof(rb)); | |||||
bzero(&rb32, sizeof(rb32)); | |||||
error = copyin(uap->uaddr1, &rb32, uap->val); | |||||
if (error != 0) | |||||
return (error); | |||||
rb.robust_list_offset = rb32.robust_list_offset; | |||||
rb.robust_priv_list_offset = rb32.robust_priv_list_offset; | |||||
rb.robust_inact_offset = rb32.robust_inact_offset; | |||||
return (umtx_robust_lists(td, &rb)); | |||||
} | |||||
static const _umtx_op_func op_table_compat32[] = { | |||||
[UMTX_OP_RESERVED0] = __umtx_op_unimpl, | [UMTX_OP_RESERVED0] = __umtx_op_unimpl, | ||||
[UMTX_OP_RESERVED1] = __umtx_op_unimpl, | [UMTX_OP_RESERVED1] = __umtx_op_unimpl, | ||||
[UMTX_OP_WAIT] = __umtx_op_wait_compat32, | [UMTX_OP_WAIT] = __umtx_op_wait, | ||||
[UMTX_OP_WAKE] = __umtx_op_wake, | [UMTX_OP_WAKE] = __umtx_op_wake, | ||||
[UMTX_OP_MUTEX_TRYLOCK] = __umtx_op_trylock_umutex, | [UMTX_OP_MUTEX_TRYLOCK] = __umtx_op_trylock_umutex, | ||||
[UMTX_OP_MUTEX_LOCK] = __umtx_op_lock_umutex_compat32, | [UMTX_OP_MUTEX_LOCK] = __umtx_op_lock_umutex, | ||||
[UMTX_OP_MUTEX_UNLOCK] = __umtx_op_unlock_umutex, | [UMTX_OP_MUTEX_UNLOCK] = __umtx_op_unlock_umutex, | ||||
[UMTX_OP_SET_CEILING] = __umtx_op_set_ceiling, | [UMTX_OP_SET_CEILING] = __umtx_op_set_ceiling, | ||||
[UMTX_OP_CV_WAIT] = __umtx_op_cv_wait_compat32, | [UMTX_OP_CV_WAIT] = __umtx_op_cv_wait, | ||||
[UMTX_OP_CV_SIGNAL] = __umtx_op_cv_signal, | [UMTX_OP_CV_SIGNAL] = __umtx_op_cv_signal, | ||||
[UMTX_OP_CV_BROADCAST] = __umtx_op_cv_broadcast, | [UMTX_OP_CV_BROADCAST] = __umtx_op_cv_broadcast, | ||||
[UMTX_OP_WAIT_UINT] = __umtx_op_wait_compat32, | [UMTX_OP_WAIT_UINT] = __umtx_op_wait_uint, | ||||
[UMTX_OP_RW_RDLOCK] = __umtx_op_rw_rdlock_compat32, | [UMTX_OP_RW_RDLOCK] = __umtx_op_rw_rdlock, | ||||
[UMTX_OP_RW_WRLOCK] = __umtx_op_rw_wrlock_compat32, | [UMTX_OP_RW_WRLOCK] = __umtx_op_rw_wrlock, | ||||
[UMTX_OP_RW_UNLOCK] = __umtx_op_rw_unlock, | [UMTX_OP_RW_UNLOCK] = __umtx_op_rw_unlock, | ||||
[UMTX_OP_WAIT_UINT_PRIVATE] = __umtx_op_wait_uint_private_compat32, | [UMTX_OP_WAIT_UINT_PRIVATE] = __umtx_op_wait_uint_private, | ||||
[UMTX_OP_WAKE_PRIVATE] = __umtx_op_wake_private, | [UMTX_OP_WAKE_PRIVATE] = __umtx_op_wake_private, | ||||
[UMTX_OP_MUTEX_WAIT] = __umtx_op_wait_umutex_compat32, | [UMTX_OP_MUTEX_WAIT] = __umtx_op_wait_umutex, | ||||
[UMTX_OP_MUTEX_WAKE] = __umtx_op_wake_umutex, | [UMTX_OP_MUTEX_WAKE] = __umtx_op_wake_umutex, | ||||
#if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | #if defined(COMPAT_FREEBSD9) || defined(COMPAT_FREEBSD10) | ||||
[UMTX_OP_SEM_WAIT] = __umtx_op_sem_wait_compat32, | [UMTX_OP_SEM_WAIT] = __umtx_op_sem_wait, | ||||
[UMTX_OP_SEM_WAKE] = __umtx_op_sem_wake, | [UMTX_OP_SEM_WAKE] = __umtx_op_sem_wake, | ||||
#else | #else | ||||
[UMTX_OP_SEM_WAIT] = __umtx_op_unimpl, | [UMTX_OP_SEM_WAIT] = __umtx_op_unimpl, | ||||
[UMTX_OP_SEM_WAKE] = __umtx_op_unimpl, | [UMTX_OP_SEM_WAKE] = __umtx_op_unimpl, | ||||
#endif | #endif | ||||
[UMTX_OP_NWAKE_PRIVATE] = __umtx_op_nwake_private32, | [UMTX_OP_NWAKE_PRIVATE] = __umtx_op_nwake_private, | ||||
[UMTX_OP_MUTEX_WAKE2] = __umtx_op_wake2_umutex, | [UMTX_OP_MUTEX_WAKE2] = __umtx_op_wake2_umutex, | ||||
[UMTX_OP_SEM2_WAIT] = __umtx_op_sem2_wait_compat32, | [UMTX_OP_SEM2_WAIT] = __umtx_op_sem2_wait, | ||||
[UMTX_OP_SEM2_WAKE] = __umtx_op_sem2_wake, | [UMTX_OP_SEM2_WAKE] = __umtx_op_sem2_wake, | ||||
[UMTX_OP_SHM] = __umtx_op_shm, | [UMTX_OP_SHM] = __umtx_op_shm, | ||||
[UMTX_OP_ROBUST_LISTS] = __umtx_op_robust_lists_compat32, | [UMTX_OP_ROBUST_LISTS] = __umtx_op_robust_lists, | ||||
}; | }; | ||||
static struct _umtx_copyops umtx_native_ops = { | |||||
kibUnsubmitted Done Inline ActionsMake this const ? kib: Make this const ? | |||||
.copyin_timeout = umtx_copyin_timeout, | |||||
.copyin_umtx_time = umtx_copyin_umtx_time, | |||||
.copyin_robust_lists = umtx_copyin_robust_lists, | |||||
.copyout_timeout = umtx_copyout_timeout, | |||||
.timespec_sz = sizeof(struct timespec), | |||||
.umtx_time_sz = sizeof(struct _umtx_time), | |||||
}; | |||||
#ifdef COMPAT_FREEBSD32 | |||||
struct _umtx_copyops umtx_native_ops32 = { | |||||
kibUnsubmitted Done Inline ActionsAnd this ? kib: And this ? | |||||
.copyin_timeout = umtx_copyin_timeout32, | |||||
.copyin_umtx_time = umtx_copyin_umtx_time32, | |||||
.copyin_robust_lists = umtx_copyin_robust_lists32, | |||||
.copyout_timeout = umtx_copyout_timeout32, | |||||
.timespec_sz = sizeof(struct timespec32), | |||||
.umtx_time_sz = sizeof(struct umtx_time32), | |||||
.compat32 = 1, | |||||
}; | |||||
#endif | |||||
int | int | ||||
freebsd32__umtx_op(struct thread *td, struct freebsd32__umtx_op_args *uap) | kern__umtx_op(struct thread *td, void *obj, int op, unsigned long val, | ||||
void *uaddr1, void *uaddr2, struct _umtx_copyops *ops) | |||||
kibUnsubmitted Done Inline Actionsconst for ops ? kib: const for ops ? | |||||
{ | { | ||||
struct _umtx_op_args uap = { | |||||
.obj = obj, | |||||
.op = op, | |||||
.val = val, | |||||
.uaddr1 = uaddr1, | |||||
.uaddr2 = uaddr2 | |||||
}; | |||||
if ((unsigned)uap->op < nitems(op_table_compat32)) { | if ((uap.op >= nitems(op_table))) | ||||
return (*op_table_compat32[uap->op])(td, | |||||
(struct _umtx_op_args *)uap); | |||||
} | |||||
return (EINVAL); | return (EINVAL); | ||||
return (*op_table[uap.op])(td, &uap, ops); | |||||
kibUnsubmitted Done Inline Actionsreturn ((*op_table[uap.op])(td, &uap, ops)); kib: `return ((*op_table[uap.op])(td, &uap, ops));` | |||||
} | } | ||||
#endif | |||||
int | |||||
sys__umtx_op(struct thread *td, struct _umtx_op_args *uap) | |||||
{ | |||||
struct _umtx_copyops *umtx_ops; | |||||
kibUnsubmitted Done Inline Actionsumtx_ops does not make much sense, why not pass &umtx_native_ops directly ? kib: umtx_ops does not make much sense, why not pass `&umtx_native_ops` directly ? | |||||
umtx_ops = &umtx_native_ops; | |||||
return (kern__umtx_op(td, uap->obj, uap->op, uap->val, uap->uaddr1, | |||||
uap->uaddr2, umtx_ops)); | |||||
} | |||||
void | void | ||||
umtx_thread_init(struct thread *td) | umtx_thread_init(struct thread *td) | ||||
{ | { | ||||
td->td_umtxq = umtxq_alloc(); | td->td_umtxq = umtxq_alloc(); | ||||
td->td_umtxq->uq_thread = td; | td->td_umtxq->uq_thread = td; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
umtx_read_rb_list(struct thread *td, struct umutex *m, uintptr_t *rb_list) | umtx_read_rb_list(struct thread *td, struct umutex *m, uintptr_t *rb_list) | ||||
{ | { | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
struct umutex32 m32; | struct umutex32 m32; | ||||
if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { | if ((td->td_pflags2 & TDP2_COMPAT32RB) != 0) { | ||||
memcpy(&m32, m, sizeof(m32)); | memcpy(&m32, m, sizeof(m32)); | ||||
*rb_list = m32.m_rb_lnk; | *rb_list = m32.m_rb_lnk; | ||||
} else | } else | ||||
#endif | #endif | ||||
*rb_list = m->m_rb_lnk; | *rb_list = m->m_rb_lnk; | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |
Why is NEED_UMTX32 needed ?
Can't you continue to use COMPAT_FREEBSD32 ? Or even drop this conditional at all.