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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "apr_portable.h"
21 #include "apr_arch_file_io.h"
22 #include "apr_arch_networkio.h"
23 #include "apr_arch_misc.h"
24 #include "apr_arch_poll_private.h"
26 #if defined(HAVE_POLL)
32 static apr_int16_t get_event(apr_int16_t event)
36 if (event & APR_POLLIN)
38 if (event & APR_POLLPRI)
40 if (event & APR_POLLOUT)
42 /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */
47 static apr_int16_t get_revent(apr_int16_t event)
69 #define SMALL_POLLSET_LIMIT 8
71 APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num,
73 apr_interval_time_t timeout)
77 /* XXX: I trust that this is a segv when insufficient stack exists? */
78 struct pollfd pollset[num];
79 #elif defined(HAVE_ALLOCA)
80 struct pollfd *pollset = alloca(sizeof(struct pollfd) * num);
84 struct pollfd tmp_pollset[SMALL_POLLSET_LIMIT];
85 struct pollfd *pollset;
87 if (num <= SMALL_POLLSET_LIMIT) {
88 pollset = tmp_pollset;
91 /* This does require O(n) to copy the descriptors to the internal
94 pollset = malloc(sizeof(struct pollfd) * num);
95 /* The other option is adding an apr_pool_abort() fn to invoke
96 * the pool's out of memory handler
102 for (i = 0; i < num; i++) {
103 if (aprset[i].desc_type == APR_POLL_SOCKET) {
104 pollset[i].fd = aprset[i].desc.s->socketdes;
106 else if (aprset[i].desc_type == APR_POLL_FILE) {
107 pollset[i].fd = aprset[i].desc.f->filedes;
112 pollset[i].events = get_event(aprset[i].reqevents);
117 timeout /= 1000; /* convert microseconds to milliseconds */
120 i = poll(pollset, num_to_poll, timeout);
123 if (i > 0) { /* poll() sets revents only if an event was signalled;
124 * we don't promise to set rtnevents unless an event
127 for (i = 0; i < num; i++) {
128 aprset[i].rtnevents = get_revent(pollset[i].revents);
132 #if !defined(HAVE_VLA) && !defined(HAVE_ALLOCA)
133 if (num > SMALL_POLLSET_LIMIT) {
139 return apr_get_netos_error();
148 #endif /* POLL_USES_POLL */
150 struct apr_pollset_private_t
152 struct pollfd *pollset;
153 apr_pollfd_t *query_set;
154 apr_pollfd_t *result_set;
157 static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
162 if (flags & APR_POLLSET_THREADSAFE) {
166 if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) {
170 pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
171 pollset->p->pollset = apr_palloc(p, size * sizeof(struct pollfd));
172 pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
173 pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
178 static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
179 const apr_pollfd_t *descriptor)
181 if (pollset->nelts == pollset->nalloc) {
185 pollset->p->query_set[pollset->nelts] = *descriptor;
187 if (descriptor->desc_type == APR_POLL_SOCKET) {
188 pollset->p->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
191 #if APR_FILES_AS_SOCKETS
192 pollset->p->pollset[pollset->nelts].fd = descriptor->desc.f->filedes;
194 if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
195 descriptor->desc.f == pollset->wakeup_pipe[0])
196 pollset->p->pollset[pollset->nelts].fd = (SOCKET)descriptor->desc.f->filedes;
201 pollset->p->pollset[pollset->nelts].events =
202 get_event(descriptor->reqevents);
208 static apr_status_t impl_pollset_remove(apr_pollset_t *pollset,
209 const apr_pollfd_t *descriptor)
213 for (i = 0; i < pollset->nelts; i++) {
214 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
215 /* Found an instance of the fd: remove this and any other copies */
216 apr_uint32_t dst = i;
217 apr_uint32_t old_nelts = pollset->nelts;
219 for (i++; i < old_nelts; i++) {
220 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
224 pollset->p->pollset[dst] = pollset->p->pollset[i];
225 pollset->p->query_set[dst] = pollset->p->query_set[i];
236 static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
237 apr_interval_time_t timeout,
239 const apr_pollfd_t **descriptors)
242 apr_status_t rv = APR_SUCCESS;
245 /* WSAPoll() requires at least one socket. */
246 if (pollset->nelts == 0) {
257 ret = WSAPoll(pollset->p->pollset, pollset->nelts, (int)timeout);
262 ret = poll(pollset->p->pollset, pollset->nelts, timeout);
266 return apr_get_netos_error();
274 for (i = 0, j = 0; i < pollset->nelts; i++) {
275 if (pollset->p->pollset[i].revents != 0) {
276 /* Check if the polled descriptor is our
277 * wakeup pipe. In that case do not put it result set.
279 if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
280 pollset->p->query_set[i].desc_type == APR_POLL_FILE &&
281 pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
282 apr_pollset_drain_wakeup_pipe(pollset);
286 pollset->p->result_set[j] = pollset->p->query_set[i];
287 pollset->p->result_set[j].rtnevents =
288 get_revent(pollset->p->pollset[i].revents);
293 if (((*num) = j) > 0)
296 if (descriptors && (*num))
297 *descriptors = pollset->p->result_set;
301 static apr_pollset_provider_t impl = {
310 apr_pollset_provider_t *apr_pollset_provider_poll = &impl;
312 /* Poll method pollcb.
313 * This is probably usable only for WIN32 having WSAPoll
315 static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb,
325 if (!APR_HAVE_LATE_DLL_FUNC(WSAPoll)) {
330 pollcb->pollset.ps = apr_palloc(p, size * sizeof(struct pollfd));
331 pollcb->copyset = apr_palloc(p, size * sizeof(apr_pollfd_t *));
337 static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb,
338 apr_pollfd_t *descriptor)
340 if (pollcb->nelts == pollcb->nalloc) {
344 if (descriptor->desc_type == APR_POLL_SOCKET) {
345 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.s->socketdes;
348 #if APR_FILES_AS_SOCKETS
349 pollcb->pollset.ps[pollcb->nelts].fd = descriptor->desc.f->filedes;
355 pollcb->pollset.ps[pollcb->nelts].events =
356 get_event(descriptor->reqevents);
357 pollcb->copyset[pollcb->nelts] = descriptor;
363 static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb,
364 apr_pollfd_t *descriptor)
368 for (i = 0; i < pollcb->nelts; i++) {
369 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) {
370 /* Found an instance of the fd: remove this and any other copies */
371 apr_uint32_t dst = i;
372 apr_uint32_t old_nelts = pollcb->nelts;
374 for (i++; i < old_nelts; i++) {
375 if (descriptor->desc.s == pollcb->copyset[i]->desc.s) {
379 pollcb->pollset.ps[dst] = pollcb->pollset.ps[i];
380 pollcb->copyset[dst] = pollcb->copyset[i];
391 static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb,
392 apr_interval_time_t timeout,
393 apr_pollcb_cb_t func,
397 apr_status_t rv = APR_SUCCESS;
401 /* WSAPoll() requires at least one socket. */
402 if (pollcb->nelts == 0) {
412 ret = WSAPoll(pollcb->pollset.ps, pollcb->nelts, (int)timeout);
417 ret = poll(pollcb->pollset.ps, pollcb->nelts, timeout);
420 return apr_get_netos_error();
426 for (i = 0; i < pollcb->nelts; i++) {
427 if (pollcb->pollset.ps[i].revents != 0) {
428 apr_pollfd_t *pollfd = pollcb->copyset[i];
429 pollfd->rtnevents = get_revent(pollcb->pollset.ps[i].revents);
430 rv = func(baton, pollfd);
440 static apr_pollcb_provider_t impl_cb = {
448 apr_pollcb_provider_t *apr_pollcb_provider_poll = &impl_cb;
450 #endif /* HAVE_POLL */