From owner-freebsd-arch Sun Dec 8 9:19:16 2002 Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4DEFA37B401 for ; Sun, 8 Dec 2002 09:19:12 -0800 (PST) Received: from heechee.tobez.org (heechee.tobez.org [213.237.10.254]) by mx1.FreeBSD.org (Postfix) with ESMTP id C19DD43ED8 for ; Sun, 8 Dec 2002 09:19:05 -0800 (PST) (envelope-from tobez@tobez.org) Received: by heechee.tobez.org (Postfix, from userid 1001) id 3FCADA922; Sun, 8 Dec 2002 18:18:47 +0100 (CET) Date: Sun, 8 Dec 2002 18:18:47 +0100 From: Anton Berezin To: alan Cc: arch@FreeBSD.org Subject: SA_NOCLDWAIT and waitXXX strangeties (Was: Re: ports/45972: Perl system() calls will hang if the process has other forked children.) Message-ID: <20021208171847.GE35282@heechee.tobez.org> References: <200212041830.gB4IU2Mi007843@freefall.freebsd.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200212041830.gB4IU2Mi007843@freefall.freebsd.org> User-Agent: Mutt/1.5.1i Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG Alan, On Wed, Dec 04, 2002 at 10:30:02AM -0800, alan wrote: > The problem is, when you set SA_NOCLDWAIT, subsequent calls to wait() > (or wait4()) wait for All child processes to exit, not just the > process ID that wait() is called on. Since Perl's system() calls > wait4() on its recently forked child, the system() call doesn't return > until All of the perl process's children exit. This doesn't seem like > particularly desirable behavior, but it is documented in FreeBSD's > sigaction man page: > > SA_NOCLDWAIT If this bit is set when calling sigaction() for the > SIGCHLD signal, the system will not create zombie > processes when children of the calling process > exit. If the calling process subsequently issues a > wait(2) (or equivalent), it blocks until all of the > calling process's child processes terminate, and > then returns a value of -1 with errno set to > ECHILD. I don't like this behavior. Personally, I would like to think that it should not wait for all children if any of the waitXXX() explicitly specifies a pid to wait for. Obviously, there is a difference between how I would like to interpret the docs and the reality. :-/ So in this particular instance it looks to me like a bug (or at least, a gray area) in FreeBSD, which should be discussed, hence the copy to arch-. (The complete description of the problem, for the benefits of arch- folks, can be found here: http://www.freebsd.org/cgi/query-pr.cgi?pr=45972) > The quick fix is to stop using SA_NOCLDWAIT when it ignores SIGCHLD. > This may create unwanted zombie processes, though. Why would it? IIRC, the BSD semantics for SIG_IGN for SIGCHLD is exactly `do not create zombies' semantics, so the combination of a perl program setting SIG_IGN for SIGCHLD and perl itself setting SA_NOCLDWAIT at the same time looks like an attempt to do the same thing twice. But, regardless of whether this behavior of perl is a bug or not, I would still like to hear our signal handling experts on the issue. > The better fix is probably not to wait() at all if SIGCHLD is > currently being ignored with SA_NOCLDWAIT. One has to waitXXX() in order to implement a system(3)-like call. FreeBSD's own system(3) does wait4(), just like perl's system() does. > Below is C code which compiles and runs on FreeBSD using gcc, and > which demonstrates the difference in behavior when SA_NOCLDWAIT is > used and is not used. I would like confirmation that this Is in fact > the expected behavior of FreeBSD, and that in this case Perl is making > incorrect assumptions about how FreeBSD will behave. Exactly. Once you have identified the problem (thanks!), it is easy to fix perl. The question is that maybe FreeBSD also need fixing. > Thanks, > > Alan Ferrency > pair Networks > alan@pair.com > > > > #include > #include > #include > #include > #include > > int main (void) { > int chld, stat; > struct sigaction act; > > act.sa_handler = SIG_IGN; > sigemptyset(&act.sa_mask); > act.sa_flags = 0; > > sigaction(SIGCHLD, &act, 0); > printf("fork 1: no one will wait for me.\n"); > if (!fork()) { > sleep(120); > printf(" Fork 1 exiting\n"); > exit(0); > } > > printf("fork 2\n"); > if (chld = fork()) { > printf(" Parent: waiting for fork 2 to exit\n"); > wait4(chld, &stat, 0, 0) == -1 && errno == EINTR; > } else { /* child process */ > sleep(1); > printf(" fork 2 exiting\n"); > exit(0); > } > printf(" Parent done with fork 2.\n"); > > > act.sa_handler = SIG_IGN; > sigemptyset(&act.sa_mask); > act.sa_flags = SA_NOCLDWAIT; > sigaction(SIGCHLD, &act, 0); > > printf("fork 3\n"); > if (chld = fork()) { > printf(" Parent: waiting for fork 3 to exit\n"); > wait4(chld, &stat, 0, 0) == -1 && errno == EINTR; > } else { /* child process */ > sleep(1); > printf(" Fork 3 exiting\n"); > exit(0); > } > printf(" Parent done with fork 3.\n"); > > printf("done\n"); > > return 0; > } Cheers, =Anton. -- | Anton Berezin | FreeBSD: The power to serve | | catpipe Systems ApS _ _ |_ | http://www.FreeBSD.org | | tobez@catpipe.net (_(_|| | tobez@FreeBSD.org | | +45 7021 0050 | Private: tobez@tobez.org | To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message