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 |
|