[net.unix-wizards] New? idea

chris@umcp-cs.UUCP (01/16/84)

Something that network servers often do is

	while ((netfd = netopen ()) >= 0) {
		if ((pid = fork ()) == 0) {
			if (fork ())
				exit (0);
			workhorse ();
			exit (0);
		}
		close (netfd);
	}

The purpose of the double-fork is to "disown" the actual worker and
let the server continue to accept network connections.  Without the
"disownment", when the "workhorse" finishes and exit()s, it hangs around
forever taking up a process slot, just so that it can return its status
to its parent.  But the server doesn't care, ergo the double-fork-be-
inherited-by-init trick.

So, my suggestion is a "disown" system call, to allow parents to give
up their children so that on exit they will vanish without a trace.
Does anyone know why this should not be implemented (other than because
you can do it without this)?  Alternatively, does anyone have better
ideas?
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris.umcp-cs@CSNet-Relay

guy@rlgvax.UUCP (Guy Harris) (01/16/84)

If it shouldn't be implemented, USG UNIX is in trouble - from SIGNAL(2),
UNIX 3.0 User's Manual:

	...SIGCLD	18 (not reset when caught)

	...SIG_IGN - ignore signal
		The signal is to be ignored.  Also, if 'sig' is SIGCLD,
		the calling process's (shouldn't that be process'? -gh)
		child processes will not create zombie processes when
		they terminate; see exit(2).

So

	signal(SIGCLD, SIG_IGN)

will disown all child processes that exit while SIGCLD is being ignored.
The signal SIGCLD is delivered whenever a child process exits; this is
sort of like the SIGCHLD in the Berkeley job control code, which is delivered
whenever the state of a child process child changes - this includes exits,
and also includes stopping, etc..

I remember reading some code, I think in the C shell, which does

	signal(SIGCHLD, SIG_IGN)

From what I could see, the kernel does the same thing whether the action
for SIGCHLD is SIG_DFL or SIG_IGN; i.e., the default action for SIGCHLD
is to do nothing.  The same is the case with the USG SIGCLD (i.e., if you
don't catch it, it's as if you ignored it except that zombies are created).
Is there any difference between 4.xBSD's handling of SIGCHLD if the action
is SIG_IGN or SIG_DFL?  And, if not, and if all cases where SIGCHLD was
ignored the code were changed to reset it to SIG_DFL, could the SIGCLD
and SIGCHLD signals be combined?  (The S3 manual says that SIGCLD is
included only for compatibility with "other versions of UNIX", and is not
guaranteed to behave the same in future releases of UNIX; it's "use in new
programs is strongly discouraged."  However, that signal still appears in
System V, albeit with the same caveat, and the S5 "init" uses it.)

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

jsq@ut-sally.UUCP (John Quarterman) (01/16/84)

x
	From: chris@umcp-cs.UUCP
	Subject: New? idea
	Message-ID: <4771@umcp-cs.UUCP>
	Date: Sun, 15-Jan-84 17:43:17 CST
	
	Something that network servers often do is

		while ((netfd = netopen ()) >= 0) {
			if ((pid = fork ()) == 0) {
				if (fork ())
					exit (0);
				workhorse ();
				exit (0);
			}
			close (netfd);
		}

	The purpose of the double-fork is to "disown" the actual worker and
	let the server continue to accept network connections.  Without the
	"disownment", when the "workhorse" finishes and exit()s, it hangs around
	forever taking up a process slot, just so that it can return its status
	to its parent.  But the server doesn't care, ergo the double-fork-be-
	inherited-by-init trick.

	So, my suggestion is a "disown" system call, to allow parents to give
	up their children so that on exit they will vanish without a trace.
	Does anyone know why this should not be implemented (other than because
	you can do it without this)?  Alternatively, does anyone have better
	ideas?
	
That's called a spawn.  For it to work correctly, you need to have a wait:

	while ((netfd = netopen ()) >= 0) {
		if ((pid = fork ()) == 0) {
			if (fork ())
				exit (0);
			workhorse ();
			exit (0);
		}
		wait (0);	/* clean up child, leave granchild */
		close (netfd);
	}

and some error checking and fork retrying is quite useful in practice.

I prefer SIGCHLD, myself.  It's too bad select wasn't made general enough
to allow selecting on dead or stopped processes as well as file and socket
conditions.
-- 
John Quarterman, CS Dept., University of Texas, Austin, Texas
{ihnp4,seismo,ctvax}!ut-sally!jsq, jsq@ut-sally.{ARPA,UUCP}

guy@rlgvax.UUCP (Guy Harris) (01/17/84)

As for "select" working for "wait", I presume the intent was that when
"wait" was implemented as a "read" on a descriptor for the child process,
one could do "select"s to see if a child was dead.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

gwyn%brl-vld@sri-unix.UUCP (01/17/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

Being able to do something acceptably without adding a new system call
seems to me to be sufficient reason for not adding the system call.

gwyn%brl-vld@sri-unix.UUCP (01/17/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

One thing you didn't mention is that wait(2) will block until all
children have terminated under UNIX System V if SIGCLD is set to
SIG_IGN.

On 4.1cBSD at least, setting the handler for SIGCHLD to SIG_IGN was
NOT the same as setting it to SIG_DFL in that this state was
detectable by user code as a non-default mode.  I found this out
the hard way when my wait(2) emulation for UNIX System V on 4.1cBSD
went into a loop when emulated code was run by csh or telnetd users.
Turns out csh and telnetd were sloppy about resetting SIGCHLD and
had set it to SIG_IGN by mistake.  The 4.1cBSD manual had more
information about this than the 4.2BSD manual seems to have.

I urge people to set SIGCHLD to SIG_DFL if they want it totally
ignored, since SIG_IGN has different semantics for UNIX System V
programs.