1 |
pcg |
1.1 |
/*---------------------------------------------------------------------------*\ |
2 |
|
|
$Id: poll.c,v 1.4 2003/01/01 19:02:29 bmc Exp $ |
3 |
|
|
|
4 |
|
|
NAME |
5 |
|
|
|
6 |
|
|
poll - select(2)-based poll() emulation function for BSD systems. |
7 |
|
|
|
8 |
|
|
SYNOPSIS |
9 |
|
|
#include "poll.h" |
10 |
|
|
|
11 |
|
|
struct pollfd |
12 |
|
|
{ |
13 |
|
|
int fd; |
14 |
|
|
short events; |
15 |
|
|
short revents; |
16 |
|
|
} |
17 |
|
|
|
18 |
|
|
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout) |
19 |
|
|
|
20 |
|
|
DESCRIPTION |
21 |
|
|
|
22 |
|
|
This file, and the accompanying "poll.h", implement the System V |
23 |
|
|
poll(2) system call for BSD systems (which typically do not provide |
24 |
|
|
poll()). Poll() provides a method for multiplexing input and output |
25 |
|
|
on multiple open file descriptors; in traditional BSD systems, that |
26 |
|
|
capability is provided by select(). While the semantics of select() |
27 |
|
|
differ from those of poll(), poll() can be readily emulated in terms |
28 |
|
|
of select() -- which is how this function is implemented. |
29 |
|
|
|
30 |
|
|
REFERENCES |
31 |
|
|
Stevens, W. Richard. Unix Network Programming. Prentice-Hall, 1990. |
32 |
|
|
|
33 |
|
|
NOTES |
34 |
|
|
1. This software requires an ANSI C compiler. |
35 |
|
|
|
36 |
|
|
LICENSE |
37 |
|
|
|
38 |
|
|
This software is released under the following license: |
39 |
|
|
|
40 |
|
|
Copyright (c) 1995-2002 Brian M. Clapper |
41 |
|
|
All rights reserved. |
42 |
|
|
|
43 |
|
|
Redistribution and use in source and binary forms are |
44 |
|
|
permitted provided that: (1) source distributions retain |
45 |
|
|
this entire copyright notice and comment; (2) modifications |
46 |
|
|
made to the software are prominently mentioned, and a copy |
47 |
|
|
of the original software (or a pointer to its location) are |
48 |
|
|
included; and (3) distributions including binaries display |
49 |
|
|
the following acknowledgement: "This product includes |
50 |
|
|
software developed by Brian M. Clapper <bmc@clapper.org>" |
51 |
|
|
in the documentation or other materials provided with the |
52 |
|
|
distribution. The name of the author may not be used to |
53 |
|
|
endorse or promote products derived from this software |
54 |
|
|
without specific prior written permission. |
55 |
|
|
|
56 |
|
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS |
57 |
|
|
OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE |
58 |
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
59 |
|
|
PARTICULAR PURPOSE. |
60 |
|
|
|
61 |
|
|
Effectively, this means you can do what you want with the software |
62 |
|
|
except remove this notice or take advantage of the author's name. |
63 |
|
|
If you modify the software and redistribute your modified version, |
64 |
|
|
you must indicate that your version is a modification of the |
65 |
|
|
original, and you must provide either a pointer to or a copy of the |
66 |
|
|
original. |
67 |
|
|
\*---------------------------------------------------------------------------*/ |
68 |
|
|
|
69 |
|
|
|
70 |
|
|
/*---------------------------------------------------------------------------*\ |
71 |
|
|
Includes |
72 |
|
|
\*---------------------------------------------------------------------------*/ |
73 |
|
|
|
74 |
|
|
#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL) |
75 |
|
|
|
76 |
|
|
#include <unistd.h> /* standard Unix definitions */ |
77 |
|
|
#include <sys/types.h> /* system types */ |
78 |
|
|
#include <sys/time.h> /* time definitions */ |
79 |
|
|
#include <assert.h> /* assertion macros */ |
80 |
|
|
#include <string.h> /* string functions */ |
81 |
|
|
#include "poll.h" /* this package */ |
82 |
|
|
|
83 |
|
|
/*---------------------------------------------------------------------------*\ |
84 |
|
|
Macros |
85 |
|
|
\*---------------------------------------------------------------------------*/ |
86 |
|
|
|
87 |
|
|
#ifndef MAX |
88 |
|
|
#define MAX(a,b) ((a) > (b) ? (a) : (b)) |
89 |
|
|
#endif |
90 |
|
|
|
91 |
|
|
|
92 |
|
|
/*---------------------------------------------------------------------------*\ |
93 |
|
|
Private Functions |
94 |
|
|
\*---------------------------------------------------------------------------*/ |
95 |
|
|
|
96 |
|
|
static int map_poll_spec |
97 |
|
|
#if __STDC__ > 0 |
98 |
|
|
(struct pollfd *pArray, |
99 |
|
|
unsigned long n_fds, |
100 |
|
|
fd_set *pReadSet, |
101 |
|
|
fd_set *pWriteSet, |
102 |
|
|
fd_set *pExceptSet) |
103 |
|
|
#else |
104 |
|
|
(pArray, n_fds, pReadSet, pWriteSet, pExceptSet) |
105 |
|
|
struct pollfd *pArray; |
106 |
|
|
unsigned long n_fds; |
107 |
|
|
fd_set *pReadSet; |
108 |
|
|
fd_set *pWriteSet; |
109 |
|
|
fd_set *pExceptSet; |
110 |
|
|
#endif |
111 |
|
|
{ |
112 |
|
|
register unsigned long i; /* loop control */ |
113 |
|
|
register struct pollfd *pCur; /* current array element */ |
114 |
|
|
register int max_fd = -1; /* return value */ |
115 |
|
|
|
116 |
|
|
/* |
117 |
|
|
Map the poll() structures into the file descriptor sets required |
118 |
|
|
by select(). |
119 |
|
|
*/ |
120 |
|
|
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) |
121 |
|
|
{ |
122 |
|
|
/* Skip any bad FDs in the array. */ |
123 |
|
|
|
124 |
|
|
if (pCur->fd < 0) |
125 |
|
|
continue; |
126 |
|
|
|
127 |
|
|
if (pCur->events & POLLIN) |
128 |
|
|
{ |
129 |
|
|
/* "Input Ready" notification desired. */ |
130 |
|
|
FD_SET (pCur->fd, pReadSet); |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
if (pCur->events & POLLOUT) |
134 |
|
|
{ |
135 |
|
|
/* "Output Possible" notification desired. */ |
136 |
|
|
FD_SET (pCur->fd, pWriteSet); |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
if (pCur->events & POLLPRI) |
140 |
|
|
{ |
141 |
|
|
/* |
142 |
|
|
"Exception Occurred" notification desired. (Exceptions |
143 |
|
|
include out of band data. |
144 |
|
|
*/ |
145 |
|
|
FD_SET (pCur->fd, pExceptSet); |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
max_fd = MAX (max_fd, pCur->fd); |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
return max_fd; |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
static struct timeval *map_timeout |
155 |
|
|
#if __STDC__ > 0 |
156 |
|
|
(int poll_timeout, struct timeval *pSelTimeout) |
157 |
|
|
#else |
158 |
|
|
(poll_timeout, pSelTimeout) |
159 |
|
|
int poll_timeout; |
160 |
|
|
struct timeval *pSelTimeout; |
161 |
|
|
#endif |
162 |
|
|
{ |
163 |
|
|
struct timeval *pResult; |
164 |
|
|
|
165 |
|
|
/* |
166 |
|
|
Map the poll() timeout value into a select() timeout. The possible |
167 |
|
|
values of the poll() timeout value, and their meanings, are: |
168 |
|
|
|
169 |
|
|
VALUE MEANING |
170 |
|
|
|
171 |
|
|
-1 wait indefinitely (until signal occurs) |
172 |
|
|
0 return immediately, don't block |
173 |
|
|
>0 wait specified number of milliseconds |
174 |
|
|
|
175 |
|
|
select() uses a "struct timeval", which specifies the timeout in |
176 |
|
|
seconds and microseconds, so the milliseconds value has to be mapped |
177 |
|
|
accordingly. |
178 |
|
|
*/ |
179 |
|
|
|
180 |
|
|
assert (pSelTimeout != (struct timeval *) NULL); |
181 |
|
|
|
182 |
|
|
switch (poll_timeout) |
183 |
|
|
{ |
184 |
|
|
case -1: |
185 |
|
|
/* |
186 |
|
|
A NULL timeout structure tells select() to wait indefinitely. |
187 |
|
|
*/ |
188 |
|
|
pResult = (struct timeval *) NULL; |
189 |
|
|
break; |
190 |
|
|
|
191 |
|
|
case 0: |
192 |
|
|
/* |
193 |
|
|
"Return immediately" (test) is specified by all zeros in |
194 |
|
|
a timeval structure. |
195 |
|
|
*/ |
196 |
|
|
pSelTimeout->tv_sec = 0; |
197 |
|
|
pSelTimeout->tv_usec = 0; |
198 |
|
|
pResult = pSelTimeout; |
199 |
|
|
break; |
200 |
|
|
|
201 |
|
|
default: |
202 |
|
|
/* Wait the specified number of milliseconds. */ |
203 |
|
|
pSelTimeout->tv_sec = poll_timeout / 1000; /* get seconds */ |
204 |
|
|
poll_timeout %= 1000; /* remove seconds */ |
205 |
|
|
pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */ |
206 |
|
|
pResult = pSelTimeout; |
207 |
|
|
break; |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
|
211 |
|
|
return pResult; |
212 |
|
|
} |
213 |
|
|
|
214 |
|
|
static void map_select_results |
215 |
|
|
#if __STDC__ > 0 |
216 |
|
|
(struct pollfd *pArray, |
217 |
|
|
unsigned long n_fds, |
218 |
|
|
fd_set *pReadSet, |
219 |
|
|
fd_set *pWriteSet, |
220 |
|
|
fd_set *pExceptSet) |
221 |
|
|
#else |
222 |
|
|
(pArray, n_fds, pReadSet, pWriteSet, pExceptSet) |
223 |
|
|
struct pollfd *pArray; |
224 |
|
|
unsigned long n_fds; |
225 |
|
|
fd_set *pReadSet; |
226 |
|
|
fd_set *pWriteSet; |
227 |
|
|
fd_set *pExceptSet; |
228 |
|
|
#endif |
229 |
|
|
{ |
230 |
|
|
register unsigned long i; /* loop control */ |
231 |
|
|
register struct pollfd *pCur; /* current array element */ |
232 |
|
|
|
233 |
|
|
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) |
234 |
|
|
{ |
235 |
|
|
/* Skip any bad FDs in the array. */ |
236 |
|
|
|
237 |
|
|
if (pCur->fd < 0) |
238 |
|
|
continue; |
239 |
|
|
|
240 |
|
|
/* Exception events take priority over input events. */ |
241 |
|
|
|
242 |
|
|
pCur->revents = 0; |
243 |
|
|
if (FD_ISSET (pCur->fd, pExceptSet)) |
244 |
|
|
pCur->revents |= POLLPRI; |
245 |
|
|
|
246 |
|
|
else if (FD_ISSET (pCur->fd, pReadSet)) |
247 |
|
|
pCur->revents |= POLLIN; |
248 |
|
|
|
249 |
|
|
if (FD_ISSET (pCur->fd, pWriteSet)) |
250 |
|
|
pCur->revents |= POLLOUT; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
return; |
254 |
|
|
} |
255 |
|
|
|
256 |
|
|
/*---------------------------------------------------------------------------*\ |
257 |
|
|
Public Functions |
258 |
|
|
\*---------------------------------------------------------------------------*/ |
259 |
|
|
|
260 |
|
|
int poll |
261 |
|
|
|
262 |
|
|
#if __STDC__ > 0 |
263 |
|
|
(struct pollfd *pArray, unsigned long n_fds, int timeout) |
264 |
|
|
#else |
265 |
|
|
(pArray, n_fds, timeout) |
266 |
|
|
struct pollfd *pArray; |
267 |
|
|
unsigned long n_fds; |
268 |
|
|
int timeout; |
269 |
|
|
#endif |
270 |
|
|
|
271 |
|
|
{ |
272 |
|
|
fd_set read_descs; /* input file descs */ |
273 |
|
|
fd_set write_descs; /* output file descs */ |
274 |
|
|
fd_set except_descs; /* exception descs */ |
275 |
|
|
struct timeval stime; /* select() timeout value */ |
276 |
|
|
int ready_descriptors; /* function result */ |
277 |
|
|
int max_fd; /* maximum fd value */ |
278 |
|
|
struct timeval *pTimeout; /* actually passed */ |
279 |
|
|
|
280 |
|
|
FD_ZERO (&read_descs); |
281 |
|
|
FD_ZERO (&write_descs); |
282 |
|
|
FD_ZERO (&except_descs); |
283 |
|
|
|
284 |
|
|
assert (pArray != (struct pollfd *) NULL); |
285 |
|
|
|
286 |
|
|
/* Map the poll() file descriptor list in the select() data structures. */ |
287 |
|
|
|
288 |
|
|
max_fd = map_poll_spec (pArray, n_fds, |
289 |
|
|
&read_descs, &write_descs, &except_descs); |
290 |
|
|
|
291 |
|
|
/* Map the poll() timeout value in the select() timeout structure. */ |
292 |
|
|
|
293 |
|
|
pTimeout = map_timeout (timeout, &stime); |
294 |
|
|
|
295 |
|
|
/* Make the select() call. */ |
296 |
|
|
|
297 |
|
|
ready_descriptors = select (max_fd + 1, &read_descs, &write_descs, |
298 |
|
|
&except_descs, pTimeout); |
299 |
|
|
|
300 |
|
|
if (ready_descriptors >= 0) |
301 |
|
|
{ |
302 |
|
|
map_select_results (pArray, n_fds, |
303 |
|
|
&read_descs, &write_descs, &except_descs); |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
return ready_descriptors; |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
#endif |
310 |
|
|
|