Subject: Re: proposal for Linux exit_group emulation
To: None <tech-kern@netbsd.org>
From: Christos Zoulas <christos@astron.com>
List: tech-kern
Date: 12/02/2005 13:35:42
In article <20051201222613.GH21477@NetBSD.org>,
Emmanuel Dreyfus <manu@netbsd.org> wrote:
>-=-=-=-=-=-
>
>Hello
>
>Please find attached a proposal for emulating Linux exit_group(). I'm not
>sur it follows The Right Way.
>
>exit_group is supposed to exit all threads of a group. We emulate Linux
>threads as processes with shared memory.
>
>In order to exit all the processes in a group:
>- I awake sleeping processes
>- I tag processes as doomed by exit_grouo
>- a test in syscall and userret checks the tag and call exit1 if nescessary.
>
>I'm not sure the test in syscall is a good idea.
>--
>Emmanuel Dreyfus
>manu@netbsd.org
>
>-=-=-=-=-=-
>
>Index: arch/amd64/amd64/syscall.c
>===================================================================
>RCS file: /cvsroot/src/sys/arch/amd64/amd64/syscall.c,v
>retrieving revision 1.12
>diff -U2 -r1.12 syscall.c
>--- arch/amd64/amd64/syscall.c 13 Nov 2005 00:14:57 -0000 1.12
>+++ arch/amd64/amd64/syscall.c 1 Dec 2005 22:14:42 -0000
>@@ -128,4 +128,11 @@
> size_t argsize, argoff;
> register_t code, args[9], rval[2], *argp;
>+#ifdef COMPAT_LINUX
>+ struct linux_emuldata *led;
>+
>+ led = l->l_proc->p_emuldata;
>+ if (led->exit_group)
>+ return exit1(l, 0);
>+#endif
>
> uvmexp.syscalls++;
>@@ -235,4 +244,11 @@
> size_t argsize, argoff;
> register_t code, args[9], rval[2], *argp;
>+#ifdef COMPAT_LINUX
>+ struct linux_emuldata *led;
>+
>+ led = l->l_proc->p_emuldata;
>+ if (led->exit_group)
>+ return exit1(l, 0);
>+#endif
>
> uvmexp.syscalls++;
There is a linux_syscall.c where the above should go.
>Index: compat/linux/common/linux_emuldata.h
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_emuldata.h,v
>retrieving revision 1.9
>diff -U2 -r1.9 linux_emuldata.h
>--- compat/linux/common/linux_emuldata.h 5 Nov 2005 00:47:26 -0000 1.9
>+++ compat/linux/common/linux_emuldata.h 1 Dec 2005 22:14:42 -0000
>@@ -65,4 +65,5 @@
> int *clear_tid; /* Own TID to clear on exit */
> unsigned long set_tls; /* New TLS in child if not 0 */
>+ int exit_group; /* Set to 1 if exit_group in operation */
> #endif
> };
>Index: compat/linux/common/linux_exec.c
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_exec.c,v
>retrieving revision 1.82
>diff -U2 -r1.82 linux_exec.c
>--- compat/linux/common/linux_exec.c 23 Nov 2005 22:38:46 -0000 1.82
>+++ compat/linux/common/linux_exec.c 1 Dec 2005 22:14:43 -0000
>@@ -64,6 +64,6 @@
> #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_machdep.h>
>+#include <compat/linux/common/linux_exec.h>
> #include <compat/linux/common/linux_futex.h>
>
>@@ -83,8 +83,4 @@
> static void linux_e_proc_init __P((struct proc *, struct proc *, int));
>
>-#ifdef LINUX_NPTL
>-static void linux_userret __P((struct lwp *, void *));
>-#endif
>-
> /*
> * Execve(2). Just check the alternate emulation path, and pass it on
>@@ -226,4 +222,5 @@
> e->child_clear_tid = NULL;
> e->child_set_tid = NULL;
>+ e->exit_group = 0;
> if (ep != NULL) {
> e->clear_tid = ep->child_clear_tid;
>@@ -336,5 +336,5 @@
>
> #ifdef LINUX_NPTL
>-static void
>+void
> linux_userret(l, arg)
> struct lwp *l;
>@@ -347,4 +347,8 @@
> p->p_userret = NULL;
>
>+ /* Emulate exit_group() */
>+ if (led->exit_group)
>+ return exit1(l, 0);
>+
> /* Emulate LINUX_CLONE_CHILD_SETTID */
> if (led->set_tid != NULL) {
>Index: compat/linux/common/linux_exec.h
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_exec.h,v
>retrieving revision 1.35
>diff -U2 -r1.35 linux_exec.h
>--- compat/linux/common/linux_exec.h 20 May 2005 12:48:27 -0000 1.35
>+++ compat/linux/common/linux_exec.h 1 Dec 2005 22:14:43 -0000
>@@ -146,4 +146,8 @@
> #endif
> __END_DECLS
>+
>+#ifdef LINUX_NPTL
>+void linux_userret __P((struct lwp *, void *));
>+#endif
> #endif /* !_KERNEL */
>
>Index: compat/linux/common/linux_sched.c
>===================================================================
>RCS file: /cvsroot/src/sys/compat/linux/common/linux_sched.c,v
>retrieving revision 1.29
>diff -U2 -r1.29 linux_sched.c
>--- compat/linux/common/linux_sched.c 29 Nov 2005 22:31:59 -0000 1.29
>+++ compat/linux/common/linux_sched.c 1 Dec 2005 22:14:43 -0000
>@@ -60,4 +60,5 @@
> #include <compat/linux/common/linux_signal.h>
> #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */
>+#include <compat/linux/common/linux_exec.h>
> #include <compat/linux/common/linux_emuldata.h>
>
>@@ -407,13 +408,45 @@
> syscallarg(int) error_code;
> } */ *uap = v;
>+#ifdef LINUX_NPTL
>+ struct proc *p;
>+ struct linux_emuldata *led;
>+ pid_t group_pid;
>
> /*
>- * XXX The calling thread is supposed to kill all threads
>+ * 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). This appears
>- * to not be used yet, so the thread group handling
>- * is currently not implemented.
>+ * via clone(2) with CLONE_THREAD flag set).
> */
>+ led = l->l_proc->p_emuldata;
>+ group_pid = led->s->group_pid;
>+
>+ PROCLIST_FOREACH(p, &allproc) {
>+ if (p->p_emul != &emul_linux)
>+ continue;
>+
>+ if (p == l->l_proc)
>+ continue;
>+
>+ led = p->p_emuldata;
>+ if (led->s->group_pid == group_pid) {
>+ struct lwp *cl;
>+
>+ /* There is only one LWP in Linux processes... */
>+ cl = proc_representative_lwp(p);
>+
>+ printf("exit with pid %d\n", p->p_pid);
>+ if (cl->l_stat == LSSLEEP) {
>+ printf(" awake pid %d wchan %s\n",
>+ p->p_pid, l->l_wmesg);
>+ wakeup(cl->l_wchan);
>+ }
>+
>+ /* Tag as a process to exit */
>+ led->exit_group = 1;
>+ p->p_userret = (*linux_userret);
This looks ugly to me. Why trap both the syscall and tne userret?
>+ }
>+ }
>
>+#endif /* LINUX_NPTL */
> exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
> /* NOTREACHED */
>
>-=-=-=-=-=-
Have you tested the above with openoffice or java?
christos