Subject: proposal for Linux exit_group emulation
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 12/01/2005 22:26:13
--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
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
--fdj2RfSjLxBAspz7
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="exit_group.diff"
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++;
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);
+ }
+ }
+#endif /* LINUX_NPTL */
exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
/* NOTREACHED */
--fdj2RfSjLxBAspz7--