#include /* for errno() */ #include /* for ARG_MAX */ #include /* for signal(), SIG* */ #include /* for sprintf(), stderr, ... */ #include /* for exit() */ #include /* for strerror() */ #include /* for wait() */ #include /* for wait() */ #include /* for sleep(), fork() and execlp() */ #include "funcs.h" /* for infomsg(), errormsg() */ /* * Macros */ #define TIMEOUT 15 #define A_LONG_TIME 3600 #define CHILD_RUN_TIME 10 /* * Type and struct definitions */ /* * Global variables */ int child_reaped = FALSE; int timed_out = FALSE; /* * Forward declarations */ pid_t start_child_sleep(void); void sigchld_handler(int); void sigalrm_handler(int); /* * Functions */ int main( int argc, char *argv[]) { pid_t pid; /* * Initialise. */ infomsg("parent setting up signal handlers ..."); signal(SIGCHLD, sigchld_handler); signal(SIGALRM, sigalrm_handler); /* * Start child. */ infomsg("parent starting one child ..."); pid = start_child_sleep(); /* * Schedule timeout alarm. */ infomsg("parent scheduling timeout alarm ..."); alarm(TIMEOUT); /* * Main monitoring loop */ infomsg("parent entering monitoring loop ..."); while (TRUE) { /* * Exit if no running children. */ if (child_reaped) { if (!timed_out) alarm(0); infomsg("parent sees child_reaped flag and so stops looping ..."); break; } /* * Kill child if it has reached its timeout time. */ if (timed_out) { infomsg("parent sees timed_out flag and so kills child ..."); kill(pid, SIGTERM); } /* * Sleep until next signal arrives */ infomsg("parent sleeping until signal arrives ..."); sleep(A_LONG_TIME); /* * If SIGCHLD arrived before SIGALRM then the alarm is still * pending. Cancel it. */ infomsg("parent cancelling alarm ..."); alarm(0); } /* * Clean up and exit. */ infomsg("parent cleaning up and exiting ..."); signal(SIGCHLD, SIG_DFL); signal(SIGALRM, SIG_DFL); return(0); } pid_t start_child_sleep( ) { pid_t pid; char buf[ARG_MAX]; if ((pid=fork()) < 0) errormsg("fork() failed: %s", strerror(errno)); else if (pid > 0) return(pid); /* * Only the child gets here */ sprintf(buf, "echo \"child running ...\";" "sleep %d;" "echo \"child exiting ...\"", CHILD_RUN_TIME); execlp("/bin/sh", "sh", "-c", buf, (char *) NULL); errormsg("exec() failed: %s", strerror(errno)); } void sigchld_handler( int sig) { int wstatus; pid_t pid; infomsg("parent received SIGCHLD; reaping and setting child_reaped flag ..."); pid = wait(&wstatus); child_reaped = TRUE; } void sigalrm_handler( int sig) { infomsg("parent received SIGALRM; setting timed_out flag ..."); timed_out = TRUE; }