Let ExtensionState resolve dynamic hints.
[asterisk/asterisk.git] / main / poll.c
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
82 #include "asterisk/utils.h"                            /* this package */
83 #include "asterisk/poll-compat.h"                            /* this package */
84
85 #ifdef AST_POLL_COMPAT
86
87 #ifndef MAX
88 #define MAX(a,b)        a > b ? a : b
89 #endif
90
91 /*---------------------------------------------------------------------------*\
92                              Private Functions
93 \*---------------------------------------------------------------------------*/
94
95 static int map_poll_spec
96 #if __STDC__ > 0
97                         (struct pollfd *pArray,
98                           unsigned long  n_fds,
99                           fd_set        *pReadSet,
100                           fd_set        *pWriteSet,
101                           fd_set        *pExceptSet)
102 #else
103                          (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
104                           struct pollfd *pArray;
105                           unsigned long  n_fds;
106                           fd_set        *pReadSet;
107                           fd_set        *pWriteSet;
108                           fd_set        *pExceptSet;
109 #endif
110 {
111         register unsigned long  i;                   /* loop control */
112         register struct     pollfd *pCur;        /* current array element */
113         register int        max_fd = -1;         /* return value */
114
115         /*!\note
116          * Map the poll() structures into the file descriptor sets required
117          * by select().
118          */
119         for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
120                 /* Skip any bad FDs in the array. */
121
122                 if (pCur->fd < 0)
123                         continue;
124
125                 if (pCur->events & POLLIN) {
126                         /* "Input Ready" notification desired. */
127                         FD_SET(pCur->fd, pReadSet);
128                 }
129
130                 if (pCur->events & POLLOUT) {
131                         /* "Output Possible" notification desired. */
132                         FD_SET(pCur->fd, pWriteSet);
133                 }
134
135                 if (pCur->events & POLLPRI) {
136                         /*!\note
137                          * "Exception Occurred" notification desired.  (Exceptions
138                          * include out of band data.)
139                          */
140                         FD_SET(pCur->fd, pExceptSet);
141                 }
142
143                 max_fd = MAX(max_fd, pCur->fd);
144         }
145
146         return max_fd;
147 }
148 \f
149 static struct timeval *map_timeout
150 #if __STDC__ > 0
151                         (int poll_timeout, struct timeval *pSelTimeout)
152 #else
153                         (poll_timeout, pSelTimeout)
154                          int             poll_timeout;
155                          struct timeval *pSelTimeout;
156 #endif
157 {
158         struct timeval *pResult;
159
160         /*!\note
161          * Map the poll() timeout value into a select() timeout.  The possible
162          * values of the poll() timeout value, and their meanings, are:
163          *
164          * VALUE        MEANING
165          *
166          * -1   wait indefinitely (until signal occurs)
167          *  0   return immediately, don't block
168          * >0   wait specified number of milliseconds
169          *
170          * select() uses a "struct timeval", which specifies the timeout in
171          * seconds and microseconds, so the milliseconds value has to be mapped
172          * accordingly.
173          */
174
175         assert(pSelTimeout != (struct timeval *) NULL);
176
177         switch (poll_timeout) {
178         case -1:
179                 /*
180                  * A NULL timeout structure tells select() to wait indefinitely.
181                  */
182                 pResult = (struct timeval *) NULL;
183                 break;
184
185         case 0:
186                 /*
187                  * "Return immediately" (test) is specified by all zeros in
188                  * a timeval structure.
189                  */
190                 pSelTimeout->tv_sec  = 0;
191                 pSelTimeout->tv_usec = 0;
192                 pResult = pSelTimeout;
193                 break;
194
195         default:
196                 /* Wait the specified number of milliseconds. */
197                 pSelTimeout->tv_sec  = poll_timeout / 1000; /* get seconds */
198                 poll_timeout        %= 1000;                /* remove seconds */
199                 pSelTimeout->tv_usec = poll_timeout * 1000; /* get microseconds */
200                 pResult = pSelTimeout;
201                 break;
202         }
203
204         return pResult;
205 }
206
207 static void map_select_results
208 #if __STDC__ > 0
209                          (struct pollfd *pArray,
210                           unsigned long  n_fds,
211                           fd_set        *pReadSet,
212                           fd_set        *pWriteSet,
213                           fd_set        *pExceptSet)
214 #else
215                          (pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
216                           struct pollfd *pArray;
217                           unsigned long  n_fds;
218                           fd_set        *pReadSet;
219                           fd_set        *pWriteSet;
220                           fd_set        *pExceptSet;
221 #endif
222 {
223         register unsigned long  i;                   /* loop control */
224         register struct     pollfd *pCur;        /* current array element */
225
226         for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
227                 /* Skip any bad FDs in the array. */
228
229                 if (pCur->fd < 0) {
230                         continue;
231                 }
232
233                 /* Exception events take priority over input events. */
234
235                 pCur->revents = 0;
236                 if (FD_ISSET (pCur->fd, pExceptSet)) {
237                         pCur->revents |= POLLPRI;
238                 } else if (FD_ISSET (pCur->fd, pReadSet)) {
239                         pCur->revents |= POLLIN;
240                 }
241
242                 if (FD_ISSET (pCur->fd, pWriteSet)) {
243                         pCur->revents |= POLLOUT;
244                 }
245         }
246
247         return;
248 }
249
250 /*---------------------------------------------------------------------------*\
251                              Public Functions
252 \*---------------------------------------------------------------------------*/
253
254 int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
255 {
256         fd_set  read_descs;                          /* input file descs */
257         fd_set  write_descs;                         /* output file descs */
258         fd_set  except_descs;                        /* exception descs */
259         struct  timeval stime;                       /* select() timeout value */
260         int         ready_descriptors;                   /* function result */
261         int         max_fd = 0;                          /* maximum fd value */
262         struct  timeval *pTimeout;                   /* actually passed */
263
264         FD_ZERO (&read_descs);
265         FD_ZERO (&write_descs);
266         FD_ZERO (&except_descs);
267
268         /* Map the poll() file descriptor list in the select() data structures. */
269
270         if (pArray) {
271         max_fd = map_poll_spec (pArray, n_fds,
272                                 &read_descs, &write_descs, &except_descs);
273         }
274
275         /* Map the poll() timeout value in the select() timeout structure. */
276         pTimeout = map_timeout(timeout, &stime);
277
278         /* Make the select() call. */
279         ready_descriptors = select(max_fd + 1, &read_descs, &write_descs,
280                                 &except_descs, pTimeout);
281
282         if (ready_descriptors >= 0) {
283                 map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
284         }
285
286         return ready_descriptors;
287 }
288
289 #endif /* AST_POLL_COMPAT */