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