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