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