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