From nobody@FreeBSD.org  Mon Mar  5 19:21:03 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 9B91E16A403
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  5 Mar 2007 19:21:03 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 8C18A13C461
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  5 Mar 2007 19:21:03 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l25JL3wP015640
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 5 Mar 2007 19:21:03 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l25JL3ae015639;
	Mon, 5 Mar 2007 19:21:03 GMT
	(envelope-from nobody)
Message-Id: <200703051921.l25JL3ae015639@www.freebsd.org>
Date: Mon, 5 Mar 2007 19:21:03 GMT
From: "Jukka A. Ukkonen"<jau@iki.fi>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Compatibility: FreeBSD has been missing WNOWAIT flag for wait*() calls
X-Send-Pr-Version: www-3.0

>Number:         109946
>Category:       kern
>Synopsis:       [kernel] [patch] Compatibility: FreeBSD has been missing WNOWAIT flag for wait*() calls
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Mar 05 19:30:01 GMT 2007
>Closed-Date:    Sat Jan 26 08:55:21 UTC 2008
>Last-Modified:  Sat Jan 26 08:55:21 UTC 2008
>Originator:     Jukka A. Ukkonen
>Release:        6.2-STABLE
>Organization:
private person
>Environment:
FreeBSD mjolnir 6.2-STABLE FreeBSD 6.2-STABLE #1: Fri Mar  2 08:08:33 EET 2007     root@mjolnir:/usr/obj/usr/src/sys/Mjolnir  i386
>Description:
Were there a problem class compatibility errors, I would have classified this
as belonging to such a category.

SUS required WNOWAIT flag for wait*() calls already long ago.
Anyhow FreeBSD has not introduced one, though, implementing it is relatively
easy. Simply do everything as with a normal wait*() call cutting the syscall
short just before actually releasing the proc struct belonging to the zombie.

The availability of the WNOWAIT flag allows one to wait for any child from
within a thread which has no idea of child processes created by other threads.
With WNOWAIT set one can first poll for a child to see whether the pid is
one that is known to the calling thread.
If the child is known, the code can then call waitpid() or wait4() with
the pid of the found process and without WNOWAIT to reap its process struct.
If the child is unknown, the code can simply give up waiting and let another
thread, take its turn waiting for the child.
This allows the thread that created the child process to eventually find the
child and collect its exit status.

This is especially useful when implementing a threaded library which might
fork child processes which are otherwise completely unknown in the program,
but the library still needs to know when the child process has terminated.
A library OTOH cannot expect to know anything about the programs in which it
is going to be used.

>How-To-Repeat:
See /usr/include/sys/wait.h - there is no WNOWAIT.

>Fix:
Apply the attached patch.
And, please, MFC it before 7.x goes out.
Relatively straight forward things like this
really do not deserve to linger in the HEAD
until the next major release.


Patch attached with submission follows:

--- src/sys/sys/wait.h.orig	Mon Mar  5 20:11:30 2007
+++ src/sys/sys/wait.h	Mon Mar  5 20:40:32 2007
@@ -78,7 +78,9 @@
  */
 #define	WNOHANG		1	/* Don't hang in wait. */
 #define	WUNTRACED	2	/* Tell about stopped, untraced children. */
+#define	WSTOPPED	WUNTRACED   /* SUS compatibility */
 #define	WCONTINUED	4	/* Report a job control continued process. */
+#define	WNOWAIT		8	/* Poll only. Don't delete the proc entry. */
 
 #if __BSD_VISIBLE
 #define	WLINUXCLONE 0x80000000	/* Wait for kthread spawned from linux_clone. */
--- src/sys/kern/kern_exit.c.orig	Mon Mar  5 20:17:19 2007
+++ src/sys/kern/kern_exit.c	Mon Mar  5 20:34:10 2007
@@ -590,7 +590,7 @@
 		pid = -q->p_pgid;
 		PROC_UNLOCK(q);
 	}
-	if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE))
+	if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WNOWAIT|WLINUXCLONE))
 		return (EINVAL);
 loop:
 	if (q->p_flag & P_STATCHILD) {
@@ -663,6 +663,26 @@
 				psignal(t, SIGCHLD);
 				wakeup(t);
 				PROC_UNLOCK(t);
+				sx_xunlock(&proctree_lock);
+				return (0);
+			}
+
+			if (! (options & WNOWAIT)) {
+				/*
+				 *  SUS compatibility.
+				 *
+				 *  We poll only returning the status.
+				 *  We do not wish to release the proc
+				 *  struct just yet.
+				 *  ==> If another thread created this
+				 *  process, it is sometimes better to
+				 *  leave this one as is for now and let
+				 *  the other thread reap the remnants
+				 *  of the child instead of automatically
+				 *  destroying the proc entry and making
+				 *  it impossible for the other thread to
+				 *  wait for its own child process.
+				 */
 				sx_xunlock(&proctree_lock);
 				return (0);
 			}

>Release-Note:
>Audit-Trail:

From: "Jukka A. Ukkonen" <jau@oxit.fi>
To: bug-followup@FreeBSD.org, jau@iki.fi
Cc:  
Subject: Re: kern/109946: [kernel] [patch] Compatibility: FreeBSD has been
 missing WNOWAIT flag for wait*() calls://undefined
Date: Wed, 07 Mar 2007 10:06:28 +0200

 This is a MIME-formatted message.  If you see this text it means that your
 E-mail software does not support MIME-formatted messages.
 
 --=_singer-1914-1173254800-0001-2
 Content-Type: text/plain; charset=iso-8859-15
 Content-Transfer-Encoding: 7bit
 
 
 	Oops!
 
 	Reverse the if-condition to read
 
 		if (options & WNOWAIT) {
 
 	The version I attached seems to be an older diff
 	which I - obviously - cannot be using myself, because
 	doing the the wrong way would quickly end up never
 	cleaning the zombies away from the proc table.
 
 	I originally intended to do the test the other way
 	around enveloping the whole proc entry cleanup in
 	an if block, but then I decided to favour readability
 	and to cut the whole thing short by unlocking and
 	returning early.
 	The bad news is I made an intermediate diff for myself
 	while I had already added shortcut return but had not
 	yet reversed the if-test. Though I made another diff
 	after changing the if-test direction as well, I still
 	somehow managed to attach the wrong one to the PR. Sigh!
 
 	Additionally it might make sense to do the shortcut
 	return already before the "ptrace attach" test/block
 	but after the PROC_UNLOCK(p); line when rusage has
 	been filled in.
 	So, I attach a modified patch which in addition to
 	showing the proper WNOWAIT test also moves the WNOWAIT
 	test before the ptrace attach test.
 
 	Cheers,
 		// jau
 
 --=_singer-1914-1173254800-0001-2
 Content-Type: text/x-patch; name="wait-WNOWAIT.patch"; charset=iso-8859-1
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="wait-WNOWAIT.patch"
 
 --- src/sys/sys/wait.h.orig	Mon Mar  5 20:11:30 2007
 +++ src/sys/sys/wait.h	Mon Mar  5 20:40:32 2007
 @@ -78,7 +78,9 @@
   */
  #define	WNOHANG		1	/* Don't hang in wait. */
  #define	WUNTRACED	2	/* Tell about stopped, untraced children. */
 +#define	WSTOPPED	WUNTRACED   /* SUS compatibility */
  #define	WCONTINUED	4	/* Report a job control continued process. */
 +#define	WNOWAIT		8	/* Poll only. Don't delete the proc entry. */
  
  #if __BSD_VISIBLE
  #define	WLINUXCLONE 0x80000000	/* Wait for kthread spawned from linux_clone. */
 --- src/sys/kern/kern_exit.c.orig	Mon Mar  5 20:17:19 2007
 +++ src/sys/kern/kern_exit.c	Wed Mar  7 09:46:01 2007
 @@ -590,7 +590,7 @@
  		pid = -q->p_pgid;
  		PROC_UNLOCK(q);
  	}
 -	if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WLINUXCLONE))
 +	if (options &~ (WUNTRACED|WNOHANG|WCONTINUED|WNOWAIT|WLINUXCLONE))
  		return (EINVAL);
  loop:
  	if (q->p_flag & P_STATCHILD) {
 @@ -650,11 +650,32 @@
  				calcru(p, &rusage->ru_utime, &rusage->ru_stime);
  			}
  
 +			PROC_UNLOCK(p);
 +
 +			if (options & WNOWAIT) {
 +				/*
 +				 *  SUS compatibility.
 +				 *
 +				 *  We poll only returning the status.
 +				 *  We do not wish to release the proc
 +				 *  struct just yet.
 +				 *  ==> If another thread created this
 +				 *  process, it is sometimes better to
 +				 *  leave this one as is for now and let
 +				 *  the other thread reap the remnants
 +				 *  of the child instead of automatically
 +				 *  destroying the proc entry and making
 +				 *  it impossible for the other thread to
 +				 *  wait for its own child process.
 +				 */
 +				sx_xunlock(&proctree_lock);
 +				return (0);
 +			}
 +
  			/*
  			 * If we got the child via a ptrace 'attach',
  			 * we need to give it back to the old parent.
  			 */
 -			PROC_UNLOCK(p);
  			if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) {
  				PROC_LOCK(p);
  				p->p_oppid = 0;
 
 --=_singer-1914-1173254800-0001-2--
State-Changed-From-To: open->closed 
State-Changed-By: linimon 
State-Changed-When: Sat Jan 26 08:54:35 UTC 2008 
State-Changed-Why:  
Superseded by standards/116221. 

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