kern/109946: Compatibility: FreeBSD has been missing WNOWAIT flag for wait*() calls

Jukka A. Ukkonen jau at iki.fi
Mon Mar 5 19:30:03 UTC 2007


>Number:         109946
>Category:       kern
>Synopsis:       Compatibility: FreeBSD has been missing WNOWAIT flag for wait*() calls
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Mar 05 19:30:01 GMT 2007
>Closed-Date:
>Last-Modified:
>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 at 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:
>Unformatted:


More information about the freebsd-bugs mailing list