#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 time() */ #include /* for sleep(), fork() and execlp() */ #include "funcs.h" /* for infomsg(), errormsg() */ /* * Macros */ #define MAX_CHILDREN 1000 #define CHILDREN 500 #define TIMEOUT 300 #define A_LONG_TIME 3600 #define CHILD_RUN_TIME(n) 1 /* * Type and struct definitions */ struct child { pid_t pid; time_t start; }; /* * Global variables */ struct child children[MAX_CHILDREN]; /* * Forward declarations */ pid_t start_child_sleep(int); void sigchld_handler(int); void sigalrm_handler(int); void sigusr1_handler(int); /* * Functions */ int main( int argc, char *argv[]) { int i; int running_children_count, next_timeout, killed_something; time_t now; /* * Initialise. */ infomsg("parent initialising children status table ..."); for (i=0; i= children[i].start+TIMEOUT) { kill(children[i].pid, SIGTERM); children[i].start = 0; killed_something = TRUE; } /* * Slight optimisation: if something did reach its timeout and got * killed then skip to reassessing if this program can exit. */ if (killed_something) continue; /* * Schedule timeout alarm of next-to-timeout child. */ infomsg("parent scheduling timeout alarm ..."); next_timeout = 0; for (i=0; i= 1) { infomsg("parent scheduling alarm for %ds ...", next_timeout); alarm(next_timeout); } /* * Sleep until next signal arrives * (unless timeout is so close that we didn't schedule an alarm * so sleeping might not be interrupted). */ infomsg("parent sleeping until signal arrives ..."); if (next_timeout >= 1) 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); signal(SIGUSR1, SIG_DFL); return(0); } pid_t start_child_sleep( int period) { pid_t pid; char buf[ARG_MAX]; int i; /* * Find an empty slot to store info about the process we're * about launch. */ for (i=0; i 0) { children[i].pid = pid; children[i].start = time(NULL); return(pid); } /* * Only the child gets here */ execlp("/bin/sh", "sh", "-c", buf, (char *) NULL); errormsg("exec() failed: %s", strerror(errno)); } void sigchld_handler( int sig) { int wstatus; pid_t pid; int i; while ((pid=waitpid(-1, &wstatus, WNOHANG)) > 0) { infomsg("parent received SIGCHLD; reaping and clearing child data ..."); for (i=0; i