app_dial: Allow macro/gosub pre-bridge execution to occur on priorities
[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 #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 }
306
307