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