xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/poll_fd.c (revision 16d67a18c4cbb2d3cb426b01120f4938ca6dbbf9)
1*16d67a18Stron /*	$NetBSD: poll_fd.c,v 1.1.1.1 2014/07/06 19:27:58 tron Exp $	*/
2*16d67a18Stron 
3*16d67a18Stron /*++
4*16d67a18Stron /* NAME
5*16d67a18Stron /*	poll_fd 3
6*16d67a18Stron /* SUMMARY
7*16d67a18Stron /*	wait until file descriptor becomes readable or writable
8*16d67a18Stron /* SYNOPSIS
9*16d67a18Stron /*	#include <iostuff.h>
10*16d67a18Stron /*
11*16d67a18Stron /*	int	readable(fd)
12*16d67a18Stron /*	int	fd;
13*16d67a18Stron /*
14*16d67a18Stron /*	int	writable(fd)
15*16d67a18Stron /*	int	fd;
16*16d67a18Stron /*
17*16d67a18Stron /*	int	read_wait(fd, time_limit)
18*16d67a18Stron /*	int	fd;
19*16d67a18Stron /*	int	time_limit;
20*16d67a18Stron /*
21*16d67a18Stron /*	int	write_wait(fd, time_limit)
22*16d67a18Stron /*	int	fd;
23*16d67a18Stron /*	int	time_limit;
24*16d67a18Stron /*
25*16d67a18Stron /*	int	poll_fd(fd, request, time_limit, true_res, false_res)
26*16d67a18Stron /*	int	fd;
27*16d67a18Stron /*	int	request;
28*16d67a18Stron /*	int	time_limit;
29*16d67a18Stron /*	int	true_res;
30*16d67a18Stron /*	int	false_res;
31*16d67a18Stron /* DESCRIPTION
32*16d67a18Stron /*	The read*() and write*() functions in this module are macros
33*16d67a18Stron /*	that provide a convenient interface to poll_fd().
34*16d67a18Stron /*
35*16d67a18Stron /*	readable() asks the kernel if the specified file descriptor
36*16d67a18Stron /*	is readable, i.e. a read operation would not block.
37*16d67a18Stron /*
38*16d67a18Stron /*	writable() asks the kernel if the specified file descriptor
39*16d67a18Stron /*	is writable, i.e. a write operation would not block.
40*16d67a18Stron /*
41*16d67a18Stron /*	read_wait() waits until the specified file descriptor becomes
42*16d67a18Stron /*	readable, or until the time limit is reached.
43*16d67a18Stron /*
44*16d67a18Stron /*	write_wait() waits until the specified file descriptor
45*16d67a18Stron /*	becomes writable, or until the time limit is reached.
46*16d67a18Stron /*
47*16d67a18Stron /*	poll_fd() waits until the specified file descriptor becomes
48*16d67a18Stron /*	readable or writable, or until the time limit is reached.
49*16d67a18Stron /*
50*16d67a18Stron /*	Arguments:
51*16d67a18Stron /* .IP fd
52*16d67a18Stron /*	File descriptor. With implementations based on select(), a
53*16d67a18Stron /*	best effort is made to handle descriptors >=FD_SETSIZE.
54*16d67a18Stron /* .IP request
55*16d67a18Stron /*	POLL_FD_READ (wait until readable) or POLL_FD_WRITE (wait
56*16d67a18Stron /*	until writable).
57*16d67a18Stron /* .IP time_limit
58*16d67a18Stron /*	A positive value specifies a time limit in seconds. A zero
59*16d67a18Stron /*	value effects a poll (return immediately).  A negative value
60*16d67a18Stron /*	means wait until the requested POLL_FD_READ or POLL_FD_WRITE
61*16d67a18Stron /*	condition becomes true.
62*16d67a18Stron /* .IP true_res
63*16d67a18Stron /*	Result value when the requested POLL_FD_READ or POLL_FD_WRITE
64*16d67a18Stron /*	condition is true.
65*16d67a18Stron /* .IP false_res
66*16d67a18Stron /*	Result value when the requested POLL_FD_READ or POLL_FD_WRITE
67*16d67a18Stron /*	condition is false.
68*16d67a18Stron /* DIAGNOSTICS
69*16d67a18Stron /*	Panic: interface violation. All system call errors are fatal
70*16d67a18Stron /*	unless specified otherwise.
71*16d67a18Stron /*
72*16d67a18Stron /*	readable() and writable() return 1 when the requested
73*16d67a18Stron /*	POLL_FD_READ or POLL_FD_WRITE condition is true, zero when
74*16d67a18Stron /*	it is false. They never return an error indication.
75*16d67a18Stron /*
76*16d67a18Stron /*	read_wait() and write_wait() return zero when the requested
77*16d67a18Stron /*	POLL_FD_READ or POLL_FD_WRITE condition is true, -1 (with
78*16d67a18Stron /*	errno set to ETIMEDOUT) when it is false.
79*16d67a18Stron /*
80*16d67a18Stron /*	poll_fd() returns true_res when the requested POLL_FD_READ
81*16d67a18Stron /*	or POLL_FD_WRITE condition is true, false_res when it is
82*16d67a18Stron /*	false.  When poll_fd() returns a false_res value < 0, it
83*16d67a18Stron /*	also sets errno to ETIMEDOUT.
84*16d67a18Stron /* LICENSE
85*16d67a18Stron /* .ad
86*16d67a18Stron /* .fi
87*16d67a18Stron /*	The Secure Mailer license must be distributed with this software.
88*16d67a18Stron /* AUTHOR(S)
89*16d67a18Stron /*	Wietse Venema
90*16d67a18Stron /*	IBM T.J. Watson Research
91*16d67a18Stron /*	P.O. Box 704
92*16d67a18Stron /*	Yorktown Heights, NY 10598, USA
93*16d67a18Stron /*--*/
94*16d67a18Stron 
95*16d67a18Stron /* System library. */
96*16d67a18Stron 
97*16d67a18Stron #include <sys_defs.h>
98*16d67a18Stron #include <sys/time.h>
99*16d67a18Stron #include <signal.h>
100*16d67a18Stron #include <errno.h>
101*16d67a18Stron #include <unistd.h>
102*16d67a18Stron #include <string.h>
103*16d67a18Stron 
104*16d67a18Stron  /*
105*16d67a18Stron   * Use poll() with fall-back to select(). MacOSX needs this for devices.
106*16d67a18Stron   */
107*16d67a18Stron #if defined(USE_SYSV_POLL_THEN_SELECT)
108*16d67a18Stron #define poll_fd_sysv	poll_fd
109*16d67a18Stron #define USE_SYSV_POLL
110*16d67a18Stron #define USE_BSD_SELECT
111*16d67a18Stron int     poll_fd_bsd(int, int, int, int, int);
112*16d67a18Stron 
113*16d67a18Stron  /*
114*16d67a18Stron   * Use select() only.
115*16d67a18Stron   */
116*16d67a18Stron #elif defined(USE_BSD_SELECT)
117*16d67a18Stron #define poll_fd_bsd	poll_fd
118*16d67a18Stron #undef USE_SYSV_POLL
119*16d67a18Stron 
120*16d67a18Stron  /*
121*16d67a18Stron   * Use poll() only.
122*16d67a18Stron   */
123*16d67a18Stron #elif defined(USE_SYSV_POLL)
124*16d67a18Stron #define poll_fd_sysv	poll_fd
125*16d67a18Stron 
126*16d67a18Stron  /*
127*16d67a18Stron   * Sanity check.
128*16d67a18Stron   */
129*16d67a18Stron #else
130*16d67a18Stron #error "specify USE_SYSV_POLL, USE_BSD_SELECT or USE_SYSV_POLL_THEN_SELECT"
131*16d67a18Stron #endif
132*16d67a18Stron 
133*16d67a18Stron #ifdef USE_SYSV_POLL
134*16d67a18Stron #include <poll.h>
135*16d67a18Stron #endif
136*16d67a18Stron 
137*16d67a18Stron #ifdef USE_SYS_SELECT_H
138*16d67a18Stron #include <sys/select.h>
139*16d67a18Stron #endif
140*16d67a18Stron 
141*16d67a18Stron /* Utility library. */
142*16d67a18Stron 
143*16d67a18Stron #include <msg.h>
144*16d67a18Stron #include <iostuff.h>
145*16d67a18Stron 
146*16d67a18Stron #ifdef USE_BSD_SELECT
147*16d67a18Stron 
148*16d67a18Stron /* poll_fd_bsd - block with time_limit until file descriptor is ready */
149*16d67a18Stron 
poll_fd_bsd(int fd,int request,int time_limit,int true_res,int false_res)150*16d67a18Stron int     poll_fd_bsd(int fd, int request, int time_limit,
151*16d67a18Stron 		            int true_res, int false_res)
152*16d67a18Stron {
153*16d67a18Stron     fd_set  req_fds;
154*16d67a18Stron     fd_set *read_fds;
155*16d67a18Stron     fd_set *write_fds;
156*16d67a18Stron     fd_set  except_fds;
157*16d67a18Stron     struct timeval tv;
158*16d67a18Stron     struct timeval *tp;
159*16d67a18Stron     int     temp_fd = -1;
160*16d67a18Stron 
161*16d67a18Stron     /*
162*16d67a18Stron      * Sanity checks.
163*16d67a18Stron      */
164*16d67a18Stron     if (FD_SETSIZE <= fd) {
165*16d67a18Stron 	if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
166*16d67a18Stron 	    msg_fatal("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE);
167*16d67a18Stron 	fd = temp_fd;
168*16d67a18Stron     }
169*16d67a18Stron 
170*16d67a18Stron     /*
171*16d67a18Stron      * Use select() so we do not depend on alarm() and on signal() handlers.
172*16d67a18Stron      * Restart select() when interrupted by some signal. Some select()
173*16d67a18Stron      * implementations reduce the time to wait when interrupted, which is
174*16d67a18Stron      * exactly what we want.
175*16d67a18Stron      */
176*16d67a18Stron     FD_ZERO(&req_fds);
177*16d67a18Stron     FD_SET(fd, &req_fds);
178*16d67a18Stron     except_fds = req_fds;
179*16d67a18Stron     if (request == POLL_FD_READ) {
180*16d67a18Stron 	read_fds = &req_fds;
181*16d67a18Stron 	write_fds = 0;
182*16d67a18Stron     } else if (request == POLL_FD_WRITE) {
183*16d67a18Stron 	read_fds = 0;
184*16d67a18Stron 	write_fds = &req_fds;
185*16d67a18Stron     } else {
186*16d67a18Stron 	msg_panic("poll_fd: bad request %d", request);
187*16d67a18Stron     }
188*16d67a18Stron 
189*16d67a18Stron     if (time_limit >= 0) {
190*16d67a18Stron 	tv.tv_usec = 0;
191*16d67a18Stron 	tv.tv_sec = time_limit;
192*16d67a18Stron 	tp = &tv;
193*16d67a18Stron     } else {
194*16d67a18Stron 	tp = 0;
195*16d67a18Stron     }
196*16d67a18Stron 
197*16d67a18Stron     for (;;) {
198*16d67a18Stron 	switch (select(fd + 1, read_fds, write_fds, &except_fds, tp)) {
199*16d67a18Stron 	case -1:
200*16d67a18Stron 	    if (errno != EINTR)
201*16d67a18Stron 		msg_fatal("select: %m");
202*16d67a18Stron 	    continue;
203*16d67a18Stron 	case 0:
204*16d67a18Stron 	    if (temp_fd != -1)
205*16d67a18Stron 		(void) close(temp_fd);
206*16d67a18Stron 	    if (false_res < 0)
207*16d67a18Stron 		errno = ETIMEDOUT;
208*16d67a18Stron 	    return (false_res);
209*16d67a18Stron 	default:
210*16d67a18Stron 	    if (temp_fd != -1)
211*16d67a18Stron 		(void) close(temp_fd);
212*16d67a18Stron 	    return (true_res);
213*16d67a18Stron 	}
214*16d67a18Stron     }
215*16d67a18Stron }
216*16d67a18Stron 
217*16d67a18Stron #endif
218*16d67a18Stron 
219*16d67a18Stron #ifdef USE_SYSV_POLL
220*16d67a18Stron 
221*16d67a18Stron #ifdef USE_SYSV_POLL_THEN_SELECT
222*16d67a18Stron #define HANDLE_SYSV_POLL_ERROR(fd, req, time_limit, true_res, false_res) \
223*16d67a18Stron 	return (poll_fd_bsd((fd), (req), (time_limit), (true_res), (false_res)))
224*16d67a18Stron #else
225*16d67a18Stron #define HANDLE_SYSV_POLL_ERROR(fd, req, time_limit, true_res, false_res) \
226*16d67a18Stron 	msg_fatal("poll: %m")
227*16d67a18Stron #endif
228*16d67a18Stron 
229*16d67a18Stron /* poll_fd_sysv - block with time_limit until file descriptor is ready */
230*16d67a18Stron 
poll_fd_sysv(int fd,int request,int time_limit,int true_res,int false_res)231*16d67a18Stron int     poll_fd_sysv(int fd, int request, int time_limit,
232*16d67a18Stron 		             int true_res, int false_res)
233*16d67a18Stron {
234*16d67a18Stron     struct pollfd pollfd;
235*16d67a18Stron 
236*16d67a18Stron     /*
237*16d67a18Stron      * System-V poll() is optimal for polling a few descriptors.
238*16d67a18Stron      */
239*16d67a18Stron #define WAIT_FOR_EVENT	(-1)
240*16d67a18Stron 
241*16d67a18Stron     pollfd.fd = fd;
242*16d67a18Stron     if (request == POLL_FD_READ) {
243*16d67a18Stron 	pollfd.events = POLLIN;
244*16d67a18Stron     } else if (request == POLL_FD_WRITE) {
245*16d67a18Stron 	pollfd.events = POLLOUT;
246*16d67a18Stron     } else {
247*16d67a18Stron 	msg_panic("poll_fd: bad request %d", request);
248*16d67a18Stron     }
249*16d67a18Stron 
250*16d67a18Stron     for (;;) {
251*16d67a18Stron 	switch (poll(&pollfd, 1, time_limit < 0 ?
252*16d67a18Stron 		     WAIT_FOR_EVENT : time_limit * 1000)) {
253*16d67a18Stron 	case -1:
254*16d67a18Stron 	    if (errno != EINTR)
255*16d67a18Stron 		HANDLE_SYSV_POLL_ERROR(fd, request, time_limit,
256*16d67a18Stron 				       true_res, false_res);
257*16d67a18Stron 	    continue;
258*16d67a18Stron 	case 0:
259*16d67a18Stron 	    if (false_res < 0)
260*16d67a18Stron 		errno = ETIMEDOUT;
261*16d67a18Stron 	    return (false_res);
262*16d67a18Stron 	default:
263*16d67a18Stron 	    if (pollfd.revents & POLLNVAL)
264*16d67a18Stron 		HANDLE_SYSV_POLL_ERROR(fd, request, time_limit,
265*16d67a18Stron 				       true_res, false_res);
266*16d67a18Stron 	    return (true_res);
267*16d67a18Stron 	}
268*16d67a18Stron     }
269*16d67a18Stron }
270*16d67a18Stron 
271*16d67a18Stron #endif
272