diff options
Diffstat (limited to 'src/util/timed_wait.c')
-rw-r--r-- | src/util/timed_wait.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/util/timed_wait.c b/src/util/timed_wait.c new file mode 100644 index 0000000..45fbb69 --- /dev/null +++ b/src/util/timed_wait.c @@ -0,0 +1,122 @@ +/*++ +/* NAME +/* timed_wait 3 +/* SUMMARY +/* wait operations with timeout +/* SYNOPSIS +/* #include <timed_wait.h> +/* +/* int timed_waitpid(pid, statusp, options, time_limit) +/* pid_t pid; +/* WAIT_STATUS_T *statusp; +/* int options; +/* int time_limit; +/* DESCRIPTION +/* \fItimed_waitpid\fR() waits at most \fItime_limit\fR seconds +/* for process termination. +/* +/* Arguments: +/* .IP "pid, statusp, options" +/* The process ID, status pointer and options passed to waitpid(3). +/* .IP time_limit +/* The time in seconds that timed_waitpid() will wait. +/* This must be a number > 0. +/* DIAGNOSTICS +/* Panic: interface violation. +/* +/* When the time limit is exceeded, the result is -1 and errno +/* is set to ETIMEDOUT. Otherwise, the result value is the result +/* from the underlying waitpid() routine. +/* BUGS +/* If there were a \fIportable\fR way to select() on process status +/* information, these routines would not have to use a steenkeeng +/* alarm() timer and signal() handler. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/wait.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> + +/* Utility library. */ + +#include <msg.h> +#include <posix_signals.h> +#include <timed_wait.h> + +/* Application-specific. */ + +static int timed_wait_expired; + +/* timed_wait_alarm - timeout handler */ + +static void timed_wait_alarm(int unused_sig) +{ + + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. This code + * is here only so that we can break out of waitpid(). Don't put any code + * here other than for setting a global flag. + */ + timed_wait_expired = 1; +} + +/* timed_waitpid - waitpid with time limit */ + +int timed_waitpid(pid_t pid, WAIT_STATUS_T *statusp, int options, + int time_limit) +{ + const char *myname = "timed_waitpid"; + struct sigaction action; + struct sigaction old_action; + int time_left; + int wpid; + + /* + * Sanity checks. + */ + if (time_limit <= 0) + msg_panic("%s: bad time limit: %d", myname, time_limit); + + /* + * Set up a timer. + */ + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = timed_wait_alarm; + if (sigaction(SIGALRM, &action, &old_action) < 0) + msg_fatal("%s: sigaction(SIGALRM): %m", myname); + timed_wait_expired = 0; + time_left = alarm(time_limit); + + /* + * Wait for only a limited amount of time. + */ + if ((wpid = waitpid(pid, statusp, options)) < 0 && timed_wait_expired) + errno = ETIMEDOUT; + + /* + * Cleanup. + */ + alarm(0); + if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0) + msg_fatal("%s: sigaction(SIGALRM): %m", myname); + if (time_left) + alarm(time_left); + + return (wpid); +} |