1) Complete Linux exit_group() emulation

Members of the thread group must die without reporting to the parent and
without going to zombie stage. We do that by reparenting to init before
catching a SIGKILL. The parent will not see the child death.

The thread group leader must report the exit status, even if it exits
because of another thread calling exit_group(). We do that by storing the
exit status in struct linux_emuldata_shared, and the exit hook has the
duty of setting struct proc's p_xstat for the thread group leader.

2) For exit/fork/exec hooks, move the NPTL specific code to separate functions
that are shared between COMPAT_LINUX and COMPAT_LINUX32

3) Fix LINUX_CLONE_PARENT_SETTID semantics
This commit is contained in:
manu 2006-08-23 19:49:09 +00:00
parent 52ef6583f9
commit 81c909dd45
9 changed files with 255 additions and 247 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.c,v 1.13 2005/12/16 14:16:14 christos Exp $ */
/* $NetBSD: linux_machdep.c,v 1.14 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved.
@ -33,7 +33,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.13 2005/12/16 14:16:14 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.14 2006/08/23 19:49:09 manu Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -312,6 +312,7 @@ linux_sys_modify_ldt(l, v, retval)
void *v;
register_t *retval;
{
printf("linux_sys_modify_ldt\n");
return 0;
}
@ -608,25 +609,25 @@ linux_buildcontext(struct lwp *l, void *catcher, void *f)
tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
}
unsigned long
void *
linux_get_newtls(l)
struct lwp *l;
{
struct trapframe *tf = l->l_md.md_regs;
return tf->tf_r8;
return (void *)tf->tf_r8;
}
int
linux_set_newtls(l, tls)
struct lwp *l;
unsigned long tls;
void *tls;
{
struct linux_sys_arch_prctl_args cup;
register_t retval;
SCARG(&cup, code) = LINUX_ARCH_SET_FS;
SCARG(&cup, addr) = tls;
SCARG(&cup, addr) = (unsigned long)tls;
return linux_sys_arch_prctl(l, &cup, &retval);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_emuldata.h,v 1.11 2006/06/25 16:15:39 manu Exp $ */
/* $NetBSD: linux_emuldata.h,v 1.12 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1998,2002 The NetBSD Foundation, Inc.
@ -53,8 +53,12 @@ struct linux_emuldata_shared {
pid_t group_pid; /* PID of Linux process (group of threads) */
/* List of Linux threads (NetBSD processes) in the Linux process */
LIST_HEAD(, linux_emuldata) threads;
int flags; /* See below */
int xstat; /* Thread group exit code, for exit_group */
};
#define LINUX_LES_INEXITGROUP 0x1 /* thread group doing exit_group() */
struct linux_emuldata {
#if notyet
sigset_t ps_siginfo; /* Which signals have a RT handler */
@ -63,15 +67,24 @@ struct linux_emuldata {
/* see ../arch/i386/linux_ptrace.c */
struct linux_emuldata_shared *s;
#ifdef LINUX_NPTL
void *parent_tidptr; /* Used during clone() */
void *child_tidptr; /* Used during clone() */
int clone_flags; /* Used during clone() */
void *clear_tid; /* Own TID to clear on exit */
void *set_tls; /* Pointer to child TLS desc in user space */
#if 0
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 */
int *set_tid; /* in clone(): Own TID to set on clone */
int *clear_tid; /* Own TID to clear on exit */
unsigned long set_tls; /* New TLS in child if not 0 */
int flags; /* See above */
#endif
#endif
/* List of Linux threads (NetBSD processes) in the Linux process */
LIST_ENTRY(linux_emuldata) threads;
struct proc *proc; /* backpointer to struct proc */
};
#define LINUX_CHILD_QUIETEXIT 0x1 /* Child will have quietexit set */
#define LINUX_QUIETEXIT 0x2 /* Quiet exit (no zombie state) */
#endif /* !_COMMON_LINUX_EMULDATA_H */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_exec.c,v 1.84 2006/06/25 16:15:39 manu Exp $ */
/* $NetBSD: linux_exec.c,v 1.85 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.84 2006/06/25 16:15:39 manu Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.85 2006/08/23 19:49:09 manu Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -55,6 +55,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.84 2006/06/25 16:15:39 manu Exp $")
#include <sys/sa.h>
#include <sys/syscallargs.h>
#include <sys/ptrace.h> /* For proc_reparent() */
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
@ -63,8 +65,9 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.84 2006/06/25 16:15:39 manu Exp $")
#include <compat/linux/common/linux_types.h>
#include <compat/linux/common/linux_signal.h>
#include <compat/linux/common/linux_util.h>
#include <compat/linux/common/linux_exec.h>
#include <compat/linux/common/linux_sched.h>
#include <compat/linux/common/linux_machdep.h>
#include <compat/linux/common/linux_exec.h>
#include <compat/linux/common/linux_futex.h>
#include <compat/linux/linux_syscallargs.h>
@ -83,7 +86,7 @@ static void linux_e_proc_exit __P((struct proc *));
static void linux_e_proc_init __P((struct proc *, struct proc *, int));
#ifdef LINUX_NPTL
static void linux_userret __P((struct lwp *, void *));
void linux_userret __P((struct lwp *, void *));
#endif
/*
@ -221,6 +224,9 @@ linux_e_proc_init(p, parent, forkflags)
* Initialize the list of threads in the group
*/
LIST_INIT(&s->threads);
s->xstat = 0;
s->flags = 0;
}
e->s = s;
@ -231,23 +237,10 @@ linux_e_proc_init(p, parent, forkflags)
LIST_INSERT_HEAD(&s->threads, e, threads);
#ifdef LINUX_NPTL
/*
* initialize TID pointers. ep->child_clear_tid and
* ep->child_set_tid will not be used beyond this point.
*/
e->child_clear_tid = NULL;
e->child_set_tid = NULL;
if (ep != NULL) {
e->clear_tid = ep->child_clear_tid;
e->set_tid = ep->child_set_tid;
e->set_tls = ep->set_tls;
ep->child_clear_tid = NULL;
ep->child_set_tid = NULL;
ep->set_tls = 0;
} else {
e->clear_tid = NULL;
e->set_tid = NULL;
e->set_tls = 0;
e->parent_tidptr = ep->parent_tidptr;
e->child_tidptr = ep->child_tidptr;
e->clone_flags = ep->clone_flags;
}
#endif /* LINUX_NPTL */
@ -278,32 +271,8 @@ linux_e_proc_exit(p)
struct linux_emuldata *e = p->p_emuldata;
#ifdef LINUX_NPTL
/* Emulate LINUX_CLONE_CHILD_CLEARTID */
if (e->clear_tid != NULL) {
int error;
int null = 0;
struct linux_sys_futex_args cup;
register_t retval;
struct lwp *l;
error = copyout(&null, e->clear_tid, sizeof(null));
#ifdef DEBUG_LINUX
if (error != 0)
printf("linux_e_proc_exit: cannot clear TID\n");
linux_nptl_proc_exit(p);
#endif
l = proc_representative_lwp(p);
SCARG(&cup, uaddr) = e->clear_tid;
SCARG(&cup, op) = LINUX_FUTEX_WAKE;
SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */
SCARG(&cup, timeout) = NULL;
SCARG(&cup, uaddr2) = NULL;
SCARG(&cup, val3) = 0;
if ((error = linux_sys_futex(l, &cup, &retval)) != 0)
printf("linux_e_proc_exit: linux_sys_futex failed\n");
}
#endif /* LINUX_NPTL */
/* Remove the thread for the group thread list */
LIST_REMOVE(e, threads);
@ -323,10 +292,6 @@ linux_e_proc_fork(p, parent, forkflags)
struct proc *p, *parent;
int forkflags;
{
#ifdef LINUX_NPTL
struct linux_emuldata *e;
#endif
/*
* The new process might share some vmspace-related stuff
* with parent, depending on fork flags (CLONE_VM et.al).
@ -337,21 +302,14 @@ linux_e_proc_fork(p, parent, forkflags)
linux_e_proc_init(p, parent, forkflags);
#ifdef LINUX_NPTL
/*
* Emulate LINUX_CLONE_CHILD_SETTID and LINUX_CLONE_TLS:
* This cannot be done right now because the child VM
* is not set up. We will do it at userret time.
*/
e = p->p_emuldata;
if ((e->set_tid != NULL) || (e->set_tls != 0))
p->p_userret = (*linux_userret);
linux_nptl_proc_fork(p, parent, (*linux_userret));
#endif
return;
}
#ifdef LINUX_NPTL
static void
void
linux_userret(l, arg)
struct lwp *l;
void *arg;
@ -362,19 +320,140 @@ linux_userret(l, arg)
p->p_userret = NULL;
/* Emulate LINUX_CLONE_CHILD_SETTID */
if (led->set_tid != NULL) {
if ((error = copyout(&p->p_pid,
led->set_tid, sizeof(p->p_pid))) != 0)
printf("linux_userret: cannot set TID\n");
/* LINUX_CLONE_CHILD_SETTID: copy child's TID to child's memory */
if (led->clone_flags & LINUX_CLONE_CHILD_SETTID) {
if ((error = copyout(&l->l_proc->p_pid,
led->child_tidptr, sizeof(l->l_proc->p_pid))) != 0)
printf("linux_userret: LINUX_CLONE_CHILD_SETTID "
"failed (led->child_tidptr = %p, p->p_pid = %d)\n",
led->child_tidptr, p->p_pid);
}
/* Emulate LINUX_CLONE_NEWTLS */
if (led->set_tls != 0) {
if (linux_set_newtls(l, led->set_tls) != 0)
printf("linux_userret: cannot set TLS\n");
/* LINUX_CLONE_SETTLS: allocate a new TLS */
if (led->clone_flags & LINUX_CLONE_SETTLS) {
if (linux_set_newtls(l, linux_get_newtls(l)) != 0)
printf("linux_userret: linux_set_tls failed");
}
return;
}
void
linux_nptl_proc_exit(p)
struct proc *p;
{
struct linux_emuldata *e = p->p_emuldata;
int s;
/*
* Check if we are a thread group leader victim of another
* thread doing exit_group(). If we are, change the exit code.
*/
if ((e->s->group_pid == p->p_pid) &&
(e->s->flags & LINUX_LES_INEXITGROUP)) {
p->p_xstat = e->s->xstat;
}
/*
* Members of the thread groups others than the leader should
* exit quietely: no zombie stage, no signal. We do that by
* reparenting to init. init will collect us and nobody will
* notice what happened.
*/
#ifdef DEBUG_LINUX
printf("%s:%d e->s->group_pid = %d, p->p_pid = %d, flags = 0x%x\n",
__func__, __LINE__, e->s->group_pid, p->p_pid, e->s->flags);
#endif
if (e->s->group_pid != p->p_pid) {
wakeup(initproc);
SCHED_LOCK(s);
proc_reparent(p, initproc);
SCHED_UNLOCK(s);
}
/* Emulate LINUX_CLONE_CHILD_CLEARTID */
if (e->clear_tid != NULL) {
int error;
int null = 0;
struct linux_sys_futex_args cup;
register_t retval;
struct lwp *l;
error = copyout(&null, e->clear_tid, sizeof(null));
#ifdef DEBUG_LINUX
if (error != 0)
printf("%s: cannot clear TID\n", __func__);
#endif
l = proc_representative_lwp(p);
SCARG(&cup, uaddr) = e->clear_tid;
SCARG(&cup, op) = LINUX_FUTEX_WAKE;
SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */
SCARG(&cup, timeout) = NULL;
SCARG(&cup, uaddr2) = NULL;
SCARG(&cup, val3) = 0;
if ((error = linux_sys_futex(l, &cup, &retval)) != 0)
printf("%s: linux_sys_futex failed\n", __func__);
}
return;
}
void
linux_nptl_proc_fork(p, parent, luserret)
struct proc *p;
struct proc *parent;
void (luserret)(struct lwp *, void *);
{
#ifdef LINUX_NPTL
struct linux_emuldata *e;
#endif
e = p->p_emuldata;
/* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
if (e->clone_flags & LINUX_CLONE_CHILD_CLEARTID)
e->clear_tid = e->child_tidptr;
/* LINUX_CLONE_PARENT_SETTID: set child's TID in parent's memory */
if (e->clone_flags & LINUX_CLONE_PARENT_SETTID) {
if (copyout_proc(parent, &p->p_pid,
e->parent_tidptr, sizeof(p->p_pid)) != 0)
printf("%s: LINUX_CLONE_PARENT_SETTID "
"failed (e->parent_tidptr = %p, "
"parent->p_pid = %d, p->p_pid = %d)\n",
__func__, e->parent_tidptr,
parent->p_pid, p->p_pid);
}
/*
* CLONE_CHILD_SETTID and LINUX_CLONE_SETTLS require child's VM
* setup to be completed, we postpone them until userret time.
*/
if (e->clone_flags &
(LINUX_CLONE_CHILD_CLEARTID | LINUX_CLONE_SETTLS))
p->p_userret = (*luserret);
return;
}
void
linux_nptl_proc_init(p, parent)
struct proc *p;
struct proc *parent;
{
struct linux_emuldata *e = p->p_emuldata;
struct linux_emuldata *ep;
if ((parent != NULL) && (parent->p_emuldata != NULL)) {
ep = parent->p_emuldata;
e->parent_tidptr = ep->parent_tidptr;
e->child_tidptr = ep->child_tidptr;
e->clone_flags = ep->clone_flags;
}
return;
}
#endif /* LINUX_NPTL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_exec.h,v 1.38 2006/08/07 14:19:57 manu Exp $ */
/* $NetBSD: linux_exec.h,v 1.39 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -137,6 +137,12 @@ int linux_aout_copyargs __P((struct lwp *, struct exec_package *,
struct ps_strings *, char **, void *));
void linux_trapsignal __P((struct lwp *, const ksiginfo_t *));
int linux_usertrap __P((struct lwp *, vaddr_t, void *));
#ifdef LINUX_NPTL
void linux_nptl_proc_fork __P((struct proc *, struct proc *,
void (luserret)(struct lwp *, void *)));
void linux_nptl_proc_exit __P((struct proc *));
void linux_nptl_proc_init __P((struct proc *, struct proc *));
#endif
#ifdef EXEC_ELF32
int linux_elf32_probe __P((struct lwp *, struct exec_package *, void *,

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.h,v 1.14 2005/12/11 12:20:19 christos Exp $ */
/* $NetBSD: linux_machdep.h,v 1.15 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -64,8 +64,8 @@ dev_t linux_fakedev __P((dev_t, int));
__END_DECLS
#ifdef LINUX_NPTL
__BEGIN_DECLS
unsigned long linux_get_newtls __P((struct lwp *));
int linux_set_newtls __P((struct lwp *, unsigned long));
void *linux_get_newtls __P((struct lwp *));
int linux_set_newtls __P((struct lwp *, void *));
__END_DECLS
#endif /* !LINUX_NPTL */
#endif /* !_KERNEL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_sched.c,v 1.33 2006/07/23 22:06:09 ad Exp $ */
/* $NetBSD: linux_sched.c,v 1.34 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.33 2006/07/23 22:06:09 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.34 2006/08/23 19:49:09 manu Exp $");
#include <sys/param.h>
#include <sys/mount.h>
@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.33 2006/07/23 22:06:09 ad Exp $");
#include <sys/syscallargs.h>
#include <sys/wait.h>
#include <sys/kauth.h>
#include <sys/ptrace.h>
#include <machine/cpu.h>
@ -116,49 +117,19 @@ linux_sys_clone(l, v, retval)
if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
flags |= FORK_PPWAIT;
/* Thread should not issue a SIGCHLD on termination */
if (SCARG(uap, flags) & LINUX_CLONE_THREAD) {
sig = 0;
} else {
sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
if (sig < 0 || sig >= LINUX__NSIG)
return (EINVAL);
sig = linux_to_native_signo[sig];
}
sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
if (sig < 0 || sig >= LINUX__NSIG)
return (EINVAL);
sig = linux_to_native_signo[sig];
#ifdef LINUX_NPTL
led = (struct linux_emuldata *)l->l_proc->p_emuldata;
if (SCARG(uap, flags) & LINUX_CLONE_PARENT_SETTID) {
if (SCARG(uap, parent_tidptr) == NULL) {
printf("linux_sys_clone: NULL parent_tidptr\n");
return EINVAL;
}
if ((error = copyout(&l->l_proc->p_pid,
SCARG(uap, parent_tidptr),
sizeof(l->l_proc->p_pid))) != 0)
return error;
}
/* CLONE_CHILD_CLEARTID: TID clear in the child on exit() */
if (SCARG(uap, flags) & LINUX_CLONE_CHILD_CLEARTID)
led->child_clear_tid = SCARG(uap, child_tidptr);
else
led->child_clear_tid = NULL;
/* CLONE_CHILD_SETTID: TID set in the child on clone() */
if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID)
led->child_set_tid = SCARG(uap, child_tidptr);
else
led->child_set_tid = NULL;
/* CLONE_SETTLS: new Thread Local Storage in the child */
if (SCARG(uap, flags) & LINUX_CLONE_SETTLS)
led->set_tls = linux_get_newtls(l);
else
led->set_tls = 0;
led->parent_tidptr = SCARG(uap, parent_tidptr);
led->child_tidptr = SCARG(uap, child_tidptr);
led->clone_flags = SCARG(uap, flags);
#endif /* LINUX_NPTL */
/*
* Note that Linux does not provide a portable way of specifying
* the stack area; the caller must know if the stack grows up
@ -291,6 +262,7 @@ linux_sys_sched_setscheduler(cl, v, retval)
return EPERM;
}
return 0;
/*
* We can't emulate anything put the default scheduling policy.
*/
@ -407,76 +379,47 @@ linux_sys_exit_group(l, v, retval)
struct proc *p = l->l_proc;
struct linux_emuldata *led = p->p_emuldata;
struct linux_emuldata *e;
struct lwp *sl;
struct proc *sp;
int s;
SCHED_LOCK(s);
#ifdef DEBUG_LINUX
printf("%s:%d, led->s->refs = %d\n", __func__, __LINE__, led->s->refs);
#endif
/*
* The calling thread is supposed to kill all threads
* in the same thread group (i.e. all threads created
* via clone(2) with CLONE_THREAD flag set).
*
* If there is only one thread, things are quite simple
*/
LIST_FOREACH(e, &led->s->threads, threads) {
sp = e->proc;
if (led->s->refs == 1)
return sys_exit(l, v, retval);
if (sp == p)
continue;
#ifdef DEBUG_LINUX
printf("linux_sys_exit_group: kill PID %d\n", sp->p_pid);
printf("%s:%d\n", __func__, __LINE__);
#endif
/* wakeup any waiter */
if (sp->p_sigctx.ps_sigwaited &&
sigismember(sp->p_sigctx.ps_sigwait, SIGKILL) &&
sp->p_stat != SSTOP) {
sched_wakeup(&sp->p_sigctx.ps_sigwait);
}
/* post SIGKILL */
sigaddset(&sp->p_sigctx.ps_siglist, SIGKILL);
sp->p_sigctx.ps_sigcheck = 1;
led->s->flags |= LINUX_LES_INEXITGROUP;
led->s->xstat = W_EXITCODE(SCARG(uap, error_code), 0);
/* Unblock the process if sleeping or stopped */
switch(sp->p_stat) {
case SSTOP:
sl = proc_unstop(sp);
break;
case SACTIVE:
sl = proc_representative_lwp(sp);
break;
default:
sl = NULL;
break;
}
if (sl == NULL) {
printf("linux_sys_exit_group: no lwp for process %d\n",
sp->p_pid);
/*
* Kill all threads in the group. The emulation exit hook takes
* care of hiding the zombies and reporting the exit code properly
*/
LIST_FOREACH(e, &led->s->threads, threads) {
if (e->proc == p)
continue;
}
if (sl->l_priority > PUSER)
sl->l_priority = PUSER;
switch(sl->l_stat) {
case LSSUSPENDED:
lwp_continue(sl);
/* FALLTHROUGH */
case LSSTOP:
case LSSLEEP:
case LSIDL:
setrunnable(sl);
/* FALLTHROUGH */
default:
break;
}
#ifdef DEBUG_LINUX
printf("%s: kill PID %d\n", __func__, e->proc->p_pid);
#endif
psignal(e->proc, SIGKILL);
}
SCHED_UNLOCK(s);
#endif /* LINUX_NPTL */
exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
/* NOTREACHED */
/* Now, kill ourselves */
psignal(p, SIGKILL);
return 0;
#else /* LINUX_NPTL */
return sys_exit(l, v, retval);
#endif /* LINUX_NPTL */
}
#endif /* !__m68k__ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux32_exec.c,v 1.2 2006/06/25 16:15:40 manu Exp $ */
/* $NetBSD: linux32_exec.c,v 1.3 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1994-2006 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux32_exec.c,v 1.2 2006/06/25 16:15:40 manu Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux32_exec.c,v 1.3 2006/08/23 19:49:09 manu Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_exec.c,v 1.2 2006/06/25 16:15:40 manu Exp $"
#include <sys/mman.h>
#include <sys/sa.h>
#include <sys/syscallargs.h>
#include <sys/ptrace.h> /* For proc_reparent() */
#include <uvm/uvm_extern.h>
@ -84,7 +85,11 @@ static void linux32_e_proc_exit __P((struct proc *));
static void linux32_e_proc_init __P((struct proc *, struct proc *, int));
#ifdef LINUX32_NPTL
static void linux32_userret __P((struct lwp *, void *));
void linux32_userret __P((struct lwp *, void *));
void linux_nptl_proc_fork __P((struct proc *, struct proc *,
void (luserret)(struct lwp *, void *)));
void linux_nptl_proc_exit __P((struct proc *));
void linux_nptl_proc_init __P((struct proc *, struct proc *));
#endif
/*
@ -186,6 +191,9 @@ linux32_e_proc_init(p, parent, forkflags)
* Initialize the list of threads in the group
*/
LIST_INIT(&s->threads);
s->xstat = 0;
s->flags = 0;
}
e->s = s;
@ -196,24 +204,7 @@ linux32_e_proc_init(p, parent, forkflags)
LIST_INSERT_HEAD(&s->threads, e, threads);
#ifdef LINUX32_NPTL
/*
* initialize TID pointers. ep->child_clear_tid and
* ep->child_set_tid will not be used beyond this point.
*/
e->child_clear_tid = NULL;
e->child_set_tid = NULL;
if (ep != NULL) {
e->clear_tid = ep->child_clear_tid;
e->set_tid = ep->child_set_tid;
e->set_tls = ep->set_tls;
ep->child_clear_tid = NULL;
ep->child_set_tid = NULL;
ep->set_tls = 0;
} else {
e->clear_tid = NULL;
e->set_tid = NULL;
e->set_tls = 0;
}
linux_nptl_proc_init(p, parent);
#endif /* LINUX32_NPTL */
p->p_emuldata = e;
@ -243,30 +234,7 @@ linux32_e_proc_exit(p)
struct linux_emuldata *e = p->p_emuldata;
#ifdef LINUX32_NPTL
/* Emulate LINUX_CLONE_CHILD_CLEARTID */
if (e->clear_tid != NULL) {
int error;
int null = 0;
struct linux32_sys_futex_args cup;
register_t retval;
struct lwp *l;
error = copyout(&null, e->clear_tid, sizeof(null));
#ifdef DEBUG_LINUX
if (error != 0)
printf("linux32_e_proc_exit: cannot clear TID\n");
#endif
l = proc_representative_lwp(p);
SCARG(&cup, uaddr) = e->clear_tid;
SCARG(&cup, op) = LINUX_FUTEX_WAKE;
SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */
SCARG(&cup, timeout) = NULL;
SCARG(&cup, uaddr2) = NULL;
SCARG(&cup, val3) = 0;
if ((error = linux32_sys_futex(l, &cup, &retval)) != 0)
printf("linux32_e_proc_exit: linux_sys_futex failed\n");
}
linux_nptl_proc_exit(p);
#endif /* LINUX32_NPTL */
/* Remove the thread for the group thread list */
@ -288,10 +256,6 @@ linux32_e_proc_fork(p, parent, forkflags)
struct proc *p, *parent;
int forkflags;
{
#ifdef LINUX32_NPTL
struct linux_emuldata *e;
#endif
/*
* The new process might share some vmspace-related stuff
* with parent, depending on fork flags (CLONE_VM et.al).
@ -302,21 +266,14 @@ linux32_e_proc_fork(p, parent, forkflags)
linux32_e_proc_init(p, parent, forkflags);
#ifdef LINUX32_NPTL
/*
* Emulate LINUX_CLONE_CHILD_SETTID and LINUX_CLONE_TLS:
* This cannot be done right now because the child VM
* is not set up. We will do it at userret time.
*/
e = p->p_emuldata;
if ((e->set_tid != NULL) || (e->set_tls != 0))
p->p_userret = (*linux32_userret);
linux_nptl_proc_fork(p, parent, (*linux32_userret));
#endif
return;
}
#ifdef LINUX32_NPTL
static void
void
linux32_userret(l, arg)
struct lwp *l;
void *arg;
@ -327,17 +284,19 @@ linux32_userret(l, arg)
p->p_userret = NULL;
/* Emulate LINUX_CLONE_CHILD_SETTID */
if (led->set_tid != NULL) {
if ((error = copyout(&p->p_pid,
led->set_tid, sizeof(p->p_pid))) != 0)
printf("linux32_userret: cannot set TID\n");
/* LINUX_CLONE_CHILD_SETTID: copy child's TID to child's memory */
if (led->clone_flags & LINUX_CLONE_CHILD_SETTID) {
if ((error = copyout(&l->l_proc->p_pid,
led->child_tidptr, sizeof(l->l_proc->p_pid))) != 0)
printf("linux32_userret: LINUX_CLONE_CHILD_SETTID "
"failed (led->child_tidptr = %p, p->p_pid = %d)\n",
led->child_tidptr, p->p_pid);
}
/* Emulate LINUX_CLONE_NEWTLS */
if (led->set_tls != 0) {
if (linux32_set_newtls(l, led->set_tls) != 0)
printf("linux32_userret: cannot set TLS\n");
/* LINUX_CLONE_SETTLS: allocate a new TLS */
if (led->clone_flags & LINUX_CLONE_SETTLS) {
if (linux32_set_newtls(l, linux32_get_newtls(l)) != 0)
printf("linux32_userret: linux32_set_tls failed");
}
return;

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux32_exec.h,v 1.2 2006/08/07 14:19:57 manu Exp $ */
/* $NetBSD: linux32_exec.h,v 1.3 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
@ -44,6 +44,11 @@ extern const struct emul emul_linux32;
/* XXXmanu Do a.out later... */
#ifdef LINUX32_NPTL
void linux_nptl_exit_hook __P((struct proc *));
#endif
#ifdef EXEC_ELF32
int linux32_elf32_probe __P((struct lwp *, struct exec_package *, void *,
char *, vaddr_t *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_exit.c,v 1.157 2006/07/19 21:11:37 ad Exp $ */
/* $NetBSD: kern_exit.c,v 1.158 2006/08/23 19:49:09 manu Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.157 2006/07/19 21:11:37 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.158 2006/08/23 19:49:09 manu Exp $");
#include "opt_ktrace.h"
#include "opt_perfctrs.h"
@ -335,7 +335,11 @@ exit1(struct lwp *l, int rv)
/*
* If emulation has process exit hook, call it now.
* Set the exit status now so that the exit hook has
* an opportunity to tweak it (COMPAT_LINUX requires
* this for thread group emulation)
*/
p->p_xstat = rv;
if (p->p_emul->e_proc_exit)
(*p->p_emul->e_proc_exit)(p);
@ -367,12 +371,10 @@ exit1(struct lwp *l, int rv)
*/
/*
* Save exit status and final rusage info, adding in child rusage
* info and self times.
* Save final rusage info, adding in child rusage info and self times.
* In order to pick up the time for the current execution, we must
* do this before unlinking the lwp from l_list.
*/
p->p_xstat = rv;
*p->p_ru = p->p_stats->p_ru;
calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
ruadd(p->p_ru, &p->p_stats->p_cru);