Question

I just realised that the "script" binary on GNU linux is using two forks instead of one. It could simply use select instead of doing a first fork(). Why would it use two forks ?

Is it simply because select did not exist at the time it has been coded and nobody had the motivation to recode it or is there a valid reason ?

man 1 script: http://linux.die.net/man/1/script

script source: http://pastebin.com/raw.php?i=br8QXRUT

Was it helpful?

Solution

The clue is in the code, which I have added some comments to.

child = fork();
sigprocmask(SIG_SETMASK, &unblock_mask, NULL);

if (child < 0) {
    warn(_("fork failed"));
    fail();
}
if (child == 0) {
            /* child of first fork */
    sigprocmask(SIG_SETMASK, &block_mask, NULL);
    subchild = child = fork();
    sigprocmask(SIG_SETMASK, &unblock_mask, NULL);

    if (child < 0) {
        warn(_("fork failed"));
        fail();
    }
    if (child) {
                    /* child of second fork runs 'dooutput' */
        if (!timingfd)
            timingfd = fdopen(STDERR_FILENO, "w");
        dooutput(timingfd);
    } else
                    /* parent of second fork runs 'doshell' */
        doshell();
} else {
    sa.sa_handler = resize;
    sigaction(SIGWINCH, &sa, NULL);
}
    /* parent of first fork runs doinput */
doinput();

There are thus three process running:

  1. dooutput()
  2. doshell()
  3. doinput()

I think you are asking why use three processes, not one process and select(). select() has existed since ancient UNIX history, so the answer is unlikely to be that select() did not exist. The answer is more prosaic. doshell() needs to be in a separate process anyway, as what it does is exec the shell with appropriately piped fds. You thus need at least one fork. Writing dooutput() and doinput() within a select() loop looks to me perfectly possible, but it is actually easier to use blocking I/O rather than have to worry about using select etc. As fork() is relatively lightweight (given UNIX's CoW semantics) and there is little need for communication between the two processes, why use select() when fork() is perfectly good and produces smaller code? IE the real answer is 'why not?'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top