/* * Functions you may use for your shell. * See FAQ Question 24. * * CS 3214 Fall 2011, Godmar Back. */ /* * SIGCHLD handler. * Call waitpid() to learn about any child processes that * have exited or changed status (been stopped, needed the * terminal, etc.) * Just record the information by updating the job list * data structures. Since the call may be spurious (e.g. * an already pending SIGCHLD is delivered even though * a foreground process was already reaped), ignore when * waitpid returns -1. * Use a loop with WNOHANG since only a single SIGCHLD * signal may be delivered for multiple children that have * exited. */ static void sigchld_handler(int sig, siginfo_t *info, void *_ctxt) { pid_t child; int status; assert(sig == SIGCHLD); while ((child = waitpid(-1, &status, WUNTRACED|WNOHANG)) > 0) { child_status_change(child, status); } } /* Wait for all processes in this pipeline to complete, or for * the pipeline's process group to no longer be the foreground * process group. * You should call this function from a) where you wait for * jobs started without the &; and b) where you implement the * 'fg' command. * * Implement child_status_change such that it records the * information obtained from waitpid() for pid 'child.' * If a child has exited or terminated (but not stopped!) * it should be removed from the list of commands of its * pipeline data structure so that an empty list is obtained * if all processes that are part of a pipeline have * terminated. If you use a different approach to keep * track of commands, adjust the code accordingly. */ static void wait_for_job(struct esh_pipeline *pipeline) { assert(esh_signal_is_blocked(SIGCHLD)); while (pipeline->status == FOREGROUND && !list_empty(&pipeline->commands)) { int status; pid_t child = waitpid(-1, &status, WUNTRACED); if (child != -1) child_status_change(child, status); } }