sh/csh and wait()

Ed Anselmo Anselmo-Ed at cs.yale.edu
Tue Jul 17 07:46:46 AEST 1990


One of the CS classes here used the following program as a simple
example of creating a chain of processes.  The idea was to watch the
exit status of all the child processes and print the results from the
parent process.  This all works fine if the last process in the chain
consumes all of stdin, e.g.

	pipe cat tail < /etc/termcap

But if the last process doesn't consume stdin, e.g.

	pipe cat head < /etc/termcap

it looks like the "head" process terminates, the "cat" process is
waiting for the pipe to unblock, and parent process has gotten a
SIGCHLD.  Basically, things just sit there until you kill the parent
process.

Obviously, this doesn't happen if you try something similar with
/bin/sh or /bin/csh.  So how do /bin/sh and /bin/csh do it?  I looked
through the sources to sh and csh and got a bit lost ....

/* compile with cc -o pipe pipc.c */

main (int argc, char *argv[])
{
    int pid, status, fd[2], i,j;
    struct entry {int pid, status;} *table;

    if (argc < 2)  {
	printf ("Usage:  pipe filter1 filter2 ... filterN\n");
	exit(0);
    }

    table = (struct entry *) malloc (argc*sizeof(struct entry));

    for (i = 2;  i < argc;  i++)  {         /* Create chain of processes */
	pipe (fd);
	if ((pid = fork()) < 0)
	    errorExit(-1);
	else if (pid == 0) {                    /* Child process */
	    close (fd[0]);                      /* stdout to parent */
	    if (fd[1] != 1)  {
		dup2 (fd[1], 1);
		close (fd[1]);
	    }
	    execlp (argv[i-1], argv[i-1],0);    /* Overlay by (i-1)st filter */
	    errorExit(-1);
	}
	else {                                  /* Parent process */
	    table[i-1].pid = pid;               /* Save child pid */
	    close (fd[1]);
	    if (fd[0] != 0)  {                  /* stdin from child */
		dup2 (fd[0], 0);
		close (fd[0]);
	    }
	}
    }

    if ((pid = fork()) < 0)                 /* Create last process in chain */
	errorExit(-1);
    else if (pid == 0) {                        /* Child process */
	execlp(argv[argc-1],argv[argc-1],0);    /* Overlay by last filter */
	errorExit(-1);
    }
    table[argc-1].pid = pid;                /* Save child pid */

    for (i = 1;  i < argc;  i++)  {         /* Wait for all children to die */
	pid = wait(&status);
	for (j = 1;  table[j].pid != pid;  j++)
	    ;
	table[j].status = status;
    }

    for (i = 1;  i < argc;  i++)  {         /* Print information */
	printf ("%-10s  pid=%d  high=%d  low=%d\n",
	    argv[i], table[i].pid,
	    (table[i].status>>8)&0377, table[i].status&0377);
    }
}

errorExit(int status)
{
    perror("pipe");
    exit(status);
}
--
Ed Anselmo   anselmo-ed at cs.yale.edu   {harvard,decvax}!yale!anselmo-ed



More information about the Comp.unix.wizards mailing list