summaryrefslogtreecommitdiffstats
path: root/src/util/timed_wait.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/timed_wait.c')
-rw-r--r--src/util/timed_wait.c122
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);
+}