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