From owner-freebsd-bugs@FreeBSD.ORG Mon Apr 6 15:00:09 2009 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D279A1065754 for ; Mon, 6 Apr 2009 15:00:09 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id BE07C8FC08 for ; Mon, 6 Apr 2009 15:00:09 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n36F09UD077322 for ; Mon, 6 Apr 2009 15:00:09 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n36F09Dc077321; Mon, 6 Apr 2009 15:00:09 GMT (envelope-from gnats) Date: Mon, 6 Apr 2009 15:00:09 GMT Message-Id: <200904061500.n36F09Dc077321@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Alan Ferrency Cc: Subject: Re: bin/108390: [libc] [patch] wait4() erroneously waits for all children when SIGCHLD is SIG_IGN [regression] X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Alan Ferrency List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 06 Apr 2009 15:00:11 -0000 The following reply was made to PR bin/108390; it has been noted by GNATS. From: Alan Ferrency To: Jilles Tjoelker Cc: bug-followup@FreeBSD.org Subject: Re: bin/108390: [libc] [patch] wait4() erroneously waits for all children when SIGCHLD is SIG_IGN [regression] Date: Mon, 6 Apr 2009 10:24:37 -0400 (EDT) Hi, I realized after submitting this bug fix, that the original patch I removed was intended to be a feature and not a bug. We don't like it, but we've worked around it by using wait() in our SIGCHLD handlers instead of SIG_IGN. Our main problem was in Perl, where there is no longer a straightfoward way to avoid zombies and ignore child process exit codes on FreeBSD. Perl and other similar languages provide portable interfaces to things like fork(), wait(), and system(), but don't provide interfaces to native things like kqueue() and rfork(). In this case, we set $SIG{CHLD} to IGNORE, forked, and then called system(). Perl's system() internally uses wait4pid() to synchronously wait for the system() child processes to end, and to collect their status. But on FreeBSD, this hangs until all child processes are finished, not just the system() call. The Perl people insisted this wasn't their problem, they're just mimicking what the native OS does; but now that I see your explanation, I'm not sure I agree with them anymore. One way or another, there's a functionality mismatch here between FreeBSD and Perl which makes $SIG{CHLD} = IGNORE basically useless. Our basic goal was to ignore the status of most child processes, while still retrieving the exit code from a system() call. It seems that SIG_IGN is not the solution for this, in FreeBSD. Overall, this change puts a huge damper on cross-platform portability. But, just as with SA_NOCLDWAIT, it seems that FreeBSD is supporting features that Linux isn't (but should be), so I guess I just need to wait for them to catch up. Thanks for the followup, I'm sorry to submit a report for not-a-bug. Alan Ferrency pair Networks, Inc. On Sun, 5 Apr 2009, Jilles Tjoelker wrote: > POSIX seems to agree with what FreeBSD does. The change you refer to > just makes ignoring SIGCHLD do the same as SA_NOCLDWAIT, i.e. avoid > creating zombies from terminated child processes. > > Fact of the matter is that signal(SIGCHLD, SIG_IGN) and SA_NOCLDWAIT are > pretty useless, even if this were to be "fixed". If the child process > terminates while you are not executing waitpid(), the status is just > lost and it is even possible for a new child process to get the same > pid. Also think of functions like system(3), wordexp(3) and grantpt(3) > (the latter only on freebsd 5, 6 and 7), which create child processes to > do some of their work. > > If you want to check if the pid still exists (beware of pid reuse), use > kill(pid, 0); to wait (not portably and with the same caveat), use > kqueue/kevent with EVFILT_PROC. > > Additionally, if your code does not have to be portable, you can use > rfork(2) with the RFNOWAIT flag to avoid zombie creation for specific > child processes only. If that's not possible, consider forking twice and > waiting for the first child immediately or doing execl("/bin/sh", "sh", > "...&", (const char *)NULL); in a child process. > > -- > Jilles Tjoelker >