bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / poll / unix / poll.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 #include "apr.h"
18 #include "apr_poll.h"
19 #include "apr_time.h"
20 #include "apr_portable.h"
21 #include "apr_arch_networkio.h"
22 #include "apr_arch_file_io.h"
23 #if HAVE_POLL_H
24 #include <poll.h>
25 #endif
26 #if HAVE_SYS_POLL_H
27 #include <sys/poll.h>
28 #endif
29 #if HAVE_ALLOCA_H
30 #include <alloca.h>
31 #endif
32
33 #ifdef NETWARE
34 #define HAS_SOCKETS(dt) (dt == APR_POLL_SOCKET) ? 1 : 0
35 #define HAS_PIPES(dt) (dt == APR_POLL_FILE) ? 1 : 0
36 #endif
37
38 #ifdef HAVE_POLL    /* We can just use poll to do our socket polling. */
39
40 static apr_int16_t get_event(apr_int16_t event)
41 {
42     apr_int16_t rv = 0;
43
44     if (event & APR_POLLIN)
45         rv |= POLLIN;        
46     if (event & APR_POLLPRI)
47         rv |= POLLPRI;        
48     if (event & APR_POLLOUT)
49         rv |= POLLOUT;       
50     if (event & APR_POLLERR)
51         rv |= POLLERR;        
52     if (event & APR_POLLHUP)
53         rv |= POLLHUP;        
54     if (event & APR_POLLNVAL)
55         rv |= POLLNVAL;        
56
57     return rv;
58 }
59
60 static apr_int16_t get_revent(apr_int16_t event)
61 {
62     apr_int16_t rv = 0;
63
64     if (event & POLLIN)
65         rv |= APR_POLLIN;
66     if (event & POLLPRI)
67         rv |= APR_POLLPRI;
68     if (event & POLLOUT)
69         rv |= APR_POLLOUT;
70     if (event & POLLERR)
71         rv |= APR_POLLERR;
72     if (event & POLLHUP)
73         rv |= APR_POLLHUP;
74     if (event & POLLNVAL)
75         rv |= APR_POLLNVAL;
76
77     return rv;
78 }        
79
80 #define SMALL_POLLSET_LIMIT  8
81
82 APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num,
83                       apr_int32_t *nsds, apr_interval_time_t timeout)
84 {
85     int i, num_to_poll;
86 #ifdef HAVE_VLA
87     /* XXX: I trust that this is a segv when insufficient stack exists? */
88     struct pollfd pollset[num];
89 #elif defined(HAVE_ALLOCA)
90     struct pollfd *pollset = alloca(sizeof(struct pollfd) * num);
91     if (!pollset)
92         return APR_ENOMEM;
93 #else
94     struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT];
95     struct pollfd *pollset;
96
97     if (num <= SMALL_POLLSET_LIMIT) {
98         pollset = tmp_pollset;
99     }
100     else {
101         /* This does require O(n) to copy the descriptors to the internal
102          * mapping.
103          */
104         pollset = malloc(sizeof(struct pollfd) * num);
105         /* The other option is adding an apr_pool_abort() fn to invoke
106          * the pool's out of memory handler
107          */
108         if (!pollset)
109             return APR_ENOMEM;
110     }
111 #endif
112     for (i = 0; i < num; i++) {
113         if (aprset[i].desc_type == APR_POLL_SOCKET) {
114             pollset[i].fd = aprset[i].desc.s->socketdes;
115         }
116         else if (aprset[i].desc_type == APR_POLL_FILE) {
117             pollset[i].fd = aprset[i].desc.f->filedes;
118         }
119         else {
120             break;
121         }
122         pollset[i].events = get_event(aprset[i].reqevents);
123     }
124     num_to_poll = i;
125
126     if (timeout > 0) {
127         timeout /= 1000; /* convert microseconds to milliseconds */
128     }
129
130     i = poll(pollset, num_to_poll, timeout);
131     (*nsds) = i;
132
133     for (i = 0; i < num; i++) {
134         aprset[i].rtnevents = get_revent(pollset[i].revents);
135     }
136     
137 #if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA)
138     if (num > SMALL_POLLSET_LIMIT) {
139         free(pollset);
140     }
141 #endif
142
143     if ((*nsds) < 0) {
144         return apr_get_netos_error();
145     }
146     if ((*nsds) == 0) {
147         return APR_TIMEUP;
148     }
149     return APR_SUCCESS;
150 }
151
152
153 #else    /* Use select to mimic poll */
154
155 APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num, apr_int32_t *nsds, 
156                     apr_interval_time_t timeout)
157 {
158     fd_set readset, writeset, exceptset;
159     int rv, i;
160     int maxfd = -1;
161     struct timeval tv, *tvptr;
162 #ifdef NETWARE
163     apr_datatype_e set_type = APR_NO_DESC;
164 #endif
165
166     if (timeout < 0) {
167         tvptr = NULL;
168     }
169     else {
170         tv.tv_sec = (long)apr_time_sec(timeout);
171         tv.tv_usec = (long)apr_time_usec(timeout);
172         tvptr = &tv;
173     }
174
175     FD_ZERO(&readset);
176     FD_ZERO(&writeset);
177     FD_ZERO(&exceptset);
178
179     for (i = 0; i < num; i++) {
180         apr_os_sock_t fd;
181
182         aprset[i].rtnevents = 0;
183
184         if (aprset[i].desc_type == APR_POLL_SOCKET) {
185 #ifdef NETWARE
186             if (HAS_PIPES(set_type)) {
187                 return APR_EBADF;
188             }
189             else {
190                 set_type = APR_POLL_SOCKET;
191             }
192 #endif
193             fd = aprset[i].desc.s->socketdes;
194         }
195         else if (aprset[i].desc_type == APR_POLL_FILE) {
196 #if !APR_FILES_AS_SOCKETS
197             return APR_EBADF;
198 #else
199 #ifdef NETWARE
200             if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
201                 set_type = APR_POLL_FILE;
202             }
203             else
204                 return APR_EBADF;
205 #endif /* NETWARE */
206
207             fd = aprset[i].desc.f->filedes;
208
209 #endif /* APR_FILES_AS_SOCKETS */
210         }
211         else {
212             break;
213         }
214 #if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */
215         if (fd >= FD_SETSIZE) {
216             /* XXX invent new error code so application has a clue */
217             return APR_EBADF;
218         }
219 #endif
220         if (aprset[i].reqevents & APR_POLLIN) {
221             FD_SET(fd, &readset);
222         }
223         if (aprset[i].reqevents & APR_POLLOUT) {
224             FD_SET(fd, &writeset);
225         }
226         if (aprset[i].reqevents & 
227             (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
228             FD_SET(fd, &exceptset);
229         }
230         if ((int)fd > maxfd) {
231             maxfd = (int)fd;
232         }
233     }
234
235 #ifdef NETWARE
236     if (HAS_PIPES(set_type)) {
237         rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
238     }
239     else {
240 #endif
241
242     rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
243
244 #ifdef NETWARE
245     }
246 #endif
247
248     (*nsds) = rv;
249     if ((*nsds) == 0) {
250         return APR_TIMEUP;
251     }
252     if ((*nsds) < 0) {
253         return apr_get_netos_error();
254     }
255
256     for (i = 0; i < num; i++) {
257         apr_os_sock_t fd;
258
259         if (aprset[i].desc_type == APR_POLL_SOCKET) {
260             fd = aprset[i].desc.s->socketdes;
261         }
262         else if (aprset[i].desc_type == APR_POLL_FILE) {
263 #if !APR_FILES_AS_SOCKETS
264             return APR_EBADF;
265 #else
266             fd = aprset[i].desc.f->filedes;
267 #endif
268         }
269         else {
270             break;
271         }
272         if (FD_ISSET(fd, &readset)) {
273             aprset[i].rtnevents |= APR_POLLIN;
274         }
275         if (FD_ISSET(fd, &writeset)) {
276             aprset[i].rtnevents |= APR_POLLOUT;
277         }
278         if (FD_ISSET(fd, &exceptset)) {
279             aprset[i].rtnevents |= APR_POLLERR;
280         }
281     }
282
283     return APR_SUCCESS;
284 }
285
286 #endif 
287
288
289 struct apr_pollset_t {
290     apr_uint32_t nelts;
291     apr_uint32_t nalloc;
292 #ifdef HAVE_POLL
293     struct pollfd *pollset;
294 #else
295     fd_set readset, writeset, exceptset;
296     int maxfd;
297 #endif
298     apr_pollfd_t *query_set;
299     apr_pollfd_t *result_set;
300     apr_pool_t *pool;
301 #ifdef NETWARE
302     int set_type;
303 #endif
304 };
305
306 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
307                                              apr_uint32_t size,
308                                              apr_pool_t *p,
309                                              apr_uint32_t flags)
310 {
311 #if !defined(HAVE_POLL) && defined(FD_SETSIZE)
312     if (size > FD_SETSIZE) {
313         *pollset = NULL;
314         return APR_EINVAL;
315     }
316 #endif
317     *pollset = apr_palloc(p, sizeof(**pollset));
318     (*pollset)->nelts = 0;
319     (*pollset)->nalloc = size;
320 #ifdef HAVE_POLL
321     (*pollset)->pollset = apr_palloc(p, size * sizeof(struct pollfd));
322 #else
323     FD_ZERO(&((*pollset)->readset));
324     FD_ZERO(&((*pollset)->writeset));
325     FD_ZERO(&((*pollset)->exceptset));
326     (*pollset)->maxfd = 0;
327 #ifdef NETWARE
328     (*pollset)->set_type = APR_NO_DESC;
329 #endif
330 #endif
331     (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
332     (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
333     (*pollset)->pool = p;
334     return APR_SUCCESS;
335 }
336
337 APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
338 {
339     /* A no-op function for now.  If we later implement /dev/poll
340      * support, we'll need to close the /dev/poll fd here
341      */
342     return APR_SUCCESS;
343 }
344
345 APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
346                                           const apr_pollfd_t *descriptor)
347 {
348 #ifndef HAVE_POLL
349     apr_os_sock_t fd;
350 #endif
351
352     if (pollset->nelts == pollset->nalloc) {
353         return APR_ENOMEM;
354     }
355
356     pollset->query_set[pollset->nelts] = *descriptor;
357 #ifdef HAVE_POLL
358
359     if (descriptor->desc_type == APR_POLL_SOCKET) {
360         pollset->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
361     }
362     else {
363         pollset->pollset[pollset->nelts].fd = descriptor->desc.f->filedes;
364     }
365
366     pollset->pollset[pollset->nelts].events = get_event(descriptor->reqevents);
367 #else
368     if (descriptor->desc_type == APR_POLL_SOCKET) {
369 #ifdef NETWARE
370         /* NetWare can't handle mixed descriptor types in select() */
371         if (HAS_PIPES(pollset->set_type)) {
372             return APR_EBADF;
373         }
374         else {
375             pollset->set_type = APR_POLL_SOCKET;
376         }
377 #endif
378         fd = descriptor->desc.s->socketdes;
379     }
380     else {
381 #if !APR_FILES_AS_SOCKETS
382         return APR_EBADF;
383 #else
384 #ifdef NETWARE
385         /* NetWare can't handle mixed descriptor types in select() */
386         if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->set_type)) {
387             pollset->set_type = APR_POLL_FILE;
388             fd = descriptor->desc.f->filedes;
389         }
390         else {
391             return APR_EBADF;
392         }
393 #else
394         fd = descriptor->desc.f->filedes;
395 #endif
396 #endif
397     }
398 #if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */
399     if (fd >= FD_SETSIZE) {
400         /* XXX invent new error code so application has a clue */
401         return APR_EBADF;
402     }
403 #endif
404     if (descriptor->reqevents & APR_POLLIN) {
405         FD_SET(fd, &(pollset->readset));
406     }
407     if (descriptor->reqevents & APR_POLLOUT) {
408         FD_SET(fd, &(pollset->writeset));
409     }
410     if (descriptor->reqevents &
411         (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
412         FD_SET(fd, &(pollset->exceptset));
413     }
414     if ((int)fd > pollset->maxfd) {
415         pollset->maxfd = (int)fd;
416     }
417 #endif
418     pollset->nelts++;
419     return APR_SUCCESS;
420 }
421
422 APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
423                                              const apr_pollfd_t *descriptor)
424 {
425     apr_uint32_t i;
426 #ifndef HAVE_POLL
427     apr_os_sock_t fd;
428 #endif
429
430 #ifdef HAVE_POLL
431     for (i = 0; i < pollset->nelts; i++) {
432         if (descriptor->desc.s == pollset->query_set[i].desc.s) {
433             /* Found an instance of the fd: remove this and any other copies */
434             apr_uint32_t dst = i;
435             apr_uint32_t old_nelts = pollset->nelts;
436             pollset->nelts--;
437             for (i++; i < old_nelts; i++) {
438                 if (descriptor->desc.s == pollset->query_set[i].desc.s) {
439                     pollset->nelts--;
440                 }
441                 else {
442                     pollset->pollset[dst] = pollset->pollset[i];
443                     pollset->query_set[dst] = pollset->query_set[i];
444                     dst++;
445                 }
446             }
447             return APR_SUCCESS;
448         }
449     }
450
451 #else /* no poll */
452     if (descriptor->desc_type == APR_POLL_SOCKET) {
453         fd = descriptor->desc.s->socketdes;
454     }
455     else {
456 #if !APR_FILES_AS_SOCKETS
457         return APR_EBADF;
458 #else
459         fd = descriptor->desc.f->filedes;
460 #endif
461     }
462
463     for (i = 0; i < pollset->nelts; i++) {
464         if (descriptor->desc.s == pollset->query_set[i].desc.s) {
465             /* Found an instance of the fd: remove this and any other copies */
466             apr_uint32_t dst = i;
467             apr_uint32_t old_nelts = pollset->nelts;
468             pollset->nelts--;
469             for (i++; i < old_nelts; i++) {
470                 if (descriptor->desc.s == pollset->query_set[i].desc.s) {
471                     pollset->nelts--;
472                 }
473                 else {
474                     pollset->query_set[dst] = pollset->query_set[i];
475                     dst++;
476                 }
477             }
478             FD_CLR(fd, &(pollset->readset));
479             FD_CLR(fd, &(pollset->writeset));
480             FD_CLR(fd, &(pollset->exceptset));
481             if (((int)fd == pollset->maxfd) && (pollset->maxfd > 0)) {
482                 pollset->maxfd--;
483             }
484             return APR_SUCCESS;
485         }
486     }
487 #endif /* no poll */
488
489     return APR_NOTFOUND;
490 }
491
492 #ifdef HAVE_POLL
493 APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
494                                            apr_interval_time_t timeout,
495                                            apr_int32_t *num,
496                                            const apr_pollfd_t **descriptors)
497 {
498     int rv;
499     apr_uint32_t i, j;
500
501     if (timeout > 0) {
502         timeout /= 1000;
503     }
504     rv = poll(pollset->pollset, pollset->nelts, timeout);
505     (*num) = rv;
506     if (rv < 0) {
507         return apr_get_netos_error();
508     }
509     if (rv == 0) {
510         return APR_TIMEUP;
511     }
512     j = 0;
513     for (i = 0; i < pollset->nelts; i++) {
514         if (pollset->pollset[i].revents != 0) {
515             pollset->result_set[j] = pollset->query_set[i];
516             pollset->result_set[j].rtnevents =
517                 get_revent(pollset->pollset[i].revents);
518             j++;
519         }
520     }
521     *descriptors = pollset->result_set;
522     return APR_SUCCESS;
523 }
524
525 #else /* no poll */
526
527 APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
528                                            apr_interval_time_t timeout,
529                                            apr_int32_t *num,
530                                            const apr_pollfd_t **descriptors)
531 {
532     int rv;
533     apr_uint32_t i, j;
534     struct timeval tv, *tvptr;
535     fd_set readset, writeset, exceptset;
536
537     if (timeout < 0) {
538         tvptr = NULL;
539     }
540     else {
541         tv.tv_sec = (long)apr_time_sec(timeout);
542         tv.tv_usec = (long)apr_time_usec(timeout);
543         tvptr = &tv;
544     }
545
546     memcpy(&readset, &(pollset->readset), sizeof(fd_set));
547     memcpy(&writeset, &(pollset->writeset), sizeof(fd_set));
548     memcpy(&exceptset, &(pollset->exceptset), sizeof(fd_set));
549
550 #ifdef NETWARE
551     if (HAS_PIPES(pollset->set_type)) {
552         rv = pipe_select(pollset->maxfd + 1, &readset, &writeset, &exceptset, tvptr);
553     }
554     else
555 #endif
556     rv = select(pollset->maxfd + 1, &readset, &writeset, &exceptset, tvptr);
557
558     /* Set initial *num now for expected -1 / 0 failures, or errors below */
559     (*num) = rv;
560     if (rv < 0) {
561         return apr_get_netos_error();
562     }
563     if (rv == 0) {
564         return APR_TIMEUP;
565     }
566     j = 0;
567     for (i = 0; i < pollset->nelts; i++) {
568         apr_os_sock_t fd;
569         if (pollset->query_set[i].desc_type == APR_POLL_SOCKET) {
570             fd = pollset->query_set[i].desc.s->socketdes;
571         }
572         else {
573 #if !APR_FILES_AS_SOCKETS
574             return APR_EBADF;
575 #else
576             fd = pollset->query_set[i].desc.f->filedes;
577 #endif
578         }
579         if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
580             FD_ISSET(fd, &exceptset)) {
581             pollset->result_set[j] = pollset->query_set[i];
582             pollset->result_set[j].rtnevents = 0;
583             if (FD_ISSET(fd, &readset)) {
584                 pollset->result_set[j].rtnevents |= APR_POLLIN;
585             }
586             if (FD_ISSET(fd, &writeset)) {
587                 pollset->result_set[j].rtnevents |= APR_POLLOUT;
588             }
589             if (FD_ISSET(fd, &exceptset)) {
590                 pollset->result_set[j].rtnevents |= APR_POLLERR;
591             }
592             j++;
593         }
594     }
595
596     /* Reset computed *num to account for multiply-polled fd's which
597      * select() - on some platforms, treats as a single fd result.
598      * The *num returned must match the size of result_set[]
599      */
600     (*num) = j;
601     *descriptors = pollset->result_set;
602     return APR_SUCCESS;
603 }
604
605 #endif /* no poll */