Add some new files needed for linux 2.6.x compatibility.
Please don't style(9) the NetBSD code, we want to stay in sync. Not imported on a vendor branch since we need local changes. Sponsored by: Google SoC 2006 Submitted by: rdivacky With help from: manu@NetBSD.org Obtained from: NetBSD (linux_{futex,time}.*)
This commit is contained in:
parent
fb5592c084
commit
ad2056f2c4
297
sys/compat/linux/linux_emul.c
Normal file
297
sys/compat/linux/linux_emul.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Roman Divacky
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_compat.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <compat/linux/linux_emul.h>
|
||||
#include <compat/linux/linux_futex.h>
|
||||
|
||||
#ifdef COMPAT_LINUX32
|
||||
#include <machine/../linux32/linux.h>
|
||||
#include <machine/../linux32/linux32_proto.h>
|
||||
#else
|
||||
#include <machine/../linux/linux.h>
|
||||
#include <machine/../linux/linux_proto.h>
|
||||
#endif
|
||||
|
||||
struct sx emul_shared_lock;
|
||||
struct sx emul_lock;
|
||||
|
||||
/* this returns locked reference to the emuldata entry (if found) */
|
||||
struct linux_emuldata *
|
||||
em_find(struct proc *p, int locked)
|
||||
{
|
||||
struct linux_emuldata *em;
|
||||
|
||||
if (locked == EMUL_UNLOCKED)
|
||||
EMUL_LOCK(&emul_lock);
|
||||
|
||||
em = p->p_emuldata;
|
||||
|
||||
if (em == NULL && locked == EMUL_UNLOCKED)
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
|
||||
return (em);
|
||||
}
|
||||
|
||||
int
|
||||
linux_proc_init(struct thread *td, pid_t child, int flags)
|
||||
{
|
||||
struct linux_emuldata *em, *p_em;
|
||||
struct proc *p;
|
||||
|
||||
if (child != 0) {
|
||||
/* non-exec call */
|
||||
MALLOC(em, struct linux_emuldata *, sizeof *em, M_LINUX, M_WAITOK | M_ZERO);
|
||||
em->pid = child;
|
||||
if (flags & CLONE_VM) {
|
||||
/* handled later in the code */
|
||||
} else {
|
||||
struct linux_emuldata_shared *s;
|
||||
|
||||
MALLOC(s, struct linux_emuldata_shared *, sizeof *s, M_LINUX, M_WAITOK | M_ZERO);
|
||||
em->shared = s;
|
||||
s->refs = 1;
|
||||
s->group_pid = child;
|
||||
|
||||
LIST_INIT(&s->threads);
|
||||
}
|
||||
p = pfind(child);
|
||||
if (p == NULL)
|
||||
panic("process not found in proc_init\n");
|
||||
p->p_emuldata = em;
|
||||
PROC_UNLOCK(p);
|
||||
} else {
|
||||
/* lookup the old one */
|
||||
em = em_find(td->td_proc, EMUL_UNLOCKED);
|
||||
KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
|
||||
}
|
||||
|
||||
em->child_clear_tid = NULL;
|
||||
em->child_set_tid = NULL;
|
||||
|
||||
/* allocate the shared struct only in clone()/fork cases
|
||||
* in the case of clone() td = calling proc and child = pid of
|
||||
* the newly created proc
|
||||
*/
|
||||
if (child != 0) {
|
||||
if (flags & CLONE_VM) {
|
||||
/* lookup the parent */
|
||||
p_em = em_find(td->td_proc, EMUL_LOCKED);
|
||||
KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_VM\n"));
|
||||
em->shared = p_em->shared;
|
||||
em->shared->refs++;
|
||||
} else {
|
||||
/* handled earlier to avoid malloc(M_WAITOK) with rwlock held */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (child != 0) {
|
||||
EMUL_SHARED_WLOCK(&emul_shared_lock);
|
||||
LIST_INSERT_HEAD(&em->shared->threads, em, threads);
|
||||
EMUL_SHARED_WUNLOCK(&emul_shared_lock);
|
||||
|
||||
p = pfind(child);
|
||||
PROC_UNLOCK(p);
|
||||
/* we might have a sleeping linux_schedtail */
|
||||
wakeup(&p->p_emuldata);
|
||||
} else
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
linux_proc_exit(void *arg __unused, struct proc *p)
|
||||
{
|
||||
struct linux_emuldata *em;
|
||||
int error;
|
||||
struct thread *td = FIRST_THREAD_IN_PROC(p);
|
||||
int *child_clear_tid;
|
||||
|
||||
if (__predict_true(p->p_sysent != &elf_linux_sysvec))
|
||||
return;
|
||||
|
||||
/* find the emuldata */
|
||||
em = em_find(p, EMUL_UNLOCKED);
|
||||
|
||||
KASSERT(em != NULL, ("proc_exit: emuldata not found.\n"));
|
||||
|
||||
child_clear_tid = em->child_clear_tid;
|
||||
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
|
||||
EMUL_SHARED_WLOCK(&emul_shared_lock);
|
||||
LIST_REMOVE(em, threads);
|
||||
|
||||
PROC_LOCK(p);
|
||||
p->p_emuldata = NULL;
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
em->shared->refs--;
|
||||
if (em->shared->refs == 0)
|
||||
FREE(em->shared, M_LINUX);
|
||||
EMUL_SHARED_WUNLOCK(&emul_shared_lock);
|
||||
|
||||
if (child_clear_tid != NULL) {
|
||||
struct linux_sys_futex_args cup;
|
||||
int null = 0;
|
||||
|
||||
error = copyout(&null, child_clear_tid, sizeof(null));
|
||||
if (error)
|
||||
return;
|
||||
|
||||
/* futexes stuff */
|
||||
cup.uaddr = child_clear_tid;
|
||||
cup.op = LINUX_FUTEX_WAKE;
|
||||
cup.val = 0x7fffffff; /* Awake everyone */
|
||||
cup.timeout = NULL;
|
||||
cup.uaddr2 = NULL;
|
||||
cup.val3 = 0;
|
||||
error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup);
|
||||
/* this cannot happen at the moment and if this happens
|
||||
* it probably mean there is a userspace bug
|
||||
*/
|
||||
if (error)
|
||||
printf(LMSG("futex stuff in proc_exit failed.\n"));
|
||||
}
|
||||
|
||||
/* clean the stuff up */
|
||||
FREE(em, M_LINUX);
|
||||
}
|
||||
|
||||
/* This is used in a case of transition from FreeBSD binary execing to linux binary
|
||||
* in this case we create linux emuldata proc entry with the pid of the currently running
|
||||
* process.
|
||||
*/
|
||||
void linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
|
||||
{
|
||||
if (__predict_false(imgp->sysent == &elf_linux_sysvec
|
||||
&& p->p_sysent != &elf_linux_sysvec))
|
||||
linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
|
||||
if (__predict_false(imgp->sysent != &elf_linux_sysvec
|
||||
&& p->p_sysent == &elf_linux_sysvec)) {
|
||||
struct linux_emuldata *em;
|
||||
|
||||
em = em_find(p, EMUL_UNLOCKED);
|
||||
|
||||
KASSERT(em != NULL, ("proc_exec: emuldata not found.\n"));
|
||||
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
|
||||
EMUL_SHARED_WLOCK(&emul_shared_lock);
|
||||
LIST_REMOVE(em, threads);
|
||||
|
||||
PROC_LOCK(p);
|
||||
p->p_emuldata = NULL;
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
em->shared->refs--;
|
||||
if (em->shared->refs == 0)
|
||||
FREE(em->shared, M_LINUX);
|
||||
EMUL_SHARED_WUNLOCK(&emul_shared_lock);
|
||||
|
||||
FREE(em, M_LINUX);
|
||||
}
|
||||
}
|
||||
|
||||
extern int hz; /* in subr_param.c */
|
||||
|
||||
void
|
||||
linux_schedtail(void *arg __unused, struct proc *p)
|
||||
{
|
||||
struct linux_emuldata *em;
|
||||
int error = 0;
|
||||
#ifdef DEBUG
|
||||
struct thread *td = FIRST_THREAD_IN_PROC(p);
|
||||
#endif
|
||||
int *child_set_tid;
|
||||
|
||||
if (p->p_sysent != &elf_linux_sysvec)
|
||||
return;
|
||||
|
||||
retry:
|
||||
/* find the emuldata */
|
||||
em = em_find(p, EMUL_UNLOCKED);
|
||||
|
||||
if (em == NULL) {
|
||||
/* We might have been called before proc_init for this process so
|
||||
* tsleep and be woken up by it. We use p->p_emuldata for this
|
||||
*/
|
||||
|
||||
error = tsleep(&p->p_emuldata, PLOCK, "linux_schedtail", hz);
|
||||
if (error == 0)
|
||||
goto retry;
|
||||
panic("no emuldata found for userreting process.\n");
|
||||
}
|
||||
child_set_tid = em->child_set_tid;
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
|
||||
if (child_set_tid != NULL)
|
||||
error = copyout(&p->p_pid, (int *) child_set_tid, sizeof(p->p_pid));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
|
||||
{
|
||||
struct linux_emuldata *em;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(set_tid_address))
|
||||
printf(ARGS(set_tid_address, "%p"), args->tidptr);
|
||||
#endif
|
||||
|
||||
/* find the emuldata */
|
||||
em = em_find(td->td_proc, EMUL_UNLOCKED);
|
||||
|
||||
KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
|
||||
|
||||
em->child_clear_tid = args->tidptr;
|
||||
td->td_retval[0] = td->td_proc->p_pid;
|
||||
|
||||
EMUL_UNLOCK(&emul_lock);
|
||||
return 0;
|
||||
}
|
74
sys/compat/linux/linux_emul.h
Normal file
74
sys/compat/linux/linux_emul.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Roman Divacky
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EMUL_H_
|
||||
#define _LINUX_EMUL_H_
|
||||
|
||||
struct linux_emuldata_shared {
|
||||
int refs;
|
||||
pid_t group_pid;
|
||||
|
||||
LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
|
||||
};
|
||||
|
||||
/* modeled after similar structure in NetBSD
|
||||
* this will be extended as we need more functionality
|
||||
*/
|
||||
struct linux_emuldata {
|
||||
pid_t pid;
|
||||
|
||||
int *child_set_tid; /* in clone(): Child's TID to set on clone */
|
||||
int *child_clear_tid; /* in clone(): Child's TID to clear on exit */
|
||||
|
||||
struct linux_emuldata_shared *shared;
|
||||
|
||||
LIST_ENTRY(linux_emuldata) threads; /* list of linux threads */
|
||||
};
|
||||
|
||||
struct linux_emuldata *em_find(struct proc *, int locked);
|
||||
|
||||
#define EMUL_LOCK(l) sx_xlock(l)
|
||||
#define EMUL_UNLOCK(l) sx_xunlock(l)
|
||||
|
||||
#define EMUL_SHARED_RLOCK(l) sx_slock(l)
|
||||
#define EMUL_SHARED_RUNLOCK(l) sx_sunlock(l)
|
||||
#define EMUL_SHARED_WLOCK(l) sx_xlock(l)
|
||||
#define EMUL_SHARED_WUNLOCK(l) sx_xunlock(l)
|
||||
|
||||
/* for em_find use */
|
||||
#define EMUL_LOCKED 1
|
||||
#define EMUL_UNLOCKED 0
|
||||
|
||||
int linux_proc_init(struct thread *, pid_t, int);
|
||||
void linux_proc_exit(void *, struct proc *);
|
||||
void linux_schedtail(void *, struct proc *);
|
||||
void linux_proc_exec(void *, struct proc *, struct image_params *);
|
||||
|
||||
#endif /* !_LINUX_EMUL_H_ */
|
500
sys/compat/linux/linux_futex.c
Normal file
500
sys/compat/linux/linux_futex.c
Normal file
@ -0,0 +1,500 @@
|
||||
/* $NetBSD: linux_futex.c,v 1.5 2005/11/23 16:14:57 manu Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Emmanuel Dreyfus
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
#if 0
|
||||
__KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.5 2005/11/23 16:14:57 manu Exp $");
|
||||
#endif
|
||||
|
||||
#include "opt_compat.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#ifdef COMPAT_LINUX32
|
||||
#include <machine/../linux32/linux.h>
|
||||
#include <machine/../linux32/linux32_proto.h>
|
||||
#else
|
||||
#include <machine/../linux/linux.h>
|
||||
#include <machine/../linux/linux_proto.h>
|
||||
#endif
|
||||
#include <compat/linux/linux_futex.h>
|
||||
|
||||
struct futex;
|
||||
|
||||
struct waiting_proc {
|
||||
struct thread *wp_t;
|
||||
struct futex *wp_new_futex;
|
||||
TAILQ_ENTRY(waiting_proc) wp_list;
|
||||
};
|
||||
struct futex {
|
||||
void *f_uaddr;
|
||||
int f_refcount;
|
||||
LIST_ENTRY(futex) f_list;
|
||||
TAILQ_HEAD(lf_waiting_proc, waiting_proc) f_waiting_proc;
|
||||
};
|
||||
|
||||
LIST_HEAD(futex_list, futex) futex_list;
|
||||
struct mtx futex_mtx; /* this protects the LIST of futexes */
|
||||
|
||||
#define FUTEX_LOCK mtx_lock(&futex_mtx)
|
||||
#define FUTEX_UNLOCK mtx_unlock(&futex_mtx)
|
||||
|
||||
#define FUTEX_LOCKED 1
|
||||
#define FUTEX_UNLOCKED 0
|
||||
|
||||
#define FUTEX_SYSTEM_LOCK mtx_lock(&Giant)
|
||||
#define FUTEX_SYSTEM_UNLOCK mtx_unlock(&Giant)
|
||||
|
||||
static struct futex *futex_get(void *, int);
|
||||
static void futex_put(struct futex *);
|
||||
static int futex_sleep(struct futex *, struct thread *, unsigned long);
|
||||
static int futex_wake(struct futex *, int, struct futex *);
|
||||
#ifdef __i386__
|
||||
static int futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr);
|
||||
#endif
|
||||
|
||||
/* support.s */
|
||||
int futex_xchgl(int oparg, caddr_t uaddr, int *oldval);
|
||||
int futex_addl(int oparg, caddr_t uaddr, int *oldval);
|
||||
int futex_orl(int oparg, caddr_t uaddr, int *oldval);
|
||||
int futex_andnl(int oparg, caddr_t uaddr, int *oldval);
|
||||
int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
|
||||
|
||||
int
|
||||
linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
struct l_timespec timeout = { 0, 0 };
|
||||
int error = 0;
|
||||
struct futex *f;
|
||||
struct futex *newf;
|
||||
int timeout_hz;
|
||||
struct timeval tv = {0, 0};
|
||||
#ifdef __i386__
|
||||
struct futex *f2;
|
||||
int op_ret;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf(ARGS(futex,"%p, %i, %i"), args->uaddr, args->op, args->val);
|
||||
#endif
|
||||
|
||||
switch (args->op) {
|
||||
case LINUX_FUTEX_WAIT:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
if ((error = copyin(args->uaddr,
|
||||
&val, sizeof(val))) != 0) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (val != args->val) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return EWOULDBLOCK;
|
||||
}
|
||||
|
||||
if (args->timeout != NULL) {
|
||||
if ((error = copyin(args->timeout,
|
||||
&timeout, sizeof(timeout))) != 0) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAIT %d: val = %d, uaddr = %p, "
|
||||
"*uaddr = %d, timeout = %d.%09ld\n",
|
||||
td->td_proc->p_pid, args->val,
|
||||
args->uaddr, val, timeout.tv_sec, timeout.tv_nsec);
|
||||
#endif
|
||||
tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000;
|
||||
timeout_hz = tvtohz(&tv);
|
||||
|
||||
if (timeout.tv_sec == 0 && timeout.tv_nsec == 0)
|
||||
timeout_hz = 0;
|
||||
/*
|
||||
* If the user process requests a non null timeout,
|
||||
* make sure we do not turn it into an infinite
|
||||
* timeout because timeout_hz gets null.
|
||||
*
|
||||
* We use a minimal timeout of 1/hz. Maybe it would
|
||||
* make sense to just return ETIMEDOUT without sleeping.
|
||||
*/
|
||||
if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) &&
|
||||
(timeout_hz == 0))
|
||||
timeout_hz = 1;
|
||||
|
||||
|
||||
f = futex_get(args->uaddr, FUTEX_UNLOCKED);
|
||||
ret = futex_sleep(f, td, timeout_hz);
|
||||
futex_put(f);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAIT %d: uaddr = %p, "
|
||||
"ret = %d\n", td->td_proc->p_pid, args->uaddr, ret);
|
||||
#endif
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
switch (ret) {
|
||||
case EWOULDBLOCK: /* timeout */
|
||||
return ETIMEDOUT;
|
||||
break;
|
||||
case EINTR: /* signal */
|
||||
return EINTR;
|
||||
break;
|
||||
case 0: /* FUTEX_WAKE received */
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAIT %d: uaddr = %p, got FUTEX_WAKE\n",
|
||||
td->td_proc->p_pid, args->uaddr);
|
||||
#endif
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAIT: unexpected ret = %d\n", ret);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_WAKE:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
/*
|
||||
* XXX: Linux is able cope with different addresses
|
||||
* corresponding to the same mapped memory in the sleeping
|
||||
* and the waker process.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAKE %d: uaddr = %p, val = %d\n",
|
||||
td->td_proc->p_pid, args->uaddr, args->val);
|
||||
#endif
|
||||
f = futex_get(args->uaddr, FUTEX_UNLOCKED);
|
||||
td->td_retval[0] = futex_wake(f, args->val, NULL);
|
||||
futex_put(f);
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_CMP_REQUEUE:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
if ((error = copyin(args->uaddr,
|
||||
&val, sizeof(val))) != 0) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (val != args->val3) {
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
f = futex_get(args->uaddr, FUTEX_UNLOCKED);
|
||||
newf = futex_get(args->uaddr2, FUTEX_UNLOCKED);
|
||||
td->td_retval[0] = futex_wake(f, args->val, newf);
|
||||
futex_put(f);
|
||||
futex_put(newf);
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_REQUEUE:
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
|
||||
f = futex_get(args->uaddr, FUTEX_UNLOCKED);
|
||||
newf = futex_get(args->uaddr2, FUTEX_UNLOCKED);
|
||||
td->td_retval[0] = futex_wake(f, args->val, newf);
|
||||
futex_put(f);
|
||||
futex_put(newf);
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_FD:
|
||||
printf("linux_sys_futex: unimplemented op %d\n",
|
||||
args->op);
|
||||
break;
|
||||
|
||||
case LINUX_FUTEX_WAKE_OP:
|
||||
#ifdef __i386__
|
||||
FUTEX_SYSTEM_LOCK;
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX_WAKE_OP: %d: uaddr = %p, op = %d, val = %d, uaddr2 = %p, val3 = %d\n",
|
||||
td->td_proc->p_pid, args->uaddr, args->op, args->val, args->uaddr2, args->val3);
|
||||
#endif
|
||||
f = futex_get(args->uaddr, FUTEX_UNLOCKED);
|
||||
f2 = futex_get(args->uaddr2, FUTEX_UNLOCKED);
|
||||
|
||||
/* This function returns positive number as results
|
||||
* and negative as errors
|
||||
*/
|
||||
op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
|
||||
if (op_ret < 0) {
|
||||
|
||||
/* XXX: we dont handle the EFAULT yet */
|
||||
if (op_ret != -EFAULT) {
|
||||
futex_put(f);
|
||||
futex_put(f2);
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return (-op_ret);
|
||||
}
|
||||
|
||||
futex_put(f);
|
||||
futex_put(f2);
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
return (EFAULT);
|
||||
|
||||
}
|
||||
|
||||
ret = futex_wake(f, args->val, NULL);
|
||||
futex_put(f);
|
||||
if (op_ret > 0) {
|
||||
printf("second wakeup\n");
|
||||
op_ret = 0;
|
||||
/* Linux always puts there 0 retries */
|
||||
op_ret += futex_wake(f2, 0, NULL);
|
||||
ret += op_ret;
|
||||
}
|
||||
futex_put(f2);
|
||||
td->td_retval[0] = ret;
|
||||
|
||||
FUTEX_SYSTEM_UNLOCK;
|
||||
#else
|
||||
printf("linux_sys_futex: wake_op not implemented");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("linux_sys_futex: unknown op %d\n",
|
||||
args->op);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct futex *
|
||||
futex_get(void *uaddr, int locked)
|
||||
{
|
||||
struct futex *f;
|
||||
|
||||
if (locked == FUTEX_UNLOCKED)
|
||||
FUTEX_LOCK;
|
||||
LIST_FOREACH(f, &futex_list, f_list) {
|
||||
if (f->f_uaddr == uaddr) {
|
||||
f->f_refcount++;
|
||||
if (locked == FUTEX_UNLOCKED)
|
||||
FUTEX_UNLOCK;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
if (locked == FUTEX_UNLOCKED)
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
/* Not found, create it */
|
||||
f = malloc(sizeof(*f), M_LINUX, M_WAITOK);
|
||||
f->f_uaddr = uaddr;
|
||||
f->f_refcount = 1;
|
||||
TAILQ_INIT(&f->f_waiting_proc);
|
||||
if (locked == FUTEX_UNLOCKED)
|
||||
FUTEX_LOCK;
|
||||
LIST_INSERT_HEAD(&futex_list, f, f_list);
|
||||
if (locked == FUTEX_UNLOCKED)
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
futex_put(f)
|
||||
struct futex *f;
|
||||
{
|
||||
FUTEX_LOCK;
|
||||
f->f_refcount--;
|
||||
if (f->f_refcount == 0) {
|
||||
LIST_REMOVE(f, f_list);
|
||||
free(f, M_LINUX);
|
||||
}
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
futex_sleep(struct futex *f, struct thread *td, unsigned long timeout)
|
||||
{
|
||||
struct waiting_proc *wp;
|
||||
int ret;
|
||||
|
||||
wp = malloc(sizeof(*wp), M_LINUX, M_WAITOK);
|
||||
wp->wp_t = td;
|
||||
wp->wp_new_futex = NULL;
|
||||
FUTEX_LOCK;
|
||||
TAILQ_INSERT_TAIL(&f->f_waiting_proc, wp, wp_list);
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(sys_futex))
|
||||
printf("FUTEX --> %d tlseep timeout = %ld\n", td->td_proc->p_pid,
|
||||
timeout);
|
||||
#endif
|
||||
ret = tsleep(wp, PCATCH|PZERO, "linuxfutex", timeout);
|
||||
|
||||
FUTEX_LOCK;
|
||||
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
if ((ret == 0) && (wp->wp_new_futex != NULL)) {
|
||||
ret = futex_sleep(wp->wp_new_futex, td, timeout);
|
||||
futex_put(wp->wp_new_futex); /* futex_get called in wakeup */
|
||||
}
|
||||
|
||||
free(wp, M_LINUX);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
futex_wake(struct futex *f, int n, struct futex *newf)
|
||||
{
|
||||
struct waiting_proc *wp;
|
||||
int count = 0;
|
||||
|
||||
FUTEX_LOCK;
|
||||
TAILQ_FOREACH(wp, &f->f_waiting_proc, wp_list) {
|
||||
if (count <= n) {
|
||||
wakeup(wp);
|
||||
count++;
|
||||
} else {
|
||||
if (newf != NULL) {
|
||||
/* futex_put called after tsleep */
|
||||
wp->wp_new_futex = futex_get(newf->f_uaddr, FUTEX_LOCKED);
|
||||
wakeup(wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
FUTEX_UNLOCK;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
static int
|
||||
futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
|
||||
{
|
||||
int op = (encoded_op >> 28) & 7;
|
||||
int cmp = (encoded_op >> 24) & 15;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
int cmparg = (encoded_op << 20) >> 20;
|
||||
int oldval = 0, ret;
|
||||
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("futex_atomic_op: op = %d, cmp = %d, oparg = %d, cmparg = %d, uaddr = %p\n",
|
||||
op, cmp, oparg, cmparg, uaddr);
|
||||
#endif
|
||||
/* XXX: linux verifies access here and returns EFAULT */
|
||||
|
||||
critical_enter();
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
ret = futex_xchgl(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
ret = futex_addl(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
ret = futex_orl(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
ret = futex_andnl(oparg, uaddr, &oldval);
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
ret = futex_xorl(oparg, uaddr, &oldval);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
critical_exit();
|
||||
|
||||
if (!ret)
|
||||
switch (cmp) {
|
||||
case FUTEX_OP_CMP_EQ:
|
||||
ret = (oldval == cmparg);
|
||||
break;
|
||||
case FUTEX_OP_CMP_NE:
|
||||
ret = (oldval != cmparg);
|
||||
break;
|
||||
case FUTEX_OP_CMP_LT:
|
||||
ret = (oldval < cmparg);
|
||||
break;
|
||||
case FUTEX_OP_CMP_GE:
|
||||
ret = (oldval >= cmparg);
|
||||
break;
|
||||
case FUTEX_OP_CMP_LE:
|
||||
ret = (oldval <= cmparg);
|
||||
break;
|
||||
case FUTEX_OP_CMP_GT:
|
||||
ret = (oldval > cmparg);
|
||||
break;
|
||||
default: ret = -ENOSYS;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
61
sys/compat/linux/linux_futex.h
Normal file
61
sys/compat/linux/linux_futex.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* $NetBSD: linux_futex.h,v 1.2 2005/12/11 12:20:19 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Emmanuel Dreyfus
|
||||
* 4. The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUTEX_H
|
||||
#define _LINUX_FUTEX_H
|
||||
|
||||
#define LINUX_FUTEX_WAIT 0
|
||||
#define LINUX_FUTEX_WAKE 1
|
||||
#define LINUX_FUTEX_FD 2
|
||||
#define LINUX_FUTEX_REQUEUE 3
|
||||
#define LINUX_FUTEX_CMP_REQUEUE 4
|
||||
#define LINUX_FUTEX_WAKE_OP 5
|
||||
|
||||
#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
|
||||
#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
|
||||
#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */
|
||||
#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */
|
||||
#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */
|
||||
|
||||
#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */
|
||||
|
||||
#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */
|
||||
|
||||
#endif /* !_LINUX_FUTEX_H */
|
208
sys/compat/linux/linux_time.c
Normal file
208
sys/compat/linux/linux_time.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Emmanuel Dreyfus.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
#if 0
|
||||
__KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
|
||||
#endif
|
||||
|
||||
#include "opt_compat.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/stdint.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#ifdef COMPAT_LINUX32
|
||||
#include <machine/../linux32/linux.h>
|
||||
#include <machine/../linux32/linux32_proto.h>
|
||||
#else
|
||||
#include <machine/../linux/linux.h>
|
||||
#include <machine/../linux/linux_proto.h>
|
||||
#endif
|
||||
|
||||
static void native_to_linux_timespec(struct l_timespec *,
|
||||
struct timespec *);
|
||||
static void linux_to_native_timespec(struct timespec *,
|
||||
struct l_timespec *);
|
||||
static int linux_to_native_clockid(clockid_t *, clockid_t);
|
||||
|
||||
static void
|
||||
native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
|
||||
{
|
||||
ltp->tv_sec = ntp->tv_sec;
|
||||
ltp->tv_nsec = ntp->tv_nsec;
|
||||
}
|
||||
|
||||
static void
|
||||
linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
|
||||
{
|
||||
ntp->tv_sec = ltp->tv_sec;
|
||||
ntp->tv_nsec = ltp->tv_nsec;
|
||||
}
|
||||
|
||||
static int
|
||||
linux_to_native_clockid(clockid_t *n, clockid_t l)
|
||||
{
|
||||
switch (l) {
|
||||
case LINUX_CLOCK_REALTIME:
|
||||
*n = CLOCK_REALTIME;
|
||||
break;
|
||||
case LINUX_CLOCK_MONOTONIC:
|
||||
*n = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case LINUX_CLOCK_PROCESS_CPUTIME_ID:
|
||||
case LINUX_CLOCK_THREAD_CPUTIME_ID:
|
||||
case LINUX_CLOCK_REALTIME_HR:
|
||||
case LINUX_CLOCK_MONOTONIC_HR:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
|
||||
{
|
||||
struct l_timespec lts;
|
||||
int error;
|
||||
clockid_t nwhich = 0; /* XXX: GCC */
|
||||
struct timespec tp;
|
||||
|
||||
error = linux_to_native_clockid(&nwhich, args->which);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
error = kern_clock_gettime(td, nwhich, &tp);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
native_to_linux_timespec(<s, &tp);
|
||||
|
||||
return copyout(<s, args->tp, sizeof lts);
|
||||
}
|
||||
|
||||
int
|
||||
linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct l_timespec lts;
|
||||
int error;
|
||||
clockid_t nwhich = 0; /* XXX: GCC */
|
||||
|
||||
error = linux_to_native_clockid(&nwhich, args->which);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
error = copyin(args->tp, <s, sizeof lts);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
linux_to_native_timespec(&ts, <s);
|
||||
|
||||
return kern_clock_settime(td, nwhich, &ts);
|
||||
}
|
||||
|
||||
int
|
||||
linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct l_timespec lts;
|
||||
int error;
|
||||
clockid_t nwhich = 0; /* XXX: GCC */
|
||||
|
||||
if (args->tp == NULL)
|
||||
return (0);
|
||||
|
||||
error = linux_to_native_clockid(&nwhich, args->which);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
error = kern_clock_getres(td, nwhich, &ts);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
native_to_linux_timespec(<s, &ts);
|
||||
|
||||
return copyout(<s, args->tp, sizeof lts);
|
||||
}
|
||||
|
||||
int
|
||||
linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
|
||||
{
|
||||
struct timespec *rmtp;
|
||||
struct l_timespec lrqts, lrmts;
|
||||
struct timespec rqts, rmts;
|
||||
int error;
|
||||
|
||||
if (args->flags != 0)
|
||||
return EINVAL; /* XXX deal with TIMER_ABSTIME */
|
||||
|
||||
if (args->which != LINUX_CLOCK_REALTIME)
|
||||
return EINVAL;
|
||||
|
||||
error = copyin(args->rqtp, &lrqts, sizeof lrqts);
|
||||
if (error != 0)
|
||||
return error;
|
||||
|
||||
if (args->rmtp != NULL)
|
||||
rmtp = &rmts;
|
||||
else
|
||||
rmtp = NULL;
|
||||
|
||||
linux_to_native_timespec(&rqts, &lrqts);
|
||||
|
||||
error = kern_nanosleep(td, &rqts, rmtp);
|
||||
if (error != 0)
|
||||
return error;
|
||||
if (args->rmtp != NULL) {
|
||||
native_to_linux_timespec(&lrmts, rmtp);
|
||||
error = copyout(&lrmts, args->rmtp, sizeof lrmts );
|
||||
if (error != 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user