Asterisk - The Open Source Telephony Project GIT-master-a358458
poll.c
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 $Id$
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#include "asterisk.h"
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 <errno.h>
82
83#include "asterisk/utils.h" /* this package */
84#include "asterisk/poll-compat.h" /* this package */
85
86unsigned int ast_FD_SETSIZE = FD_SETSIZE;
87
88#ifndef MAX
89#define MAX(a,b) a > b ? a : b
90#endif
91
92/*---------------------------------------------------------------------------*\
93 Private Functions
94\*---------------------------------------------------------------------------*/
95
96#if defined(AST_POLL_COMPAT)
97static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
98 ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
99{
100 register unsigned long i; /* loop control */
101 register struct pollfd *pCur; /* current array element */
102 register int max_fd = -1; /* return value */
103
104 /*
105 * Map the poll() structures into the file descriptor sets required
106 * by select().
107 */
108 for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
109 /* Skip any bad FDs in the array. */
110
111 if (pCur->fd < 0) {
112 continue;
113 }
114
115 if (pCur->events & POLLIN) {
116 /* "Input Ready" notification desired. */
117 FD_SET(pCur->fd, pReadSet);
118 }
119
120 if (pCur->events & POLLOUT) {
121 /* "Output Possible" notification desired. */
122 FD_SET(pCur->fd, pWriteSet);
123 }
124
125 if (pCur->events & POLLPRI) {
126 /*!\note
127 * "Exception Occurred" notification desired. (Exceptions
128 * include out of band data.)
129 */
130 FD_SET(pCur->fd, pExceptSet);
131 }
132
133 max_fd = MAX(max_fd, pCur->fd);
134 }
135
136 return max_fd;
137}
138
139#ifdef AST_POLL_COMPAT
140static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
141{
142 struct timeval *pResult;
143
144 /*
145 Map the poll() timeout value into a select() timeout. The possible
146 values of the poll() timeout value, and their meanings, are:
147
148 VALUE MEANING
149
150 -1 wait indefinitely (until signal occurs)
151 0 return immediately, don't block
152 >0 wait specified number of milliseconds
153
154 select() uses a "struct timeval", which specifies the timeout in
155 seconds and microseconds, so the milliseconds value has to be mapped
156 accordingly.
157 */
158
159 assert(pSelTimeout != NULL);
160
161 switch (poll_timeout) {
162 case -1:
163 /*
164 * A NULL timeout structure tells select() to wait indefinitely.
165 */
166 pResult = (struct timeval *) NULL;
167 break;
168
169 case 0:
170 /*
171 * "Return immediately" (test) is specified by all zeros in
172 * a timeval structure.
173 */
174 pSelTimeout->tv_sec = 0;
175 pSelTimeout->tv_usec = 0;
176 pResult = pSelTimeout;
177 break;
178
179 default:
180 /* Wait the specified number of milliseconds. */
181 pSelTimeout->tv_sec = poll_timeout / 1000; /* get seconds */
182 poll_timeout %= 1000; /* remove seconds */
183 pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */
184 pResult = pSelTimeout;
185 break;
186 }
187
188 return pResult;
189}
190#endif /* AST_POLL_COMPAT */
191
192static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
193 ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
194{
195 register unsigned long i; /* loop control */
196 register struct pollfd *pCur; /* current array element */
197
198 for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
199 /* Skip any bad FDs in the array. */
200
201 if (pCur->fd < 0) {
202 continue;
203 }
204
205 /* Exception events take priority over input events. */
206 pCur->revents = 0;
207 if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
208 pCur->revents |= POLLPRI;
209 } else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
210 pCur->revents |= POLLIN;
211 }
212
213 if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
214 pCur->revents |= POLLOUT;
215 }
216 }
217
218 return;
219}
220#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
221
222/*---------------------------------------------------------------------------*\
223 Public Functions
224\*---------------------------------------------------------------------------*/
225#ifdef AST_POLL_COMPAT
226int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
227{
228 ast_fdset read_descs; /* input file descs */
229 ast_fdset write_descs; /* output file descs */
230 ast_fdset except_descs; /* exception descs */
231 struct timeval stime; /* select() timeout value */
232 int ready_descriptors; /* function result */
233 int max_fd = 0; /* maximum fd value */
234 struct timeval *pTimeout; /* actually passed */
235 int save_errno;
236
237 FD_ZERO(&read_descs);
238 FD_ZERO(&write_descs);
239 FD_ZERO(&except_descs);
240
241 /* Map the poll() file descriptor list in the select() data structures. */
242
243 if (pArray) {
244 max_fd = map_poll_spec (pArray, n_fds,
245 &read_descs, &write_descs, &except_descs);
246 }
247
248 /* Map the poll() timeout value in the select() timeout structure. */
249
250 pTimeout = map_timeout (timeout, &stime);
251
252 /* Make the select() call. */
253
254 ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
255 &except_descs, pTimeout);
256 save_errno = errno;
257
258 if (ready_descriptors >= 0) {
259 map_select_results (pArray, n_fds,
260 &read_descs, &write_descs, &except_descs);
261 }
262
263 errno = save_errno;
264 return ready_descriptors;
265}
266#endif /* AST_POLL_COMPAT */
267
268int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
269{
270#if !defined(AST_POLL_COMPAT)
271 struct timeval start = ast_tvnow();
272#if defined(HAVE_PPOLL)
273 struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
274 int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
275#else
276 int res = poll(pArray, n_fds, tv ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1);
277#endif
278 struct timeval after = ast_tvnow();
279 if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) {
280 *tv = ast_tvsub(*tv, ast_tvsub(after, start));
281 } else if (res > 0 && tv) {
282 *tv = ast_tv(0, 0);
283 }
284 return res;
285#else
286 ast_fdset read_descs, write_descs, except_descs;
287 int ready_descriptors, max_fd = 0;
288
289 FD_ZERO(&read_descs);
290 FD_ZERO(&write_descs);
291 FD_ZERO(&except_descs);
292
293 if (pArray) {
294 max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs);
295 }
296
297 ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv);
298
299 if (ready_descriptors >= 0) {
300 map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
301 }
302
303 return ready_descriptors;
304#endif
305}
Asterisk main include file. File version handling, generic pbx functions.
int errno
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
Same as poll(2), except the time is specified in microseconds and the tv argument is modified to indi...
Definition: poll.c:268
unsigned int ast_FD_SETSIZE
Definition: poll.c:86
#define NULL
Definition: resample.c:96
#define FD_SET(fd, fds)
Definition: select.h:58
static int ast_select(int nfds, ast_fdset *rfds, ast_fdset *wfds, ast_fdset *efds, struct timeval *tvp)
Waits for activity on a group of channels.
Definition: select.h:79
#define FD_ZERO(a)
Definition: select.h:49
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
Utility functions.
#define MAX(a, b)
Definition: utils.h:233