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.
18 /* POSIX defines 1024 for the FD_SETSIZE */
19 #define FD_SETSIZE 1024
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"
30 #ifdef POLL_USES_SELECT
32 APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num,
34 apr_interval_time_t timeout)
36 fd_set readset, writeset, exceptset;
39 struct timeval tv, *tvptr;
41 apr_datatype_e set_type = APR_NO_DESC;
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.
63 tv.tv_sec = (long) apr_time_sec(timeout);
64 tv.tv_usec = (long) apr_time_usec(timeout);
72 for (i = 0; i < num; i++) {
75 aprset[i].rtnevents = 0;
77 if (aprset[i].desc_type == APR_POLL_SOCKET) {
79 if (HAS_PIPES(set_type)) {
83 set_type = APR_POLL_SOCKET;
86 fd = aprset[i].desc.s->socketdes;
88 else if (aprset[i].desc_type == APR_POLL_FILE) {
89 #if !APR_FILES_AS_SOCKETS
93 if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
94 set_type = APR_POLL_FILE;
100 fd = aprset[i].desc.f->filedes;
102 #endif /* APR_FILES_AS_SOCKETS */
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 */
113 if (aprset[i].reqevents & APR_POLLIN) {
114 FD_SET(fd, &readset);
116 if (aprset[i].reqevents & APR_POLLOUT) {
117 FD_SET(fd, &writeset);
119 if (aprset[i].reqevents &
120 (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
121 FD_SET(fd, &exceptset);
123 if ((int) fd > maxfd) {
129 if (HAS_PIPES(set_type)) {
130 rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
135 rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
146 return apr_get_netos_error();
150 for (i = 0; i < num; i++) {
153 if (aprset[i].desc_type == APR_POLL_SOCKET) {
154 fd = aprset[i].desc.s->socketdes;
156 else if (aprset[i].desc_type == APR_POLL_FILE) {
157 #if !APR_FILES_AS_SOCKETS
160 fd = aprset[i].desc.f->filedes;
166 if (FD_ISSET(fd, &readset)) {
167 aprset[i].rtnevents |= APR_POLLIN;
169 if (FD_ISSET(fd, &writeset)) {
170 aprset[i].rtnevents |= APR_POLLOUT;
172 if (FD_ISSET(fd, &exceptset)) {
173 aprset[i].rtnevents |= APR_POLLERR;
175 if (aprset[i].rtnevents) {
183 #endif /* POLL_USES_SELECT */
185 struct apr_pollset_private_t
187 fd_set readset, writeset, exceptset;
189 apr_pollfd_t *query_set;
190 apr_pollfd_t *result_set;
197 static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
202 if (flags & APR_POLLSET_THREADSAFE) {
207 if (size > FD_SETSIZE) {
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;
218 pollset->p->set_type = APR_NO_DESC;
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));
226 static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
227 const apr_pollfd_t *descriptor)
231 if (pollset->nelts == pollset->nalloc) {
235 pollset->p->query_set[pollset->nelts] = *descriptor;
237 if (descriptor->desc_type == APR_POLL_SOCKET) {
239 /* NetWare can't handle mixed descriptor types in select() */
240 if (HAS_PIPES(pollset->p->set_type)) {
244 pollset->p->set_type = APR_POLL_SOCKET;
247 fd = descriptor->desc.s->socketdes;
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;
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;
267 fd = descriptor->desc.f->filedes;
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 */
277 if (descriptor->reqevents & APR_POLLIN) {
278 FD_SET(fd, &(pollset->p->readset));
280 if (descriptor->reqevents & APR_POLLOUT) {
281 FD_SET(fd, &(pollset->p->writeset));
283 if (descriptor->reqevents &
284 (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
285 FD_SET(fd, &(pollset->p->exceptset));
287 if ((int) fd > pollset->p->maxfd) {
288 pollset->p->maxfd = (int) fd;
294 static apr_status_t impl_pollset_remove(apr_pollset_t * pollset,
295 const apr_pollfd_t * descriptor)
300 if (descriptor->desc_type == APR_POLL_SOCKET) {
301 fd = descriptor->desc.s->socketdes;
304 #if !APR_FILES_AS_SOCKETS
307 fd = descriptor->desc.f->filedes;
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;
317 for (i++; i < old_nelts; i++) {
318 if (descriptor->desc.s == pollset->p->query_set[i].desc.s) {
322 pollset->p->query_set[dst] = pollset->p->query_set[i];
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)) {
339 static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
340 apr_interval_time_t timeout,
342 const apr_pollfd_t **descriptors)
346 struct timeval tv, *tvptr;
347 fd_set readset, writeset, exceptset;
348 apr_status_t rv = APR_SUCCESS;
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.
355 if (pollset->nelts == 0) {
369 tv.tv_sec = (long) apr_time_sec(timeout);
370 tv.tv_usec = (long) apr_time_usec(timeout);
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));
379 if (HAS_PIPES(pollset->p->set_type)) {
380 rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
385 rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
390 return apr_get_netos_error();
396 for (i = 0; i < pollset->nelts; i++) {
398 if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) {
399 fd = pollset->p->query_set[i].desc.s->socketdes;
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);
409 #if !APR_FILES_AS_SOCKETS
412 fd = pollset->p->query_set[i].desc.f->filedes;
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;
423 if (FD_ISSET(fd, &writeset)) {
424 pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
426 if (FD_ISSET(fd, &exceptset)) {
427 pollset->p->result_set[j].rtnevents |= APR_POLLERR;
432 if (((*num) = j) != 0)
436 *descriptors = pollset->p->result_set;
440 static apr_pollset_provider_t impl = {
449 apr_pollset_provider_t *apr_pollset_provider_select = &impl;