1*4882a593Smuzhiyun /*---------------------------------------------------------------------------*\
2*4882a593Smuzhiyun $Id$
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun NAME
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun poll - select(2)-based poll() emulation function for BSD systems.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun SYNOPSIS
9*4882a593Smuzhiyun #include "poll.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun struct pollfd
12*4882a593Smuzhiyun {
13*4882a593Smuzhiyun int fd;
14*4882a593Smuzhiyun short events;
15*4882a593Smuzhiyun short revents;
16*4882a593Smuzhiyun }
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun DESCRIPTION
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun This file, and the accompanying "poll.h", implement the System V
23*4882a593Smuzhiyun poll(2) system call for BSD systems (which typically do not provide
24*4882a593Smuzhiyun poll()). Poll() provides a method for multiplexing input and output
25*4882a593Smuzhiyun on multiple open file descriptors; in traditional BSD systems, that
26*4882a593Smuzhiyun capability is provided by select(). While the semantics of select()
27*4882a593Smuzhiyun differ from those of poll(), poll() can be readily emulated in terms
28*4882a593Smuzhiyun of select() -- which is how this function is implemented.
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun REFERENCES
31*4882a593Smuzhiyun Stevens, W. Richard. Unix Network Programming. Prentice-Hall, 1990.
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun NOTES
34*4882a593Smuzhiyun 1. This software requires an ANSI C compiler.
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun LICENSE
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun This software is released under the following BSD license, adapted from
39*4882a593Smuzhiyun http://opensource.org/licenses/bsd-license.php
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun Copyright (c) 1995-2011, Brian M. Clapper
42*4882a593Smuzhiyun All rights reserved.
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun Redistribution and use in source and binary forms, with or without
45*4882a593Smuzhiyun modification, are permitted provided that the following conditions are met:
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun * Redistributions of source code must retain the above copyright notice,
48*4882a593Smuzhiyun this list of conditions and the following disclaimer.
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun * Redistributions in binary form must reproduce the above copyright
51*4882a593Smuzhiyun notice, this list of conditions and the following disclaimer in the
52*4882a593Smuzhiyun documentation and/or other materials provided with the distribution.
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun * Neither the name of the clapper.org nor the names of its contributors
55*4882a593Smuzhiyun may be used to endorse or promote products derived from this software
56*4882a593Smuzhiyun without specific prior written permission.
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
59*4882a593Smuzhiyun IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
60*4882a593Smuzhiyun THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
61*4882a593Smuzhiyun PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
62*4882a593Smuzhiyun CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
63*4882a593Smuzhiyun EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
64*4882a593Smuzhiyun PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
65*4882a593Smuzhiyun PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
66*4882a593Smuzhiyun LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
67*4882a593Smuzhiyun NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
68*4882a593Smuzhiyun SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69*4882a593Smuzhiyun \*---------------------------------------------------------------------------*/
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /*---------------------------------------------------------------------------*\
73*4882a593Smuzhiyun Includes
74*4882a593Smuzhiyun \*---------------------------------------------------------------------------*/
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
77*4882a593Smuzhiyun #include <dix-config.h>
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #include <unistd.h> /* standard Unix definitions */
81*4882a593Smuzhiyun #include <sys/types.h> /* system types */
82*4882a593Smuzhiyun #include <sys/time.h> /* time definitions */
83*4882a593Smuzhiyun #include <assert.h> /* assertion macros */
84*4882a593Smuzhiyun #include <string.h> /* string functions */
85*4882a593Smuzhiyun #include "xserver_poll.h"
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /*---------------------------------------------------------------------------*\
88*4882a593Smuzhiyun Macros
89*4882a593Smuzhiyun \*---------------------------------------------------------------------------*/
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #ifndef MAX
92*4882a593Smuzhiyun #define MAX(a,b) ((a) > (b) ? (a) : (b))
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /*---------------------------------------------------------------------------*\
96*4882a593Smuzhiyun Private Functions
97*4882a593Smuzhiyun \*---------------------------------------------------------------------------*/
98*4882a593Smuzhiyun
map_poll_spec(struct pollfd * pArray,nfds_t n_fds,fd_set * pReadSet,fd_set * pWriteSet,fd_set * pExceptSet)99*4882a593Smuzhiyun static int map_poll_spec
100*4882a593Smuzhiyun (struct pollfd *pArray,
101*4882a593Smuzhiyun nfds_t n_fds,
102*4882a593Smuzhiyun fd_set *pReadSet,
103*4882a593Smuzhiyun fd_set *pWriteSet,
104*4882a593Smuzhiyun fd_set *pExceptSet)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun register nfds_t i; /* loop control */
107*4882a593Smuzhiyun register struct pollfd *pCur; /* current array element */
108*4882a593Smuzhiyun register int max_fd = -1; /* return value */
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /*
111*4882a593Smuzhiyun Map the poll() structures into the file descriptor sets required
112*4882a593Smuzhiyun by select().
113*4882a593Smuzhiyun */
114*4882a593Smuzhiyun for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun /* Skip any bad FDs in the array. */
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (pCur->fd < 0)
119*4882a593Smuzhiyun continue;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (pCur->events & POLLIN)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun /* "Input Ready" notification desired. */
124*4882a593Smuzhiyun FD_SET (pCur->fd, pReadSet);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (pCur->events & POLLOUT)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun /* "Output Possible" notification desired. */
130*4882a593Smuzhiyun FD_SET (pCur->fd, pWriteSet);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (pCur->events & POLLPRI)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun "Exception Occurred" notification desired. (Exceptions
137*4882a593Smuzhiyun include out of band data.
138*4882a593Smuzhiyun */
139*4882a593Smuzhiyun FD_SET (pCur->fd, pExceptSet);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun max_fd = MAX (max_fd, pCur->fd);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return max_fd;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
map_timeout(int poll_timeout,struct timeval * pSelTimeout)148*4882a593Smuzhiyun static struct timeval *map_timeout
149*4882a593Smuzhiyun (int poll_timeout, struct timeval *pSelTimeout)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun struct timeval *pResult;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun Map the poll() timeout value into a select() timeout. The possible
155*4882a593Smuzhiyun values of the poll() timeout value, and their meanings, are:
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun VALUE MEANING
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun -1 wait indefinitely (until signal occurs)
160*4882a593Smuzhiyun 0 return immediately, don't block
161*4882a593Smuzhiyun >0 wait specified number of milliseconds
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun select() uses a "struct timeval", which specifies the timeout in
164*4882a593Smuzhiyun seconds and microseconds, so the milliseconds value has to be mapped
165*4882a593Smuzhiyun accordingly.
166*4882a593Smuzhiyun */
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun assert (pSelTimeout != (struct timeval *) NULL);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun switch (poll_timeout)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun case -1:
173*4882a593Smuzhiyun /*
174*4882a593Smuzhiyun A NULL timeout structure tells select() to wait indefinitely.
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun pResult = (struct timeval *) NULL;
177*4882a593Smuzhiyun break;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun case 0:
180*4882a593Smuzhiyun /*
181*4882a593Smuzhiyun "Return immediately" (test) is specified by all zeros in
182*4882a593Smuzhiyun a timeval structure.
183*4882a593Smuzhiyun */
184*4882a593Smuzhiyun pSelTimeout->tv_sec = 0;
185*4882a593Smuzhiyun pSelTimeout->tv_usec = 0;
186*4882a593Smuzhiyun pResult = pSelTimeout;
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun default:
190*4882a593Smuzhiyun /* Wait the specified number of milliseconds. */
191*4882a593Smuzhiyun pSelTimeout->tv_sec = poll_timeout / 1000; /* get seconds */
192*4882a593Smuzhiyun poll_timeout %= 1000; /* remove seconds */
193*4882a593Smuzhiyun pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */
194*4882a593Smuzhiyun pResult = pSelTimeout;
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun return pResult;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
map_select_results(struct pollfd * pArray,unsigned long n_fds,fd_set * pReadSet,fd_set * pWriteSet,fd_set * pExceptSet)202*4882a593Smuzhiyun static void map_select_results
203*4882a593Smuzhiyun (struct pollfd *pArray,
204*4882a593Smuzhiyun unsigned long n_fds,
205*4882a593Smuzhiyun fd_set *pReadSet,
206*4882a593Smuzhiyun fd_set *pWriteSet,
207*4882a593Smuzhiyun fd_set *pExceptSet)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun register unsigned long i; /* loop control */
210*4882a593Smuzhiyun register struct pollfd *pCur; /* current array element */
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun for (i = 0, pCur = pArray; i < n_fds; i++, pCur++)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun /* Skip any bad FDs in the array. */
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if (pCur->fd < 0)
217*4882a593Smuzhiyun continue;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* Exception events take priority over input events. */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun pCur->revents = 0;
222*4882a593Smuzhiyun if (FD_ISSET (pCur->fd, pExceptSet))
223*4882a593Smuzhiyun pCur->revents |= POLLPRI;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun else if (FD_ISSET (pCur->fd, pReadSet))
226*4882a593Smuzhiyun pCur->revents |= POLLIN;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (FD_ISSET (pCur->fd, pWriteSet))
229*4882a593Smuzhiyun pCur->revents |= POLLOUT;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /*---------------------------------------------------------------------------*\
236*4882a593Smuzhiyun Public Functions
237*4882a593Smuzhiyun \*---------------------------------------------------------------------------*/
238*4882a593Smuzhiyun
xserver_poll(struct pollfd * pArray,unsigned long n_fds,int timeout)239*4882a593Smuzhiyun int xserver_poll
240*4882a593Smuzhiyun (struct pollfd *pArray, unsigned long n_fds, int timeout)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun fd_set read_descs; /* input file descs */
243*4882a593Smuzhiyun fd_set write_descs; /* output file descs */
244*4882a593Smuzhiyun fd_set except_descs; /* exception descs */
245*4882a593Smuzhiyun struct timeval stime; /* select() timeout value */
246*4882a593Smuzhiyun int ready_descriptors; /* function result */
247*4882a593Smuzhiyun int max_fd; /* maximum fd value */
248*4882a593Smuzhiyun struct timeval *pTimeout; /* actually passed */
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun FD_ZERO (&read_descs);
251*4882a593Smuzhiyun FD_ZERO (&write_descs);
252*4882a593Smuzhiyun FD_ZERO (&except_descs);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun assert (pArray != (struct pollfd *) NULL);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /* Map the poll() file descriptor list in the select() data structures. */
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun max_fd = map_poll_spec (pArray, n_fds,
259*4882a593Smuzhiyun &read_descs, &write_descs, &except_descs);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun /* Map the poll() timeout value in the select() timeout structure. */
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun pTimeout = map_timeout (timeout, &stime);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /* Make the select() call. */
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun ready_descriptors = select (max_fd + 1, &read_descs, &write_descs,
268*4882a593Smuzhiyun &except_descs, pTimeout);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (ready_descriptors >= 0)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun map_select_results (pArray, n_fds,
273*4882a593Smuzhiyun &read_descs, &write_descs, &except_descs);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return ready_descriptors;
277*4882a593Smuzhiyun }
278