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