Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>"
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 
86 unsigned 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)
97 static 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
140 static 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 
192 static 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
226 int 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 
268 int 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.
static int timeout
Definition: cdr_mysql.c:86
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define NULL
Definition: resample.c:96
Utility functions.
#define FD_ZERO(a)
Definition: select.h:49
#define FD_SET(fd, fds)
Definition: select.h:58
unsigned int ast_FD_SETSIZE
Definition: poll.c:86
#define MAX(a, b)
Definition: utils.h:228
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
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
int errno
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2298