[comp.protocols.iso.dev-environ] Why do daemons fork five times?

PWW@BNR.CA (Peter Whittaker, P.W.) (02/16/91)

Several of the ISODE daemons (including tsbridge, the one I'm currently
playing with) perform an odd "try to fork five times" dance before shutting
down all ttys and getting on with real work.  One colleague suggested it had
something to do with latency in certain OS's, but could not elaborate.

Why don't the daemons just shut the ttys direclty, when they get to that
point?  Why the elaborate if not fork then sleep and try again
                          if fork and child exit
                          if fork and parent close ttys?
I've included the code in question for your perusal.

One possible bug herein:  the calls to dup() are not error checked.
This has resulted in ttys not being dupped onto /dev/null properly
with the result that user ttyps sometimes get spurious error messages.

advThanksance,

Peter Whittaker      [~~~~~~~~~~~~~~~~~~~~~~~~~~]   Open Systems Integration
pww@bnr.ca           [                          ]   Bell Northern Research
Ph: +1 613 765 2064  [                          ]   P.O. Box 3511, Station C
FAX:+1 613 763 3283  [__________________________]   Ottawa, Ontario, K1Y 4H7

Code follows:

	if (!(debug = isatty (2))) {
		for (i = 0; i < 5; i++) {
			switch (fork ()) {
			    case NOTOK:
				sleep (5);
				continue;
NOTE: if parent, go ahead and shut the ttys (see below)
			    case OK:
				break;
      if child, _exit(0)........
			    default:
				_exit (0);
			}
			break;
		}

		(void) chdir ("/");

		if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
			adios ("/dev/null", "unable to read");
		if (sd != 0)
			(void) dup2 (sd, 0), (void) close (sd);
		(void) dup2 (0, 1);
		(void) dup2 (0, 2);

harald.alvestrand@elab-runit.sintef.no (02/18/91)

You need to read this code carefully (I know, I missed!)


|> 
|> 	if (!(debug = isatty (2))) {
|> 		for (i = 0; i < 5; i++) {
|> 			switch (fork ()) {
|> 			    case NOTOK:
|> 				sleep (5);
|> 				continue;
Note that the CONTINUE matches the FOR, not the SWITCH....
|> 			    case OK:
|> 				break;
This breaks out of the SWITCH.........
|>       if child, _exit(0)........
|> 			    default:
|> 				_exit (0);
|> 			}
|> 			break;
This breaks out of the FOR...............
|> 		}
|> 

So, the code says "try five times to fork in intervals of 5 seconds".
One may suspect that ISODE was developed on a machine with limitations on
how many processes could be started at any one time, so that failed fork
calls were common.

You are right about the DUPs of course, but I would like to know what
errors can occur with a DUP, as long as /dev/null is a valid file...


                   Harald Tveit Alvestrand
Harald.Alvestrand@elab-runit.sintef.no
C=no;PRMD=uninett;O=sintef;OU=elab-runit;S=alvestrand;G=harald
+47 7 59 70 94

PWW@BNR.CA (Peter Whittaker, P.W.) (02/19/91)

One problem with posting to get answers is that if you make a booboo in
your post, people respond to that rather than to the intent of your post....

So, thanks to those who pointed out that my comments on the code snip below
were misplaced!  Regardless of whether it is the parent exiting or the child
exiting, could anyone tell me why the
     for (i = 0; i < 5; i++) {
is included, i.e. why try five times at five second intervals?  Especially
when the parent's behavior after the 5 attempts is identical with the child's
behavior after a succesful attempt?

Why don't the daemons just shut the ttys directly, when they get to that
point?  Why the elaborate if not fork then sleep and try again
                          if fork and child close ttys
                          if fork and parent exit   ?

One suggestion was that this is to wait the roughly 40 seconds required
to unregister a previously  active socket, but an active socket will not
prevent a fork (and this routine is called before there are any sockets
open).

Why not just do this:

         close(0); close(1); close(2);
         fd = open("/dev/tty", O_RDWR);
         ioctl(fd, TIOCNOTTY, (void *) 0);
         close(fd);
/* error checking removed for clarity */
This will close stdin, stderr, and stdout, then disassociate the process
from any tty whatsoever (via ioctl()).

The ioctl statement is in fact done (where TIOCNTTY is available) just after
the example of code below, but if it is available, why bother with all the
fork()ing and dup()ing? It seems more like overkill (and overkill that
doesn't work - since the dup()s aren't error checked) than anything else.

 if (!(debug = isatty (2))) {
  for (i = 0; i < 5; i++) {
   switch (fork ()) {
       case NOTOK:
    sleep (5);
    continue;
       case OK: /* child - proceed to closing all ttys */
    break;
       default: /* parent - _exit() - do not use any atexit() routines */
    _exit (0);
   }
   break;
  }

  (void) chdir ("/");

  if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
   adios ("/dev/null", "unable to read");
  if (sd != 0)
   (void) dup2 (sd, 0), (void) close (sd);
  (void) dup2 (0, 1);
  (void) dup2 (0, 2);

Peter Whittaker      [~~~~~~~~~~~~~~~~~~~~~~~~~~]   Open Systems Integration
pww@bnr.ca           [                          ]   Bell Northern Research
Ph: +1 613 765 2064  [                          ]   P.O. Box 3511, Station C
FAX:+1 613 763 3283  [__________________________]   Ottawa, Ontario, K1Y 4H7