process waiting Problem: How to architect the shell to deal with > 1 background process which may die async at any time and also deal with synchronous processes. Any number of pipes may be used in either case; e.g., % foo | bar % foo | bar | baz & Two possible approachs (approach depends on what is available on UNIX systems; e.g.,) Use waitpid or wait3 along with signal mechanism: waitpid(pid, &status, 0 or WNOHANG) <---- recommended wait3() - rough bsd equivalent of above has WNOHANG doesn't have ability to wait for specific process on pure System V.3 systems you can actually do the following and ignore waiting for async processes: This is not totally portable. signal(SIGCLD, SIG_IGN) - on V.3/V.4 systems can use this to have kernel reap zombies as soon as they are created. on non whacky (Sys V.3) unix systems, you can use SIGCHLD to get async notification: signal(SIGCHLD, onchild) - get 1 signal for 1 or more zombie processes. signal handler onchild is invoked. 1. async with signals on BSD system, could use extern int onchild(); signal(SIGCHLD, onchild); onchild is called whenever a process exits. Problem here is that SIGNALS are unreliable because only 1 unserviced signal at a time can be stored in the UNIX process control block. As a result, signals can be lost. The way to deal with this is to harvest zombies in a loop in the signal handler. E.g., init code: signal(SIGCHLD, onchild); /* harvest any existing zombies and return */ onchild() { int pid; int status; while(1) { pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) break; } } This will take care of zombies. Whatabout process sync? If you start a pipe, simply wait on the right-most process. fork fork fork/pipe pipe pipe.... waitpid(pid, &status, 0); Or you could simply pause and wait for the onchild routine to harvest 1 or more specific pids. Pause will return on any signal. in main line: fork/exec of right-most process wantPid = pid of that process if (syncFlag) { while(wantPid) pause(); } interrupt handler: onchild() { int pid; int status; while(1) { pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) break; if (wantPid == pid) wantPid = 0; } } signals are the best solution here (unless you can get the kernel to do the job for you... For pipes, you can also simply wait for the rhs process. The kernel won't let you wait (block) on a process that has been reaped. 2. polling method: Write a routine that is similar to the onchild routine. Then simply call it before you exec any jobs and before the shell exits. If you can do this you avoid messing with signals, BUT you don't reap processes as fast as they die (con). reapzombie() { int pid; int status; while(1) { pid = waitpid(-1, &status, WNOHANG); if (pid <= 0) break; } } 3. solaris compilation note void reapzombie(void); /* type declaration */ void reapzombie(void) { ... }