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:
parent
52ef6583f9
commit
81c909dd45
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 *,
|
||||
|
@ -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 */
|
||||
|
@ -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__ */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 *));
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user