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