]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr/poll/unix/select.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr / poll / unix / select.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifdef WIN32
18 /* POSIX defines 1024 for the FD_SETSIZE */
19 #define FD_SETSIZE 1024
20 #endif
21
22 #include "apr.h"
23 #include "apr_poll.h"
24 #include "apr_time.h"
25 #include "apr_portable.h"
26 #include "apr_arch_file_io.h"
27 #include "apr_arch_networkio.h"
28 #include "apr_arch_poll_private.h"
29
30 #ifdef POLL_USES_SELECT
31
32 APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num,
33                                    apr_int32_t *nsds,
34                                    apr_interval_time_t timeout)
35 {
36     fd_set readset, writeset, exceptset;
37     int rv, i;
38     int maxfd = -1;
39     struct timeval tv, *tvptr;
40 #ifdef NETWARE
41     apr_datatype_e set_type = APR_NO_DESC;
42 #endif
43
44 #ifdef WIN32
45     /* On Win32, select() must be presented with at least one socket to
46      * poll on, or select() will return WSAEINVAL.  So, we'll just
47      * short-circuit and bail now.
48      */
49     if (num == 0) {
50         (*nsds) = 0;
51         if (timeout > 0) {
52             apr_sleep(timeout);
53             return APR_TIMEUP;
54         }
55         return APR_SUCCESS;
56     }
57 #endif
58
59     if (timeout < 0) {
60         tvptr = NULL;
61     }
62     else {
63         tv.tv_sec = (long) apr_time_sec(timeout);
64         tv.tv_usec = (long) apr_time_usec(timeout);
65         tvptr = &tv;
66     }
67
68     FD_ZERO(&readset);
69     FD_ZERO(&writeset);
70     FD_ZERO(&exceptset);
71
72     for (i = 0; i < num; i++) {
73         apr_os_sock_t fd;
74
75         aprset[i].rtnevents = 0;
76
77         if (aprset[i].desc_type == APR_POLL_SOCKET) {
78 #ifdef NETWARE
79             if (HAS_PIPES(set_type)) {
80                 return APR_EBADF;
81             }
82             else {
83                 set_type = APR_POLL_SOCKET;
84             }
85 #endif
86             fd = aprset[i].desc.s->socketdes;
87         }
88         else if (aprset[i].desc_type == APR_POLL_FILE) {
89 #if !APR_FILES_AS_SOCKETS
90             return APR_EBADF;
91 #else
92 #ifdef NETWARE
93             if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
94                 set_type = APR_POLL_FILE;
95             }
96             else
97                 return APR_EBADF;
98 #endif /* NETWARE */
99
100             fd = aprset[i].desc.f->filedes;
101
102 #endif /* APR_FILES_AS_SOCKETS */
103         }
104         else {
105             break;
106         }
107 #if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
108         if (fd >= FD_SETSIZE) {
109             /* XXX invent new error code so application has a clue */
110             return APR_EBADF;
111         }
112 #endif
113         if (aprset[i].reqevents & APR_POLLIN) {
114             FD_SET(fd, &readset);
115         }
116         if (aprset[i].reqevents & APR_POLLOUT) {
117             FD_SET(fd, &writeset);
118         }
119         if (aprset[i].reqevents &
120             (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
121             FD_SET(fd, &exceptset);
122         }
123         if ((int) fd > maxfd) {
124             maxfd = (int) fd;
125         }
126     }
127
128 #ifdef NETWARE
129     if (HAS_PIPES(set_type)) {
130         rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
131     }
132     else {
133 #endif
134
135         rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
136
137 #ifdef NETWARE
138     }
139 #endif
140
141     (*nsds) = rv;
142     if ((*nsds) == 0) {
143         return APR_TIMEUP;
144     }
145     if ((*nsds) < 0) {
146         return apr_get_netos_error();
147     }
148
149     (*nsds) = 0;
150     for (i = 0; i < num; i++) {
151         apr_os_sock_t fd;
152
153         if (aprset[i].desc_type == APR_POLL_SOCKET) {
154             fd = aprset[i].desc.s->socketdes;
155         }
156         else if (aprset[i].desc_type == APR_POLL_FILE) {
157 #if !APR_FILES_AS_SOCKETS
158             return APR_EBADF;
159 #else
160             fd = aprset[i].desc.f->filedes;
161 #endif
162         }
163         else {
164             break;
165         }
166         if (FD_ISSET(fd, &readset)) {
167             aprset[i].rtnevents |= APR_POLLIN;
168         }
169         if (FD_ISSET(fd, &writeset)) {
170             aprset[i].rtnevents |= APR_POLLOUT;
171         }
172         if (FD_ISSET(fd, &exceptset)) {
173             aprset[i].rtnevents |= APR_POLLERR;
174         }
175         if (aprset[i].rtnevents) {
176             (*nsds)++;
177         }
178     }
179
180     return APR_SUCCESS;
181 }
182
183 #endif /* POLL_USES_SELECT */
184
185 struct apr_pollset_private_t
186 {
187     fd_set readset, writeset, exceptset;
188     int maxfd;
189     apr_pollfd_t *query_set;
190     apr_pollfd_t *result_set;
191     apr_uint32_t flags;
192 #ifdef NETWARE
193     int set_type;
194 #endif
195 };
196
197 static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
198                                         apr_uint32_t size,
199                                         apr_pool_t *p,
200                                         apr_uint32_t flags)
201 {
202     if (flags & APR_POLLSET_THREADSAFE) {                
203         pollset->p = NULL;
204         return APR_ENOTIMPL;
205     }
206 #ifdef FD_SETSIZE
207     if (size > FD_SETSIZE) {
208         pollset->p = NULL;
209         return APR_EINVAL;
210     }
211 #endif
212     pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
213     FD_ZERO(&(pollset->p->readset));
214     FD_ZERO(&(pollset->p->writeset));
215     FD_ZERO(&(pollset->p->exceptset));
216     pollset->p->maxfd = 0;
217 #ifdef NETWARE
218     pollset->p->set_type = APR_NO_DESC;
219 #endif
220     pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
221     pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
222
223     return APR_SUCCESS;
224 }
225
226 static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
227                                      const apr_pollfd_t *descriptor)
228 {
229     apr_os_sock_t fd;
230
231     if (pollset->nelts == pollset->nalloc) {
232         return APR_ENOMEM;
233     }
234
235     pollset->p->query_set[pollset->nelts] = *descriptor;
236
237     if (descriptor->desc_type == APR_POLL_SOCKET) {
238 #ifdef NETWARE
239         /* NetWare can't handle mixed descriptor types in select() */
240         if (HAS_PIPES(pollset->p->set_type)) {
241             return APR_EBADF;
242         }
243         else {
244             pollset->p->set_type = APR_POLL_SOCKET;
245         }
246 #endif
247         fd = descriptor->desc.s->socketdes;
248     }
249     else {
250 #if !APR_FILES_AS_SOCKETS
251         if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
252             descriptor->desc.f == pollset->wakeup_pipe[0])
253             fd = (apr_os_sock_t)descriptor->desc.f->filedes;
254         else
255             return APR_EBADF;
256 #else
257 #ifdef NETWARE
258         /* NetWare can't handle mixed descriptor types in select() */
259         if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->p->set_type)) {
260             pollset->p->set_type = APR_POLL_FILE;
261             fd = descriptor->desc.f->filedes;
262         }
263         else {
264             return APR_EBADF;
265         }
266 #else
267         fd = descriptor->desc.f->filedes;
268 #endif
269 #endif
270     }
271 #if !defined(WIN32) && !defined(NETWARE)        /* socket sets handled with array of handles */
272     if (fd >= FD_SETSIZE) {
273         /* XXX invent new error code so application has a clue */
274         return APR_EBADF;
275     }
276 #endif
277     if (descriptor->reqevents & APR_POLLIN) {
278         FD_SET(fd, &(pollset->p->readset));
279     }
280     if (descriptor->reqevents & APR_POLLOUT) {
281         FD_SET(fd, &(pollset->p->writeset));
282     }
283     if (descriptor->reqevents &
284         (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
285         FD_SET(fd, &(pollset->p->exceptset));
286     }
287     if ((int) fd > pollset->p->maxfd) {
288         pollset->p->maxfd = (int) fd;
289     }
290     pollset->nelts++;
291     return APR_SUCCESS;
292 }
293
294 static apr_status_t impl_pollset_remove(apr_pollset_t * pollset,
295                                         const apr_pollfd_t * descriptor)
296 {
297     apr_uint32_t i;
298     apr_os_sock_t fd;
299
300     if (descriptor->desc_type == APR_POLL_SOCKET) {
301         fd = descriptor->desc.s->socketdes;
302     }
303     else {
304 #if !APR_FILES_AS_SOCKETS
305         return APR_EBADF;
306 #else
307         fd = descriptor->desc.f->filedes;
308 #endif
309     }
310
311     for (i = 0; i < pollset->nelts; i++) {
312         if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
313             /* Found an instance of the fd: remove this and any other copies */
314             apr_uint32_t dst = i;
315             apr_uint32_t old_nelts = pollset->nelts;
316             pollset->nelts--;
317             for (i++; i < old_nelts; i++) {
318                 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
319                     pollset->nelts--;
320                 }
321                 else {
322                     pollset->p->query_set[dst] = pollset->p->query_set[i];
323                     dst++;
324                 }
325             }
326             FD_CLR(fd, &(pollset->p->readset));
327             FD_CLR(fd, &(pollset->p->writeset));
328             FD_CLR(fd, &(pollset->p->exceptset));
329             if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) {
330                 pollset->p->maxfd--;
331             }
332             return APR_SUCCESS;
333         }
334     }
335
336     return APR_NOTFOUND;
337 }
338
339 static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
340                                       apr_interval_time_t timeout,
341                                       apr_int32_t *num,
342                                       const apr_pollfd_t **descriptors)
343 {
344     int rs;
345     apr_uint32_t i, j;
346     struct timeval tv, *tvptr;
347     fd_set readset, writeset, exceptset;
348     apr_status_t rv = APR_SUCCESS;
349
350 #ifdef WIN32
351     /* On Win32, select() must be presented with at least one socket to
352      * poll on, or select() will return WSAEINVAL.  So, we'll just
353      * short-circuit and bail now.
354      */
355     if (pollset->nelts == 0) {
356         (*num) = 0;
357         if (timeout > 0) {
358             apr_sleep(timeout);
359             return APR_TIMEUP;
360         }
361         return APR_SUCCESS;
362     }
363 #endif
364
365     if (timeout < 0) {
366         tvptr = NULL;
367     }
368     else {
369         tv.tv_sec = (long) apr_time_sec(timeout);
370         tv.tv_usec = (long) apr_time_usec(timeout);
371         tvptr = &tv;
372     }
373
374     memcpy(&readset, &(pollset->p->readset), sizeof(fd_set));
375     memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set));
376     memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set));
377
378 #ifdef NETWARE
379     if (HAS_PIPES(pollset->p->set_type)) {
380         rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
381                          tvptr);
382     }
383     else
384 #endif
385         rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
386                     tvptr);
387
388     (*num) = rs;
389     if (rs < 0) {
390         return apr_get_netos_error();
391     }
392     if (rs == 0) {
393         return APR_TIMEUP;
394     }
395     j = 0;
396     for (i = 0; i < pollset->nelts; i++) {
397         apr_os_sock_t fd;
398         if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) {
399             fd = pollset->p->query_set[i].desc.s->socketdes;
400         }
401         else {
402             if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
403                 pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
404                 apr_pollset_drain_wakeup_pipe(pollset);
405                 rv = APR_EINTR;
406                 continue;
407             }
408             else {
409 #if !APR_FILES_AS_SOCKETS
410                 return APR_EBADF;
411 #else
412                 fd = pollset->p->query_set[i].desc.f->filedes;
413 #endif
414             }
415         }
416         if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
417             FD_ISSET(fd, &exceptset)) {
418             pollset->p->result_set[j] = pollset->p->query_set[i];
419             pollset->p->result_set[j].rtnevents = 0;
420             if (FD_ISSET(fd, &readset)) {
421                 pollset->p->result_set[j].rtnevents |= APR_POLLIN;
422             }
423             if (FD_ISSET(fd, &writeset)) {
424                 pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
425             }
426             if (FD_ISSET(fd, &exceptset)) {
427                 pollset->p->result_set[j].rtnevents |= APR_POLLERR;
428             }
429             j++;
430         }
431     }
432     if (((*num) = j) != 0)
433         rv = APR_SUCCESS;
434
435     if (descriptors)
436         *descriptors = pollset->p->result_set;
437     return rv;
438 }
439
440 static apr_pollset_provider_t impl = {
441     impl_pollset_create,
442     impl_pollset_add,
443     impl_pollset_remove,
444     impl_pollset_poll,
445     NULL,
446     "select"
447 };
448
449 apr_pollset_provider_t *apr_pollset_provider_select = &impl;