/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "apr.h" #include "apr_poll.h" #include "apr_arch_networkio.h" struct apr_pollset_t { apr_pool_t *pool; apr_uint32_t nelts; apr_uint32_t nalloc; int *pollset; int num_read; int num_write; int num_except; int num_total; apr_pollfd_t *query_set; apr_pollfd_t *result_set; }; APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags) { *pollset = apr_palloc(p, sizeof(**pollset)); (*pollset)->pool = p; (*pollset)->nelts = 0; (*pollset)->nalloc = size; (*pollset)->pollset = apr_palloc(p, size * sizeof(int) * 3); (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); (*pollset)->num_read = -1; return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset) { /* A no-op function for now. If we later implement /dev/poll * support, we'll need to close the /dev/poll fd here */ return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, const apr_pollfd_t *descriptor) { if (pollset->nelts == pollset->nalloc) { return APR_ENOMEM; } pollset->query_set[pollset->nelts] = *descriptor; if (descriptor->desc_type != APR_POLL_SOCKET) { return APR_EBADF; } pollset->nelts++; pollset->num_read = -1; return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, const apr_pollfd_t *descriptor) { apr_uint32_t i; for (i = 0; i < pollset->nelts; i++) { if (descriptor->desc.s == pollset->query_set[i].desc.s) { /* Found an instance of the fd: remove this and any other copies */ apr_uint32_t dst = i; apr_uint32_t old_nelts = pollset->nelts; pollset->nelts--; for (i++; i < old_nelts; i++) { if (descriptor->desc.s == pollset->query_set[i].desc.s) { pollset->nelts--; } else { pollset->pollset[dst] = pollset->pollset[i]; pollset->query_set[dst] = pollset->query_set[i]; dst++; } } pollset->num_read = -1; return APR_SUCCESS; } } return APR_NOTFOUND; } static void make_pollset(apr_pollset_t *pollset) { int i; int pos = 0; pollset->num_read = 0; pollset->num_write = 0; pollset->num_except = 0; for (i = 0; i < pollset->nelts; i++) { if (pollset->query_set[i].reqevents & APR_POLLIN) { pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; pollset->num_read++; } } for (i = 0; i < pollset->nelts; i++) { if (pollset->query_set[i].reqevents & APR_POLLOUT) { pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; pollset->num_write++; } } for (i = 0; i < pollset->nelts; i++) { if (pollset->query_set[i].reqevents & APR_POLLPRI) { pollset->pollset[pos++] = pollset->query_set[i].desc.s->socketdes; pollset->num_except++; } } pollset->num_total = pollset->num_read + pollset->num_write + pollset->num_except; } APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, apr_interval_time_t timeout, apr_int32_t *num, const apr_pollfd_t **descriptors) { int rv; apr_uint32_t i; int *pollresult; int read_pos, write_pos, except_pos; if (pollset->num_read < 0) { make_pollset(pollset); } pollresult = alloca(sizeof(int) * pollset->num_total); memcpy(pollresult, pollset->pollset, sizeof(int) * pollset->num_total); (*num) = 0; if (timeout > 0) { timeout /= 1000; } rv = select(pollresult, pollset->num_read, pollset->num_write, pollset->num_except, timeout); if (rv < 0) { return APR_FROM_OS_ERROR(sock_errno()); } if (rv == 0) { return APR_TIMEUP; } read_pos = 0; write_pos = pollset->num_read; except_pos = pollset->num_read + pollset->num_write; for (i = 0; i < pollset->nelts; i++) { int rtnevents = 0; if (pollset->query_set[i].reqevents & APR_POLLIN) { if (pollresult[read_pos++] != -1) { rtnevents |= APR_POLLIN; } } if (pollset->query_set[i].reqevents & APR_POLLOUT) { if (pollresult[write_pos++] != -1) { rtnevents |= APR_POLLOUT; } } if (pollset->query_set[i].reqevents & APR_POLLPRI) { if (pollresult[except_pos++] != -1) { rtnevents |= APR_POLLPRI; } } if (rtnevents) { pollset->result_set[*num] = pollset->query_set[i]; pollset->result_set[*num].rtnevents = rtnevents; (*num)++; } } if (descriptors) { *descriptors = pollset->result_set; } return APR_SUCCESS; }