MFC: Support for running 32-bit multithreaded binaries using libthr on

amd64 including:
- Add 32-bit wrappers for thr_new(), thr_suspend(), and the umtx system
  calls.
- Add support to amd64 for constructing thread upcalls for 32-bit
  processes.
- Leave %fs and %gs alone in the signal trampoline for 32-bit processes on
  amd64.
- Add 'casuword32()' to amd64 and ia64.

Tested by:	emaste
This commit is contained in:
jhb 2007-06-18 22:44:59 +00:00
parent 952376d89d
commit 9d52499b7d
11 changed files with 554 additions and 35 deletions

View File

@ -313,6 +313,34 @@ copyin_fault:
movq $EFAULT,%rax
ret
/*
* casuword32. Compare and set user integer. Returns -1 or the current value.
* dst = %rdi, old = %rsi, new = %rdx
*/
ENTRY(casuword32)
movq PCPU(CURPCB),%rcx
movq $fusufault,PCB_ONFAULT(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rdi /* verify address is valid */
ja fusufault
movl %esi,%eax /* old */
#ifdef SMP
lock
#endif
cmpxchgl %edx,(%rdi) /* new = %edx */
/*
* The old value is in %eax. If the store succeeded it will be the
* value we expected (old) from before the store, otherwise it will
* be the current value.
*/
movq PCPU(CURPCB),%rcx
movq $0,PCB_ONFAULT(%rcx)
ret
/*
* casuptr. Compare and set user pointer. Returns -1 or the current value.
* dst = %rdi, old = %rsi, new = %rdx

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include "opt_isa.h"
#include "opt_cpu.h"
#include "opt_compat.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -69,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/specialreg.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@ -79,6 +81,12 @@ __FBSDID("$FreeBSD$");
#include <amd64/isa/isa.h>
#ifdef COMPAT_IA32
extern struct sysentvec ia32_freebsd_sysvec;
#endif
static void cpu_reset_real(void);
#ifdef SMP
static void cpu_reset_proxy(void);
@ -320,6 +328,28 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
*/
cpu_thread_clean(td);
#ifdef COMPAT_IA32
if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
/*
* Set the trap frame to point at the beginning of the uts
* function.
*/
td->td_frame->tf_rbp = 0;
td->td_frame->tf_rsp =
(((uintptr_t)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4;
td->td_frame->tf_rip = (uintptr_t)entry;
/*
* Pass the address of the mailbox for this kse to the uts
* function as a parameter on the stack.
*/
suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)),
(uint32_t)(uintptr_t)arg);
return;
}
#endif
/*
* Set the trap frame to point at the beginning of the uts
* function.
@ -328,7 +358,6 @@ cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
td->td_frame->tf_rsp =
((register_t)stack->ss_sp + stack->ss_size) & ~0x0f;
td->td_frame->tf_rsp -= 8;
td->td_frame->tf_rbp = 0;
td->td_frame->tf_rip = (register_t)entry;
/*
@ -345,6 +374,19 @@ cpu_set_user_tls(struct thread *td, void *tls_base)
if ((u_int64_t)tls_base >= VM_MAXUSER_ADDRESS)
return (EINVAL);
#ifdef COMPAT_IA32
if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
if (td == curthread) {
critical_enter();
td->td_pcb->pcb_gsbase = (register_t)tls_base;
wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase);
critical_exit();
} else {
td->td_pcb->pcb_gsbase = (register_t)tls_base;
}
return (0);
}
#endif
if (td == curthread) {
critical_enter();
td->td_pcb->pcb_fsbase = (register_t)tls_base;

View File

@ -45,8 +45,6 @@ ia32_sigcode:
calll *IA32_SIGF_HANDLER(%esp)
leal IA32_SIGF_UC(%esp),%eax /* get ucontext */
pushl %eax
movl IA32_UC_GS(%eax),%gs /* restore %gs */
movl IA32_UC_FS(%eax),%fs /* restore %fs */
movl IA32_UC_ES(%eax),%es /* restore %es */
movl IA32_UC_DS(%eax),%ds /* restore %ds */
movl $SYS_sigreturn,%eax
@ -62,8 +60,6 @@ freebsd4_ia32_sigcode:
calll *IA32_SIGF_HANDLER(%esp)
leal IA32_SIGF_UC4(%esp),%eax/* get ucontext */
pushl %eax
movl IA32_UC4_GS(%eax),%gs /* restore %gs */
movl IA32_UC4_FS(%eax),%fs /* restore %fs */
movl IA32_UC4_ES(%eax),%es /* restore %es */
movl IA32_UC4_DS(%eax),%ds /* restore %ds */
movl $344,%eax /* 4.x SYS_sigreturn */

View File

@ -103,4 +103,17 @@ struct statfs32 {
int32_t f_spare[2];
};
struct thr_param32 {
uint32_t start_func;
uint32_t arg;
uint32_t stack_base;
uint32_t stack_size;
uint32_t tls_base;
uint32_t tls_size;
uint32_t child_tid;
uint32_t parent_tid;
int32_t flags;
uint32_t spare[4];
};
#endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */

View File

@ -2115,6 +2115,60 @@ freebsd32_clock_getres(struct thread *td,
return (error);
}
int
freebsd32_thr_new(struct thread *td,
struct freebsd32_thr_new_args *uap)
{
struct thr_param32 param32;
struct thr_param param;
int error;
if (uap->param_size < 0 ||
uap->param_size > sizeof(struct thr_param32))
return (EINVAL);
bzero(&param, sizeof(struct thr_param));
bzero(&param32, sizeof(struct thr_param32));
error = copyin(uap->param, &param32, uap->param_size);
if (error != 0)
return (error);
param.start_func = PTRIN(param32.start_func);
param.arg = PTRIN(param32.arg);
param.stack_base = PTRIN(param32.stack_base);
param.stack_size = param32.stack_size;
param.tls_base = PTRIN(param32.tls_base);
param.tls_size = param32.tls_size;
param.child_tid = PTRIN(param32.child_tid);
param.parent_tid = PTRIN(param32.parent_tid);
param.flags = param32.flags;
param.spare[0] = PTRIN(param32.spare[0]);
param.spare[1] = PTRIN(param32.spare[1]);
param.spare[2] = PTRIN(param32.spare[2]);
param.spare[3] = PTRIN(param32.spare[3]);
return (kern_thr_new(td, &param));
}
int
freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap)
{
struct timespec32 ts32;
struct timespec ts, *tsp;
int error;
error = 0;
tsp = NULL;
if (uap->timeout != NULL) {
error = copyin((const void *)uap->timeout, (void *)&ts32,
sizeof(struct timespec32));
if (error != 0)
return (error);
ts.tv_sec = ts32.tv_sec;
ts.tv_nsec = ts32.tv_nsec;
tsp = &ts;
}
return (kern_thr_suspend(td, tsp));
}
#if 0
int

View File

@ -718,21 +718,20 @@
428 AUE_NULL UNIMPL __acl_aclcheck_link
; XXX implement
429 AUE_SIGWAIT UNIMPL sigwait
430 AUE_NULL MNOPROTO { int thr_create(ucontext_t *ctx, long *id, \
int flag s); }
430 AUE_NULL UNIMPL thr_create
431 AUE_NULL MNOPROTO { void thr_exit(long *state); }
432 AUE_NULL MNOPROTO { int thr_self(long *id); }
433 AUE_NULL MNOPROTO { int thr_kill(long id, int sig); }
434 AUE_NULL MNOPROTO { int _umtx_lock(struct umtx *umtx); }
435 AUE_NULL MNOPROTO { int _umtx_unlock(struct umtx *umtx); }
434 AUE_NULL MSTD { int freebsd32_umtx_lock(struct umtx *umtx); }
435 AUE_NULL MSTD { int freebsd32_umtx_unlock(struct umtx *umtx); }
436 AUE_NULL MNOPROTO { int jail_attach(int jid); }
437 AUE_EXTATTR_LIST_FD UNIMPL extattr_list_fd
438 AUE_EXTATTR_LIST_FILE UNIMPL extattr_list_file
439 AUE_EXTATTR_LIST_LINK UNIMPL extattr_list_link
440 AUE_NULL UNIMPL kse_switchin
441 AUE_NULL UNIMPL ksem_timedwait
442 AUE_NULL MNOPROTO { int thr_suspend( \
const struct timespec *timeout); }
442 AUE_NULL MSTD { int freebsd32_thr_suspend( \
const struct timespec32 *timeout); }
443 AUE_NULL MNOPROTO { int thr_wake(long id); }
444 AUE_MODUNLOAD MNOPROTO { int kldunloadf(int fileid, int flags); }
445 AUE_AUDIT MNOPROTO { int audit(const void *record, \
@ -750,4 +749,9 @@
struct auditinfo_addr *auditinfo_addr, \
u_int length); }
453 AUE_AUDITCTL MNOPROTO { int auditctl(char *path); }
454 AUE_NULL UNIMPL _umtx_op
454 AUE_NULL MSTD { int freebsd32_umtx_op(struct umtx *umtx, \
int op, long id, void *uaddr, \
void *uaddr2); }
455 AUE_NULL MSTD { int freebsd32_thr_new( \
struct thr_param32 *param, \
int param_size); }

View File

@ -241,6 +241,56 @@ ENTRY(casuptr, 3)
}
END(casuptr)
/*
* casuword32(int32_t *p, int32_t old, int32_t new)
* Perform a 32-bit compare-exchange in user space.
*/
ENTRY(casuword32, 3)
{ .mlx
add r15=PC_CURTHREAD,r13
movl r14=VM_MAX_ADDRESS
;;
}
{ .mib
ld8 r15=[r15] // r15 = curthread
cmp.geu p6,p0=in0,r14
(p6) br.dpnt.few 1f
;;
}
{ .mlx
add r15=TD_PCB,r15
movl r14=fusufault
;;
}
{ .mmi
ld8 r15=[r15] // r15 = PCB
;;
mov ar.ccv=in1
add r15=PCB_ONFAULT,r15
;;
}
{ .mmi
st8 [r15]=r14 // Set onfault
;;
cmpxchg4.rel ret0=[in0],in2,ar.ccv
nop 0
;;
}
{ .mfb
st8.rel [r15]=r0 // Clear onfault
nop 0
br.ret.sptk rp
;;
}
1:
{ .mfb
add ret0=-1,r0
nop 0
br.ret.sptk rp
;;
}
END(casuword32)
/*
* subyte(void *addr, int byte)
* suword16(void *addr, int word)

View File

@ -27,6 +27,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@ -36,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/sysctl.h>
#include <sys/smp.h>
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
@ -46,6 +48,26 @@ __FBSDID("$FreeBSD$");
#include <machine/frame.h>
#ifdef COMPAT_IA32
extern struct sysentvec ia32_freebsd_sysvec;
static inline int
suword_lwpid(void *addr, lwpid_t lwpid)
{
int error;
if (curproc->p_sysent != &ia32_freebsd_sysvec)
error = suword(addr, lwpid);
else
error = suword32(addr, lwpid);
return (error);
}
#else
#define suword_lwpid suword
#endif
extern int max_threads_per_proc;
extern int max_groups_per_proc;
@ -94,9 +116,17 @@ thr_new(struct thread *td, struct thr_new_args *uap)
return (EINVAL);
if ((error = copyin(uap->param, &param, sizeof(param))))
return (error);
error = create_thread(td, NULL, param.start_func, param.arg,
param.stack_base, param.stack_size, param.tls_base,
param.child_tid, param.parent_tid, param.flags);
return (kern_thr_new(td, &param));
}
int
kern_thr_new(struct thread *td, struct thr_param *param)
{
int error;
error = create_thread(td, NULL, param->start_func, param->arg,
param->stack_base, param->stack_size, param->tls_base,
param->child_tid, param->parent_tid, param->flags);
return (error);
}
@ -112,7 +142,6 @@ create_thread(struct thread *td, mcontext_t *ctx,
struct thread *newtd;
struct ksegrp *kg, *newkg;
struct proc *p;
long id;
int error, scope_sys, linkkg;
error = 0;
@ -146,11 +175,10 @@ create_thread(struct thread *td, mcontext_t *ctx,
* its storage, because child thread may exit quickly and
* memory is freed before parent thread can access it.
*/
id = newtd->td_tid;
if ((child_tid != NULL &&
(error = copyout(&id, child_tid, sizeof(long)))) ||
suword_lwpid(child_tid, newtd->td_tid)) ||
(parent_tid != NULL &&
(error = copyout(&id, parent_tid, sizeof(long))))) {
suword_lwpid(parent_tid, newtd->td_tid))) {
thread_free(newtd);
return (error);
}
@ -257,13 +285,11 @@ int
thr_self(struct thread *td, struct thr_self_args *uap)
/* long *id */
{
long id;
int error;
id = td->td_tid;
if ((error = copyout(&id, uap->id, sizeof(long))))
return (error);
error = suword_lwpid(uap->id, (unsigned)td->td_tid);
if (error == -1)
return (EFAULT);
return (0);
}
@ -277,7 +303,7 @@ thr_exit(struct thread *td, struct thr_exit_args *uap)
/* Signal userland that it can free the stack. */
if ((void *)uap->state != NULL) {
suword((void *)uap->state, 1);
suword_lwpid(uap->state, 1);
kern_umtx_wake(td, uap->state, INT_MAX);
}
@ -348,23 +374,34 @@ int
thr_suspend(struct thread *td, struct thr_suspend_args *uap)
/* const struct timespec *timeout */
{
struct timespec ts;
struct timeval tv;
struct timespec ts, *tsp;
int error;
int hz;
hz = 0;
error = 0;
tsp = NULL;
if (uap->timeout != NULL) {
error = copyin((const void *)uap->timeout, (void *)&ts,
sizeof(struct timespec));
if (error != 0)
return (error);
if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000)
tsp = &ts;
}
return (kern_thr_suspend(td, tsp));
}
int
kern_thr_suspend(struct thread *td, struct timespec *tsp)
{
struct timeval tv;
int error = 0, hz = 0;
if (tsp != NULL) {
if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000)
return (EINVAL);
if (ts.tv_sec == 0 && ts.tv_nsec == 0)
if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
return (ETIMEDOUT);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
TIMESPEC_TO_TIMEVAL(&tv, tsp);
hz = tvtohz(&tv);
}
PROC_LOCK(td->td_proc);

View File

@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/limits.h>
@ -48,6 +49,12 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#ifdef COMPAT_IA32
#include <compat/freebsd32/freebsd32_proto.h>
#define UMTX_CONTESTED32 (-0x7fffffff - 1)
#endif
#define UMTX_PRIVATE 0
#define UMTX_SHARED 1
@ -113,7 +120,7 @@ static void fork_handler(void *arg, struct proc *p1, struct proc *p2,
int flags);
#endif
static int umtx_key_match(const struct umtx_key *k1, const struct umtx_key *k2);
static int umtx_key_get(struct thread *td, struct umtx *umtx,
static int umtx_key_get(struct thread *td, void *umtx,
struct umtx_key *key);
static void umtx_key_release(struct umtx_key *key);
@ -299,7 +306,7 @@ umtxq_sleep(struct thread *td, struct umtx_key *key, int priority,
}
static int
umtx_key_get(struct thread *td, struct umtx *umtx, struct umtx_key *key)
umtx_key_get(struct thread *td, void *umtx, struct umtx_key *key)
{
#if defined(UMTX_DYNAMIC_SHARED) || defined(UMTX_STATIC_SHARED)
vm_map_t map;
@ -355,7 +362,7 @@ umtx_key_release(struct umtx_key *key)
}
static inline int
umtxq_queue_me(struct thread *td, struct umtx *umtx, struct umtx_q *uq)
umtxq_queue_me(struct thread *td, void *umtx, struct umtx_q *uq)
{
int error;
@ -621,6 +628,186 @@ do_unlock(struct thread *td, struct umtx *umtx, long id)
return (0);
}
#ifdef COMPAT_IA32
static int
_do_lock32(struct thread *td, uint32_t *m, uint32_t id, int timo)
{
struct umtx_q *uq;
int32_t owner;
int32_t old;
int error = 0;
uq = td->td_umtxq;
/*
* Care must be exercised when dealing with umtx structure. It
* can fault on any access.
*/
for (;;) {
/*
* Try the uncontested case. This should be done in userland.
*/
owner = casuword32(m, UMTX_UNOWNED, id);
/* The acquire succeeded. */
if (owner == UMTX_UNOWNED)
return (0);
/* The address was invalid. */
if (owner == -1)
return (EFAULT);
/* If no one owns it but it is contested try to acquire it. */
if (owner == UMTX_CONTESTED32) {
owner = casuword32(m,
UMTX_CONTESTED32, id | UMTX_CONTESTED32);
if (owner == UMTX_CONTESTED32)
return (0);
/* The address was invalid. */
if (owner == -1)
return (EFAULT);
/* If this failed the lock has changed, restart. */
continue;
}
/*
* If we caught a signal, we have retried and now
* exit immediately.
*/
if (error || (error = umtxq_queue_me(td, m, uq)) != 0)
return (error);
/*
* Set the contested bit so that a release in user space
* knows to use the system call for unlock. If this fails
* either some one else has acquired the lock or it has been
* released.
*/
old = casuword32(m, owner, owner | UMTX_CONTESTED32);
/* The address was invalid. */
if (old == -1) {
umtxq_lock(&uq->uq_key);
umtxq_busy(&uq->uq_key);
umtxq_remove(uq);
umtxq_unbusy(&uq->uq_key);
umtxq_unlock(&uq->uq_key);
umtx_key_release(&uq->uq_key);
return (EFAULT);
}
/*
* We set the contested bit, sleep. Otherwise the lock changed
* and we need to retry or we lost a race to the thread
* unlocking the umtx.
*/
umtxq_lock(&uq->uq_key);
if (old == owner && (td->td_flags & TDF_UMTXQ)) {
error = umtxq_sleep(td, &uq->uq_key, PCATCH,
"umtx", timo);
}
umtxq_busy(&uq->uq_key);
umtxq_remove(uq);
umtxq_unbusy(&uq->uq_key);
umtxq_unlock(&uq->uq_key);
umtx_key_release(&uq->uq_key);
}
return (0);
}
static int
do_lock32(struct thread *td, void *m, uint32_t id,
struct timespec *timeout)
{
struct timespec ts, ts2, ts3;
struct timeval tv;
int error;
if (timeout == NULL) {
error = _do_lock32(td, m, id, 0);
} else {
getnanouptime(&ts);
timespecadd(&ts, timeout);
TIMESPEC_TO_TIMEVAL(&tv, timeout);
for (;;) {
error = _do_lock32(td, m, id, tvtohz(&tv));
if (error != ETIMEDOUT)
break;
getnanouptime(&ts2);
if (timespeccmp(&ts2, &ts, >=)) {
error = ETIMEDOUT;
break;
}
ts3 = ts;
timespecsub(&ts3, &ts2);
TIMESPEC_TO_TIMEVAL(&tv, &ts3);
}
}
/*
* This lets userland back off critical region if needed.
*/
if (error == ERESTART)
error = EINTR;
return (error);
}
static int
do_unlock32(struct thread *td, uint32_t *m, uint32_t id)
{
struct umtx_key key;
int32_t owner;
int32_t old;
int error;
int count;
/*
* Make sure we own this mtx.
*
* XXX Need a {fu,su}ptr this is not correct on arch where
* sizeof(intptr_t) != sizeof(long).
*/
if ((owner = fuword32(m)) == -1)
return (EFAULT);
if ((owner & ~UMTX_CONTESTED32) != id)
return (EPERM);
/* We should only ever be in here for contested locks */
if ((owner & UMTX_CONTESTED32) == 0)
return (EINVAL);
if ((error = umtx_key_get(td, m, &key)) != 0)
return (error);
umtxq_lock(&key);
umtxq_busy(&key);
count = umtxq_count(&key);
umtxq_unlock(&key);
/*
* When unlocking the umtx, it must be marked as unowned if
* there is zero or one thread only waiting for it.
* Otherwise, it must be marked as contested.
*/
old = casuword32(m, owner,
count <= 1 ? UMTX_UNOWNED : UMTX_CONTESTED32);
umtxq_lock(&key);
umtxq_signal(&key, 0);
umtxq_unbusy(&key);
umtxq_unlock(&key);
umtx_key_release(&key);
if (old == -1)
return (EFAULT);
if (old != owner)
return (EINVAL);
return (0);
}
#endif
static int
do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *timeout)
{
@ -768,3 +955,107 @@ _umtx_op(struct thread *td, struct _umtx_op_args *uap)
}
return (error);
}
#ifdef COMPAT_IA32
int
freebsd32_umtx_lock(struct thread *td, struct freebsd32_umtx_lock_args *uap)
/* struct umtx *umtx */
{
return (do_lock32(td, (uint32_t *)uap->umtx, td->td_tid, NULL));
}
int
freebsd32_umtx_unlock(struct thread *td, struct freebsd32_umtx_unlock_args *uap)
/* struct umtx *umtx */
{
return (do_unlock32(td, (uint32_t *)uap->umtx, td->td_tid));
}
struct timespec32 {
u_int32_t tv_sec;
u_int32_t tv_nsec;
};
static inline int
copyin_timeout32(void *addr, struct timespec *tsp)
{
struct timespec32 ts32;
int error;
error = copyin(addr, &ts32, sizeof(struct timespec32));
if (error == 0) {
tsp->tv_sec = ts32.tv_sec;
tsp->tv_nsec = ts32.tv_nsec;
}
return (error);
}
static int
__umtx_op_lock_umtx_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 = copyin_timeout32(uap->uaddr2, &timeout);
if (error != 0)
return (error);
if (timeout.tv_nsec >= 1000000000 ||
timeout.tv_nsec < 0) {
return (EINVAL);
}
ts = &timeout;
}
return (do_lock32(td, uap->umtx, uap->id, ts));
}
static int
__umtx_op_unlock_umtx_compat32(struct thread *td, struct _umtx_op_args *uap)
{
return (do_unlock32(td, (uint32_t *)uap->umtx, (uint32_t)uap->id));
}
static int
__umtx_op_wait_compat32(struct thread *td, struct _umtx_op_args *uap)
{
struct timespec *ts, timeout;
int error;
if (uap->uaddr2 == NULL)
ts = NULL;
else {
error = copyin_timeout32(uap->uaddr2, &timeout);
if (error != 0)
return (error);
if (timeout.tv_nsec >= 1000000000 ||
timeout.tv_nsec < 0)
return (EINVAL);
ts = &timeout;
}
return do_wait(td, uap->umtx, uap->id, ts);
}
int
freebsd32_umtx_op(struct thread *td, struct freebsd32_umtx_op_args *uap)
{
switch ((unsigned)uap->op) {
case UMTX_OP_LOCK:
return __umtx_op_lock_umtx_compat32(td,
(struct _umtx_op_args *)uap);
case UMTX_OP_UNLOCK:
return __umtx_op_unlock_umtx_compat32(td,
(struct _umtx_op_args *)uap);
case UMTX_OP_WAIT:
return __umtx_op_wait_compat32(td,
(struct _umtx_op_args *)uap);
case UMTX_OP_WAKE:
return kern_umtx_wake(td, (uint32_t *)uap->umtx, uap->id);
default:
return (EINVAL);
}
}
#endif

View File

@ -46,6 +46,7 @@ struct stat;
struct kevent;
struct kevent_copyops;
struct sendfile_args;
struct thr_param;
int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg,
u_int buflen);
@ -148,6 +149,8 @@ int kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
struct statfs *buf);
int kern_symlink(struct thread *td, char *path, char *link,
enum uio_seg segflg);
int kern_thr_new(struct thread *td, struct thr_param *param);
int kern_thr_suspend(struct thread *td, struct timespec *tsp);
int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,
off_t length);
int kern_unlink(struct thread *td, char *path, enum uio_seg pathseg);

View File

@ -204,6 +204,7 @@ int suword(void *base, long word);
int suword16(void *base, int word);
int suword32(void *base, int32_t word);
int suword64(void *base, int64_t word);
int32_t casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval);
intptr_t casuptr(intptr_t *p, intptr_t old, intptr_t new);
void realitexpire(void *);