1 /* $NetBSD: timed_wait.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* timed_wait 3 6 /* SUMMARY 7 /* wait operations with timeout 8 /* SYNOPSIS 9 /* #include <timed_wait.h> 10 /* 11 /* int timed_waitpid(pid, statusp, options, time_limit) 12 /* pid_t pid; 13 /* WAIT_STATUS_T *statusp; 14 /* int options; 15 /* int time_limit; 16 /* DESCRIPTION 17 /* \fItimed_waitpid\fR() waits at most \fItime_limit\fR seconds 18 /* for process termination. 19 /* 20 /* Arguments: 21 /* .IP "pid, statusp, options" 22 /* The process ID, status pointer and options passed to waitpid(3). 23 /* .IP time_limit 24 /* The time in seconds that timed_waitpid() will wait. 25 /* This must be a number > 0. 26 /* DIAGNOSTICS 27 /* Panic: interface violation. 28 /* 29 /* When the time limit is exceeded, the result is -1 and errno 30 /* is set to ETIMEDOUT. Otherwise, the result value is the result 31 /* from the underlying waitpid() routine. 32 /* BUGS 33 /* If there were a \fIportable\fR way to select() on process status 34 /* information, these routines would not have to use a steenkeeng 35 /* alarm() timer and signal() handler. 36 /* LICENSE 37 /* .ad 38 /* .fi 39 /* The Secure Mailer license must be distributed with this software. 40 /* AUTHOR(S) 41 /* Wietse Venema 42 /* IBM T.J. Watson Research 43 /* P.O. Box 704 44 /* Yorktown Heights, NY 10598, USA 45 /*--*/ 46 47 /* System library. */ 48 49 #include <sys_defs.h> 50 #include <sys/wait.h> 51 #include <unistd.h> 52 #include <signal.h> 53 #include <errno.h> 54 55 /* Utility library. */ 56 57 #include <msg.h> 58 #include <posix_signals.h> 59 #include <timed_wait.h> 60 61 /* Application-specific. */ 62 63 static int timed_wait_expired; 64 65 /* timed_wait_alarm - timeout handler */ 66 67 static void timed_wait_alarm(int unused_sig) 68 { 69 70 /* 71 * WARNING WARNING WARNING. 72 * 73 * This code runs at unpredictable moments, as a signal handler. This code 74 * is here only so that we can break out of waitpid(). Don't put any code 75 * here other than for setting a global flag. 76 */ 77 timed_wait_expired = 1; 78 } 79 80 /* timed_waitpid - waitpid with time limit */ 81 82 int timed_waitpid(pid_t pid, WAIT_STATUS_T *statusp, int options, 83 int time_limit) 84 { 85 const char *myname = "timed_waitpid"; 86 struct sigaction action; 87 struct sigaction old_action; 88 int time_left; 89 int wpid; 90 91 /* 92 * Sanity checks. 93 */ 94 if (time_limit <= 0) 95 msg_panic("%s: bad time limit: %d", myname, time_limit); 96 97 /* 98 * Set up a timer. 99 */ 100 sigemptyset(&action.sa_mask); 101 action.sa_flags = 0; 102 action.sa_handler = timed_wait_alarm; 103 if (sigaction(SIGALRM, &action, &old_action) < 0) 104 msg_fatal("%s: sigaction(SIGALRM): %m", myname); 105 timed_wait_expired = 0; 106 time_left = alarm(time_limit); 107 108 /* 109 * Wait for only a limited amount of time. 110 */ 111 if ((wpid = waitpid(pid, statusp, options)) < 0 && timed_wait_expired) 112 errno = ETIMEDOUT; 113 114 /* 115 * Cleanup. 116 */ 117 alarm(0); 118 if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0) 119 msg_fatal("%s: sigaction(SIGALRM): %m", myname); 120 if (time_left) 121 alarm(time_left); 122 123 return (wpid); 124 } 125