Article 59987 of comp.os.vms:
Path: jac.zko.dec.com!pa.dec.com!decuac.dec.com!haven.umd.edu!ames!lll-winken.llnl.gov!hookup!news.mathworks.com!mvb.saic.com!info-vax
From: Jerry Leichter <leichter@lrw.com>
Newsgroups: comp.os.vms
Subject: re: RE: tcp/ip, signals and queues
Message-ID: <9504301536.AA13303@uu3.psi.com>
Date: Sun, 30 Apr 95 11:27:33 EDT
Organization: Info-Vax<==>Comp.Os.Vms Gateway
X-Gateway-Source-Info: Mailing List
Lines: 68

[Mr. Jensen:  Your message arrived here with the unreplyable "From" address of
"bjj@ECL".  Your posting software needs work....]

	[I wrote:]
	>While you can more or less write Unix programs in a VMS AST-driven
	>style, you'll find yourself fighting Unix all the way.  You're likely
	>to do better using a pseudo-polling style of programming, based on
	>the select() call.  That's what it's there for.

	[Mr. Jensen replies:]
	I tried this.  It worked great until I found I needed a child process.
	A child process can't terminate until a parent terminates it.  The
	only way for the parent to find out a child wants to terminate is via
	a signal.

	I would have liked the signal to terminate the select so that I could
	clean up the child (and do some other stuff) in a polling type of way.
	Unfortunately, UNIX has no facility for terminating a select except by
	completion of I/O, a signal can't do it.

	Ok, so a signal always terminates a select, but that is strictly a
	bug, it's not useful, because a signal occuring right before a select
	will not terminate the select that is about to be executed.

Sigh.  I really don't want to turn INFO-VAX into a seminar on Unix programming
techniques (aka "hacks of the Unix masters").  However, there the situation
you describe has several solutions:

	1.  If you set up a signal handler, it would be triggered whether
		the signal arrived before or during the select().  The signal
		handler would be programmed to increment some global volatile
		variable to indicate that a child process had terminated.
		You'd then have the code executed when select() completed
		check that variable to see how many children it should wait
		on.

	2.  The waitpid() function has an option, WNOHANG, which causes it to
		return immediately if there are no un-waited for children.
		This makes it possible to poll for terminated children without
		becoming blocked in wait().

	3.  If you don't actually care about the terminated children's final
		status, you can request that the SIGCHILD (or SIGCHLD - it
		depends on the Unix system you are using!) signal be ignored.
		For this particular signal, "ignored by default" means some-
		thing different from "ignored by explicit request":  In the
		latter case, as soon as the signal has been "explicitly
		ignored", the child disappears, with no need for you to wait
		on it.  Or something like that - this is one of the more
		bizarre corners of the wholely bizarre world of Unix signal
		handling.

	4.  Finally, again if you don't care about the actual termination
		status, there is a classic if very bizarre technique that
		can be used to prevent children from becoming "zombies" when
		the parent doesn't wait on them:  Parent P fork()'s to produce
		child C, and does an immediate wait().  Child C immediate
		fork()'s again to produce grandchild G, and exits.  When C
		exits, P's wait() completes, and G becomes an orphan.  Since
		Unix doesn't like orphans, it immediately makes init G's
		parent.  G goes ahead and does whatever it's supposed to do.
		When it exits, a wait() in init (or, in recent versions, the
		strange hack with SIGCHLD/SIGCHILD) causes G to vanish, rather
		than become a zombie.
		
Yes, these are all horrible solutions.  *Unix* is a horrible solution.  But if
you've got to use it....
							-- Jerry


