From nobody@FreeBSD.org  Mon Feb 22 01:40:42 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 5E96A10657C7
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 22 Feb 2010 01:40:42 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 4F5808FC14
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 22 Feb 2010 01:40:42 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o1M1egew012012
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 22 Feb 2010 01:40:42 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o1M1egIZ012011;
	Mon, 22 Feb 2010 01:40:42 GMT
	(envelope-from nobody)
Message-Id: <201002220140.o1M1egIZ012011@www.freebsd.org>
Date: Mon, 22 Feb 2010 01:40:42 GMT
From: Gleb Kurtsou <gk@FreeBSD.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [patch] linuxulator: 2 exec bug fixes
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         144194
>Category:       kern
>Synopsis:       [linux] [patch] linuxulator: 2 exec bug fixes
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    netchild
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 22 01:50:02 UTC 2010
>Closed-Date:    Wed Mar 02 10:12:41 UTC 2011
>Last-Modified:  Wed Mar 02 10:12:41 UTC 2011
>Originator:     Gleb Kurtsou
>Release:        
>Organization:
>Environment:
FreeBSD tops 9.0-CURRENT FreeBSD 9.0-CURRENT #17 r203556+e02bf32: Mon Feb 22 03:04:35 EET 2010     root@tops:/usr/obj/freebsd-src/local/sys/TOPS  amd64
>Description:
1. After calling exec() in multithreaded linux program threads are not destroyed and continue running. They get killed after program being executed finishes

2. linux_exit_group doesn't return correct exit code when called from not from group leader. Which happens regularly using sun jvm. I've changed exit1() to allow process_exit event handler to change p->p_xstat, just like NetBSD does.

There's another PR for this bug: kern/141439
But in that PR doesn't kill group leader, it works because sun jvm calls exit_group once again. Expected behavior for exit_group is not to return to userspace.

Submitting it as a single PR because second patch (linux-exit-group-status-code.patch.txt) relays on the first one
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	linux-exec-kill-threads.patch.txt
#	linux-exit-group-status-code.patch.txt
#
echo x - linux-exec-kill-threads.patch.txt
sed 's/^X//' >linux-exec-kill-threads.patch.txt << 'ef694d85587f5b6ee852ea1905df69a1'
Xdiff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
Xindex dc81553..4da2f33 100644
X--- a/sys/compat/linux/linux_emul.c
X+++ b/sys/compat/linux/linux_emul.c
X@@ -257,6 +257,9 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
X 	if (__predict_false(imgp->sysent == &elf_linux_sysvec
X 	    && p->p_sysent != &elf_linux_sysvec))
X 		linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
X+	if (__predict_false(p->p_sysent == &elf_linux_sysvec))
X+		/* Kill threads regerdless of imgp->sysent value */
X+		linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL);
X 	if (__predict_false(imgp->sysent != &elf_linux_sysvec
X 	    && p->p_sysent == &elf_linux_sysvec)) {
X 		struct linux_emuldata *em;
X@@ -334,3 +337,29 @@ linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args
X 	EMUL_UNLOCK(&emul_lock);
X 	return 0;
X }
X+
X+void
X+linux_kill_threads(struct thread *td, int sig)
X+{
X+	struct linux_emuldata *em, *td_em, *tmp_em;
X+	struct proc *sp;
X+
X+	td_em = em_find(td->td_proc, EMUL_DONTLOCK);
X+
X+	KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n"));
X+
X+	EMUL_SHARED_RLOCK(&emul_shared_lock);
X+	LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
X+		if (em->pid == td_em->pid)
X+			continue;
X+
X+		sp = pfind(em->pid);
X+		if ((sp->p_flag & P_WEXIT) == 0)
X+			psignal(sp, sig);
X+		PROC_UNLOCK(sp);
X+#ifdef DEBUG
X+		printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid);
X+#endif
X+	}
X+	EMUL_SHARED_RUNLOCK(&emul_shared_lock);
X+}
Xdiff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
Xindex 8ce27d7..a46a262 100644
X--- a/sys/compat/linux/linux_emul.h
X+++ b/sys/compat/linux/linux_emul.h
X@@ -76,6 +76,7 @@ int	linux_proc_init(struct thread *, pid_t, int);
X void	linux_proc_exit(void *, struct proc *);
X void	linux_schedtail(void *, struct proc *);
X void	linux_proc_exec(void *, struct proc *, struct image_params *);
X+void	linux_kill_threads(struct thread *, int);
X 
X extern struct sx	emul_shared_lock;
X extern struct mtx	emul_lock;
Xdiff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
Xindex d2cf6b6..79e9c2b 100644
X--- a/sys/compat/linux/linux_misc.c
X+++ b/sys/compat/linux/linux_misc.c
X@@ -1695,34 +1695,15 @@ linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
X int
X linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
X {
X-	struct linux_emuldata *em, *td_em, *tmp_em;
X-	struct proc *sp;
X 
X #ifdef DEBUG
X 	if (ldebug(exit_group))
X 		printf(ARGS(exit_group, "%i"), args->error_code);
X #endif
X 
X-	if (linux_use26(td)) {
X-		td_em = em_find(td->td_proc, EMUL_DONTLOCK);
X-
X-		KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
X-
X-		EMUL_SHARED_RLOCK(&emul_shared_lock);
X-		LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
X-			if (em->pid == td_em->pid)
X-				continue;
X-
X-			sp = pfind(em->pid);
X-			psignal(sp, SIGKILL);
X-			PROC_UNLOCK(sp);
X-#ifdef DEBUG
X-			printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
X-#endif
X-		}
X+	if (linux_use26(td))
X+		linux_kill_threads(td, SIGKILL);
X 
X-		EMUL_SHARED_RUNLOCK(&emul_shared_lock);
X-	}
X 	/*
X 	 * XXX: we should send a signal to the parent if
X 	 * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
ef694d85587f5b6ee852ea1905df69a1
echo x - linux-exit-group-status-code.patch.txt
sed 's/^X//' >linux-exit-group-status-code.patch.txt << '844c33058a401cb53a9012cb32028df6'
Xdiff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
Xindex 4da2f33..c8c150b 100644
X--- a/sys/compat/linux/linux_emul.c
X+++ b/sys/compat/linux/linux_emul.c
X@@ -157,6 +157,7 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X 	struct linux_emuldata *em;
X 	int error;
X 	struct thread *td = FIRST_THREAD_IN_PROC(p);
X+	int shared_flags, shared_xstat;
X 	int *child_clear_tid;
X 	struct proc *q, *nq;
X 
X@@ -187,6 +188,8 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X 	}
X 
X 	EMUL_SHARED_WLOCK(&emul_shared_lock);
X+	shared_flags = em->shared->flags;
X+	shared_xstat = em->shared->xstat;
X 	LIST_REMOVE(em, threads);
X 
X 	em->shared->refs--;
X@@ -196,6 +199,12 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X 	} else	
X 		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
X 
X+	if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) {
X+		PROC_LOCK(p);
X+		p->p_xstat = shared_xstat;
X+		PROC_UNLOCK(p);
X+	}
X+
X 	if (child_clear_tid != NULL) {
X 		struct linux_sys_futex_args cup;
X 		int null = 0;
Xdiff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
Xindex a46a262..47a6989 100644
X--- a/sys/compat/linux/linux_emul.h
X+++ b/sys/compat/linux/linux_emul.h
X@@ -31,11 +31,16 @@
X #ifndef _LINUX_EMUL_H_
X #define	_LINUX_EMUL_H_
X 
X+#define EMUL_SHARED_HASXSTAT	0x01
X+
X struct linux_emuldata_shared {
X 	int	refs;
X 	pid_t	group_pid;
X 
X 	LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
X+
X+	int	flags;
X+	int	xstat;
X };
X 
X /*
Xdiff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
Xindex 79e9c2b..c50bf1c 100644
X--- a/sys/compat/linux/linux_misc.c
X+++ b/sys/compat/linux/linux_misc.c
X@@ -1695,14 +1695,22 @@ linux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
X int
X linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
X {
X+	struct linux_emuldata *em;
X 
X #ifdef DEBUG
X 	if (ldebug(exit_group))
X 		printf(ARGS(exit_group, "%i"), args->error_code);
X #endif
X 
X-	if (linux_use26(td))
X-		linux_kill_threads(td, SIGKILL);
X+	em = em_find(td->td_proc, EMUL_DONTLOCK);
X+	if (em->shared->refs > 1) {
X+		EMUL_SHARED_WLOCK(&emul_shared_lock);
X+		em->shared->flags |= EMUL_SHARED_HASXSTAT;
X+		em->shared->xstat = W_EXITCODE(args->error_code, 0);
X+		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
X+		if (linux_use26(td))
X+			linux_kill_threads(td, SIGKILL);
X+	}
X 
X 	/*
X 	 * XXX: we should send a signal to the parent if
Xdiff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
Xindex af00f42..9c27e75 100644
X--- a/sys/kern/kern_exit.c
X+++ b/sys/kern/kern_exit.c
X@@ -204,6 +204,7 @@ exit1(struct thread *td, int rv)
X 	while (p->p_lock > 0)
X 		msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0);
X 
X+	p->p_xstat = rv;	/* Let event handler change exit status */
X 	PROC_UNLOCK(p);
X 	/* Drain the limit callout while we don't have the proc locked */
X 	callout_drain(&p->p_limco);
X@@ -246,6 +247,7 @@ exit1(struct thread *td, int rv)
X 	 * P_PPWAIT is set; we will wakeup the parent below.
X 	 */
X 	PROC_LOCK(p);
X+	rv = p->p_xstat;	/* Event handler could change exit status */
X 	stopprofclock(p);
X 	p->p_flag &= ~(P_TRACED | P_PPWAIT);
X 
X@@ -452,7 +454,6 @@ exit1(struct thread *td, int rv)
X 
X 	/* Save exit status. */
X 	PROC_LOCK(p);
X-	p->p_xstat = rv;
X 	p->p_xthread = td;
X 
X 	/* Tell the prison that we are gone. */
844c33058a401cb53a9012cb32028df6
exit



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-emulation 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Feb 22 17:09:17 UTC 2010 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=144194 
Responsible-Changed-From-To: freebsd-emulation->dchagin 
Responsible-Changed-By: dchagin 
Responsible-Changed-When: Mon Jul 5 21:43:55 UTC 2010 
Responsible-Changed-Why:  
Grab 

http://www.freebsd.org/cgi/query-pr.cgi?pr=144194 
State-Changed-From-To: open->patched 
State-Changed-By: netchild 
State-Changed-When: Mon Nov 22 09:08:39 UTC 2010 
State-Changed-Why:  
Patched in -current. 


Responsible-Changed-From-To: dchagin->netchild 
Responsible-Changed-By: netchild 
Responsible-Changed-When: Mon Nov 22 09:08:39 UTC 2010 
Responsible-Changed-Why:  
Patched in -current. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=144194 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/144194: commit references a PR
Date: Mon, 22 Nov 2010 09:07:08 +0000 (UTC)

 Author: netchild
 Date: Mon Nov 22 09:06:59 2010
 New Revision: 215664
 URL: http://svn.freebsd.org/changeset/base/215664
 
 Log:
   By using the 32-bit Linux version of Sun's Java Development Kit 1.6
   on FreeBSD (amd64), invocations of "javac" (or "java") eventually
   end with the output of "Killed" and exit code 137.
   
   This is caused by:
   1. After calling exec() in multithreaded linux program threads are not
      destroyed and continue running. They get killed after program being
      executed finishes.
   
   2. linux_exit_group doesn't return correct exit code when called not
      from group leader. Which happens regularly using sun jvm.
   
   The submitters fix this in a similar way to how NetBSD handles this.
   
   I took the PRs away from dchagin, who seems to be out of touch of
   this since a while (no response from him).
   
   The patches committed here are from [2], with some little modifications
   from me to the style.
   
   PR:		141439 [1], 144194 [2]
   Submitted by:	Stefan Schmidt <stefan.schmidt@stadtbuch.de>, gk
   Reviewed by:	rdivacky (in april 2010)
   MFC after:	5 days
 
 Modified:
   head/sys/compat/linux/linux_emul.c
   head/sys/compat/linux/linux_emul.h
   head/sys/compat/linux/linux_misc.c
   head/sys/kern/kern_exit.c
 
 Modified: head/sys/compat/linux/linux_emul.c
 ==============================================================================
 --- head/sys/compat/linux/linux_emul.c	Mon Nov 22 09:04:29 2010	(r215663)
 +++ head/sys/compat/linux/linux_emul.c	Mon Nov 22 09:06:59 2010	(r215664)
 @@ -155,7 +155,7 @@ void
  linux_proc_exit(void *arg __unused, struct proc *p)
  {
  	struct linux_emuldata *em;
 -	int error;
 +	int error, shared_flags, shared_xstat;
  	struct thread *td = FIRST_THREAD_IN_PROC(p);
  	int *child_clear_tid;
  	struct proc *q, *nq;
 @@ -187,6 +187,8 @@ linux_proc_exit(void *arg __unused, stru
  	}
  
  	EMUL_SHARED_WLOCK(&emul_shared_lock);
 +	shared_flags = em->shared->flags;
 +	shared_xstat = em->shared->xstat;
  	LIST_REMOVE(em, threads);
  
  	em->shared->refs--;
 @@ -196,6 +198,12 @@ linux_proc_exit(void *arg __unused, stru
  	} else	
  		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
  
 +	if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) {
 +		PROC_LOCK(p);
 +		p->p_xstat = shared_xstat;
 +		PROC_UNLOCK(p);
 +	}
 +
  	if (child_clear_tid != NULL) {
  		struct linux_sys_futex_args cup;
  		int null = 0;
 @@ -257,6 +265,9 @@ linux_proc_exec(void *arg __unused, stru
  	if (__predict_false(imgp->sysent == &elf_linux_sysvec
  	    && p->p_sysent != &elf_linux_sysvec))
  		linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
 +	if (__predict_false(p->p_sysent == &elf_linux_sysvec))
 +		/* Kill threads regardless of imgp->sysent value */
 +		linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL);
  	if (__predict_false(imgp->sysent != &elf_linux_sysvec
  	    && p->p_sysent == &elf_linux_sysvec)) {
  		struct linux_emuldata *em;
 @@ -334,3 +345,29 @@ linux_set_tid_address(struct thread *td,
  	EMUL_UNLOCK(&emul_lock);
  	return 0;
  }
 +
 +void
 +linux_kill_threads(struct thread *td, int sig)
 +{
 +	struct linux_emuldata *em, *td_em, *tmp_em;
 +	struct proc *sp;
 +
 +	td_em = em_find(td->td_proc, EMUL_DONTLOCK);
 +
 +	KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n"));
 +
 +	EMUL_SHARED_RLOCK(&emul_shared_lock);
 +	LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
 +		if (em->pid == td_em->pid)
 +			continue;
 +
 +		sp = pfind(em->pid);
 +		if ((sp->p_flag & P_WEXIT) == 0)
 +			psignal(sp, sig);
 +		PROC_UNLOCK(sp);
 +#ifdef DEBUG
 +		printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid);
 +#endif
 +	}
 +	EMUL_SHARED_RUNLOCK(&emul_shared_lock);
 +}
 
 Modified: head/sys/compat/linux/linux_emul.h
 ==============================================================================
 --- head/sys/compat/linux/linux_emul.h	Mon Nov 22 09:04:29 2010	(r215663)
 +++ head/sys/compat/linux/linux_emul.h	Mon Nov 22 09:06:59 2010	(r215664)
 @@ -31,8 +31,12 @@
  #ifndef _LINUX_EMUL_H_
  #define	_LINUX_EMUL_H_
  
 +#define EMUL_SHARED_HASXSTAT	0x01
 +
  struct linux_emuldata_shared {
  	int	refs;
 +	int	flags;
 +	int	xstat;
  	pid_t	group_pid;
  
  	LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
 @@ -76,6 +80,7 @@ int	linux_proc_init(struct thread *, pid
  void	linux_proc_exit(void *, struct proc *);
  void	linux_schedtail(void *, struct proc *);
  void	linux_proc_exec(void *, struct proc *, struct image_params *);
 +void	linux_kill_threads(struct thread *, int);
  
  extern struct sx	emul_shared_lock;
  extern struct mtx	emul_lock;
 
 Modified: head/sys/compat/linux/linux_misc.c
 ==============================================================================
 --- head/sys/compat/linux/linux_misc.c	Mon Nov 22 09:04:29 2010	(r215663)
 +++ head/sys/compat/linux/linux_misc.c	Mon Nov 22 09:06:59 2010	(r215664)
 @@ -1695,34 +1695,23 @@ linux_setdomainname(struct thread *td, s
  int
  linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
  {
 -	struct linux_emuldata *em, *td_em, *tmp_em;
 -	struct proc *sp;
 +	struct linux_emuldata *em;
  
  #ifdef DEBUG
  	if (ldebug(exit_group))
  		printf(ARGS(exit_group, "%i"), args->error_code);
  #endif
  
 -	if (linux_use26(td)) {
 -		td_em = em_find(td->td_proc, EMUL_DONTLOCK);
 -
 -		KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
 -
 -		EMUL_SHARED_RLOCK(&emul_shared_lock);
 -		LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
 -			if (em->pid == td_em->pid)
 -				continue;
 -
 -			sp = pfind(em->pid);
 -			psignal(sp, SIGKILL);
 -			PROC_UNLOCK(sp);
 -#ifdef DEBUG
 -			printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
 -#endif
 -		}
 -
 -		EMUL_SHARED_RUNLOCK(&emul_shared_lock);
 +	em = em_find(td->td_proc, EMUL_DONTLOCK);
 +	if (em->shared->refs > 1) {
 +		EMUL_SHARED_WLOCK(&emul_shared_lock);
 +		em->shared->flags |= EMUL_SHARED_HASXSTAT;
 +		em->shared->xstat = W_EXITCODE(args->error_code, 0);
 +		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
 +		if (linux_use26(td))
 +			linux_kill_threads(td, SIGKILL);
  	}
 +
  	/*
  	 * XXX: we should send a signal to the parent if
  	 * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
 
 Modified: head/sys/kern/kern_exit.c
 ==============================================================================
 --- head/sys/kern/kern_exit.c	Mon Nov 22 09:04:29 2010	(r215663)
 +++ head/sys/kern/kern_exit.c	Mon Nov 22 09:06:59 2010	(r215664)
 @@ -200,6 +200,7 @@ exit1(struct thread *td, int rv)
  	while (p->p_lock > 0)
  		msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0);
  
 +	p->p_xstat = rv;	/* Let event handler change exit status */
  	PROC_UNLOCK(p);
  	/* Drain the limit callout while we don't have the proc locked */
  	callout_drain(&p->p_limco);
 @@ -242,6 +243,7 @@ exit1(struct thread *td, int rv)
  	 * P_PPWAIT is set; we will wakeup the parent below.
  	 */
  	PROC_LOCK(p);
 +	rv = p->p_xstat;	/* Event handler could change exit status */
  	stopprofclock(p);
  	p->p_flag &= ~(P_TRACED | P_PPWAIT);
  
 @@ -424,7 +426,6 @@ exit1(struct thread *td, int rv)
  
  	/* Save exit status. */
  	PROC_LOCK(p);
 -	p->p_xstat = rv;
  	p->p_xthread = td;
  
  	/* Tell the prison that we are gone. */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/144194: commit references a PR
Date: Wed,  2 Mar 2011 09:53:33 +0000 (UTC)

 Author: netchild
 Date: Wed Mar  2 09:53:13 2011
 New Revision: 219173
 URL: http://svn.freebsd.org/changeset/base/219173
 
 Log:
   MFC r215664:
     By using the 32-bit Linux version of Sun's Java Development Kit 1.6
     on FreeBSD (amd64), invocations of "javac" (or "java") eventually
     end with the output of "Killed" and exit code 137.
   
     This is caused by:
     1. After calling exec() in multithreaded linux program threads are not
        destroyed and continue running. They get killed after program being
        executed finishes.
   
     2. linux_exit_group doesn't return correct exit code when called not
        from group leader. Which happens regularly using sun jvm.
   
     The submitters fix this in a similar way to how NetBSD handles this.
   
     I took the PRs away from dchagin, who seems to be out of touch of
     this since a while (no response from him).
   
     The patches committed here are from [2], with some little modifications
     from me to the style.
   
     PR:                141439 [1], 144194 [2]
     Submitted by:        Stefan Schmidt <stefan.schmidt@stadtbuch.de>, gk
     Reviewed by:        rdivacky (in april 2010)
   
   MFC r215675:
     Do not take the process lock. The assignment to u_short inside the
     properly aligned structure is atomic on all supported architectures, and
     the thread that should see side-effect of assignment is the same thread
     that does assignment.
   
     Use a more appropriate conditional to detect the linux ABI.
   
     Suggested by:        kib
 
 Modified:
   stable/8/sys/compat/linux/linux_emul.c
   stable/8/sys/compat/linux/linux_emul.h
   stable/8/sys/compat/linux/linux_misc.c
   stable/8/sys/kern/kern_exit.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/compat/linux/linux_emul.c
 ==============================================================================
 --- stable/8/sys/compat/linux/linux_emul.c	Wed Mar  2 06:24:46 2011	(r219172)
 +++ stable/8/sys/compat/linux/linux_emul.c	Wed Mar  2 09:53:13 2011	(r219173)
 @@ -155,7 +155,7 @@ void
  linux_proc_exit(void *arg __unused, struct proc *p)
  {
  	struct linux_emuldata *em;
 -	int error;
 +	int error, shared_flags, shared_xstat;
  	struct thread *td = FIRST_THREAD_IN_PROC(p);
  	int *child_clear_tid;
  	struct proc *q, *nq;
 @@ -187,6 +187,8 @@ linux_proc_exit(void *arg __unused, stru
  	}
  
  	EMUL_SHARED_WLOCK(&emul_shared_lock);
 +	shared_flags = em->shared->flags;
 +	shared_xstat = em->shared->xstat;
  	LIST_REMOVE(em, threads);
  
  	em->shared->refs--;
 @@ -196,6 +198,9 @@ linux_proc_exit(void *arg __unused, stru
  	} else	
  		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
  
 +	if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0)
 +		p->p_xstat = shared_xstat;
 +
  	if (child_clear_tid != NULL) {
  		struct linux_sys_futex_args cup;
  		int null = 0;
 @@ -257,6 +262,10 @@ linux_proc_exec(void *arg __unused, stru
  	if (__predict_false(imgp->sysent == &elf_linux_sysvec
  	    && p->p_sysent != &elf_linux_sysvec))
  		linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
 +	if (__predict_false((p->p_sysent->sv_flags & SV_ABI_MASK) ==
 +	    SV_ABI_LINUX))
 +		/* Kill threads regardless of imgp->sysent value */
 +		linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL);
  	if (__predict_false(imgp->sysent != &elf_linux_sysvec
  	    && p->p_sysent == &elf_linux_sysvec)) {
  		struct linux_emuldata *em;
 @@ -334,3 +343,29 @@ linux_set_tid_address(struct thread *td,
  	EMUL_UNLOCK(&emul_lock);
  	return 0;
  }
 +
 +void
 +linux_kill_threads(struct thread *td, int sig)
 +{
 +	struct linux_emuldata *em, *td_em, *tmp_em;
 +	struct proc *sp;
 +
 +	td_em = em_find(td->td_proc, EMUL_DONTLOCK);
 +
 +	KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n"));
 +
 +	EMUL_SHARED_RLOCK(&emul_shared_lock);
 +	LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
 +		if (em->pid == td_em->pid)
 +			continue;
 +
 +		sp = pfind(em->pid);
 +		if ((sp->p_flag & P_WEXIT) == 0)
 +			psignal(sp, sig);
 +		PROC_UNLOCK(sp);
 +#ifdef DEBUG
 +		printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid);
 +#endif
 +	}
 +	EMUL_SHARED_RUNLOCK(&emul_shared_lock);
 +}
 
 Modified: stable/8/sys/compat/linux/linux_emul.h
 ==============================================================================
 --- stable/8/sys/compat/linux/linux_emul.h	Wed Mar  2 06:24:46 2011	(r219172)
 +++ stable/8/sys/compat/linux/linux_emul.h	Wed Mar  2 09:53:13 2011	(r219173)
 @@ -31,8 +31,12 @@
  #ifndef _LINUX_EMUL_H_
  #define	_LINUX_EMUL_H_
  
 +#define EMUL_SHARED_HASXSTAT	0x01
 +
  struct linux_emuldata_shared {
  	int	refs;
 +	int	flags;
 +	int	xstat;
  	pid_t	group_pid;
  
  	LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
 @@ -76,6 +80,7 @@ int	linux_proc_init(struct thread *, pid
  void	linux_proc_exit(void *, struct proc *);
  void	linux_schedtail(void *, struct proc *);
  void	linux_proc_exec(void *, struct proc *, struct image_params *);
 +void	linux_kill_threads(struct thread *, int);
  
  extern struct sx	emul_shared_lock;
  extern struct mtx	emul_lock;
 
 Modified: stable/8/sys/compat/linux/linux_misc.c
 ==============================================================================
 --- stable/8/sys/compat/linux/linux_misc.c	Wed Mar  2 06:24:46 2011	(r219172)
 +++ stable/8/sys/compat/linux/linux_misc.c	Wed Mar  2 09:53:13 2011	(r219173)
 @@ -1655,34 +1655,23 @@ linux_setdomainname(struct thread *td, s
  int
  linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
  {
 -	struct linux_emuldata *em, *td_em, *tmp_em;
 -	struct proc *sp;
 +	struct linux_emuldata *em;
  
  #ifdef DEBUG
  	if (ldebug(exit_group))
  		printf(ARGS(exit_group, "%i"), args->error_code);
  #endif
  
 -	if (linux_use26(td)) {
 -		td_em = em_find(td->td_proc, EMUL_DONTLOCK);
 -
 -		KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
 -
 -		EMUL_SHARED_RLOCK(&emul_shared_lock);
 -		LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
 -			if (em->pid == td_em->pid)
 -				continue;
 -
 -			sp = pfind(em->pid);
 -			psignal(sp, SIGKILL);
 -			PROC_UNLOCK(sp);
 -#ifdef DEBUG
 -			printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
 -#endif
 -		}
 -
 -		EMUL_SHARED_RUNLOCK(&emul_shared_lock);
 +	em = em_find(td->td_proc, EMUL_DONTLOCK);
 +	if (em->shared->refs > 1) {
 +		EMUL_SHARED_WLOCK(&emul_shared_lock);
 +		em->shared->flags |= EMUL_SHARED_HASXSTAT;
 +		em->shared->xstat = W_EXITCODE(args->error_code, 0);
 +		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
 +		if (linux_use26(td))
 +			linux_kill_threads(td, SIGKILL);
  	}
 +
  	/*
  	 * XXX: we should send a signal to the parent if
  	 * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
 
 Modified: stable/8/sys/kern/kern_exit.c
 ==============================================================================
 --- stable/8/sys/kern/kern_exit.c	Wed Mar  2 06:24:46 2011	(r219172)
 +++ stable/8/sys/kern/kern_exit.c	Wed Mar  2 09:53:13 2011	(r219173)
 @@ -200,6 +200,7 @@ exit1(struct thread *td, int rv)
  	while (p->p_lock > 0)
  		msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0);
  
 +	p->p_xstat = rv;	/* Let event handler change exit status */
  	PROC_UNLOCK(p);
  	/* Drain the limit callout while we don't have the proc locked */
  	callout_drain(&p->p_limco);
 @@ -242,6 +243,7 @@ exit1(struct thread *td, int rv)
  	 * P_PPWAIT is set; we will wakeup the parent below.
  	 */
  	PROC_LOCK(p);
 +	rv = p->p_xstat;	/* Event handler could change exit status */
  	stopprofclock(p);
  	p->p_flag &= ~(P_TRACED | P_PPWAIT);
  
 @@ -421,7 +423,6 @@ exit1(struct thread *td, int rv)
  
  	/* Save exit status. */
  	PROC_LOCK(p);
 -	p->p_xstat = rv;
  	p->p_xthread = td;
  
  	/* Tell the prison that we are gone. */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: netchild 
State-Changed-When: Wed Mar 2 10:12:25 UTC 2011 
State-Changed-Why:  
The fix is now in 8-stable. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=144194 
>Unformatted:
