freebsd-dev/contrib/apr/poll/unix/select.c
Peter Wemm 937a200089 Introduce svnlite so that we can check out our source code again.
This is actually a fully functional build except:
* All internal shared libraries are static linked to make sure there
  is no interference with ports (and to reduce build time).
* It does not have the python/perl/etc plugin or API support.
* By default, it installs as "svnlite" rather than "svn".
* If WITH_SVN added in make.conf, you get "svn".
* If WITHOUT_SVNLITE is in make.conf, this is completely disabled.

To be absolutely clear, this is not intended for any use other than
checking out freebsd source and committing, like we once did with cvs.

It should be usable for small scale local repositories that don't
need the python/perl plugin architecture.
2013-06-18 02:53:45 +00:00

450 lines
12 KiB
C

/* 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.
*/
#ifdef WIN32
/* POSIX defines 1024 for the FD_SETSIZE */
#define FD_SETSIZE 1024
#endif
#include "apr.h"
#include "apr_poll.h"
#include "apr_time.h"
#include "apr_portable.h"
#include "apr_arch_file_io.h"
#include "apr_arch_networkio.h"
#include "apr_arch_poll_private.h"
#ifdef POLL_USES_SELECT
APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, int num,
apr_int32_t *nsds,
apr_interval_time_t timeout)
{
fd_set readset, writeset, exceptset;
int rv, i;
int maxfd = -1;
struct timeval tv, *tvptr;
#ifdef NETWARE
apr_datatype_e set_type = APR_NO_DESC;
#endif
#ifdef WIN32
/* On Win32, select() must be presented with at least one socket to
* poll on, or select() will return WSAEINVAL. So, we'll just
* short-circuit and bail now.
*/
if (num == 0) {
(*nsds) = 0;
if (timeout > 0) {
apr_sleep(timeout);
return APR_TIMEUP;
}
return APR_SUCCESS;
}
#endif
if (timeout < 0) {
tvptr = NULL;
}
else {
tv.tv_sec = (long) apr_time_sec(timeout);
tv.tv_usec = (long) apr_time_usec(timeout);
tvptr = &tv;
}
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
for (i = 0; i < num; i++) {
apr_os_sock_t fd;
aprset[i].rtnevents = 0;
if (aprset[i].desc_type == APR_POLL_SOCKET) {
#ifdef NETWARE
if (HAS_PIPES(set_type)) {
return APR_EBADF;
}
else {
set_type = APR_POLL_SOCKET;
}
#endif
fd = aprset[i].desc.s->socketdes;
}
else if (aprset[i].desc_type == APR_POLL_FILE) {
#if !APR_FILES_AS_SOCKETS
return APR_EBADF;
#else
#ifdef NETWARE
if (aprset[i].desc.f->is_pipe && !HAS_SOCKETS(set_type)) {
set_type = APR_POLL_FILE;
}
else
return APR_EBADF;
#endif /* NETWARE */
fd = aprset[i].desc.f->filedes;
#endif /* APR_FILES_AS_SOCKETS */
}
else {
break;
}
#if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */
if (fd >= FD_SETSIZE) {
/* XXX invent new error code so application has a clue */
return APR_EBADF;
}
#endif
if (aprset[i].reqevents & APR_POLLIN) {
FD_SET(fd, &readset);
}
if (aprset[i].reqevents & APR_POLLOUT) {
FD_SET(fd, &writeset);
}
if (aprset[i].reqevents &
(APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
FD_SET(fd, &exceptset);
}
if ((int) fd > maxfd) {
maxfd = (int) fd;
}
}
#ifdef NETWARE
if (HAS_PIPES(set_type)) {
rv = pipe_select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
}
else {
#endif
rv = select(maxfd + 1, &readset, &writeset, &exceptset, tvptr);
#ifdef NETWARE
}
#endif
(*nsds) = rv;
if ((*nsds) == 0) {
return APR_TIMEUP;
}
if ((*nsds) < 0) {
return apr_get_netos_error();
}
(*nsds) = 0;
for (i = 0; i < num; i++) {
apr_os_sock_t fd;
if (aprset[i].desc_type == APR_POLL_SOCKET) {
fd = aprset[i].desc.s->socketdes;
}
else if (aprset[i].desc_type == APR_POLL_FILE) {
#if !APR_FILES_AS_SOCKETS
return APR_EBADF;
#else
fd = aprset[i].desc.f->filedes;
#endif
}
else {
break;
}
if (FD_ISSET(fd, &readset)) {
aprset[i].rtnevents |= APR_POLLIN;
}
if (FD_ISSET(fd, &writeset)) {
aprset[i].rtnevents |= APR_POLLOUT;
}
if (FD_ISSET(fd, &exceptset)) {
aprset[i].rtnevents |= APR_POLLERR;
}
if (aprset[i].rtnevents) {
(*nsds)++;
}
}
return APR_SUCCESS;
}
#endif /* POLL_USES_SELECT */
struct apr_pollset_private_t
{
fd_set readset, writeset, exceptset;
int maxfd;
apr_pollfd_t *query_set;
apr_pollfd_t *result_set;
apr_uint32_t flags;
#ifdef NETWARE
int set_type;
#endif
};
static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
apr_uint32_t size,
apr_pool_t *p,
apr_uint32_t flags)
{
if (flags & APR_POLLSET_THREADSAFE) {
pollset->p = NULL;
return APR_ENOTIMPL;
}
#ifdef FD_SETSIZE
if (size > FD_SETSIZE) {
pollset->p = NULL;
return APR_EINVAL;
}
#endif
pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
FD_ZERO(&(pollset->p->readset));
FD_ZERO(&(pollset->p->writeset));
FD_ZERO(&(pollset->p->exceptset));
pollset->p->maxfd = 0;
#ifdef NETWARE
pollset->p->set_type = APR_NO_DESC;
#endif
pollset->p->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
return APR_SUCCESS;
}
static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
const apr_pollfd_t *descriptor)
{
apr_os_sock_t fd;
if (pollset->nelts == pollset->nalloc) {
return APR_ENOMEM;
}
pollset->p->query_set[pollset->nelts] = *descriptor;
if (descriptor->desc_type == APR_POLL_SOCKET) {
#ifdef NETWARE
/* NetWare can't handle mixed descriptor types in select() */
if (HAS_PIPES(pollset->p->set_type)) {
return APR_EBADF;
}
else {
pollset->p->set_type = APR_POLL_SOCKET;
}
#endif
fd = descriptor->desc.s->socketdes;
}
else {
#if !APR_FILES_AS_SOCKETS
if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
descriptor->desc.f == pollset->wakeup_pipe[0])
fd = (apr_os_sock_t)descriptor->desc.f->filedes;
else
return APR_EBADF;
#else
#ifdef NETWARE
/* NetWare can't handle mixed descriptor types in select() */
if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->p->set_type)) {
pollset->p->set_type = APR_POLL_FILE;
fd = descriptor->desc.f->filedes;
}
else {
return APR_EBADF;
}
#else
fd = descriptor->desc.f->filedes;
#endif
#endif
}
#if !defined(WIN32) && !defined(NETWARE) /* socket sets handled with array of handles */
if (fd >= FD_SETSIZE) {
/* XXX invent new error code so application has a clue */
return APR_EBADF;
}
#endif
if (descriptor->reqevents & APR_POLLIN) {
FD_SET(fd, &(pollset->p->readset));
}
if (descriptor->reqevents & APR_POLLOUT) {
FD_SET(fd, &(pollset->p->writeset));
}
if (descriptor->reqevents &
(APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
FD_SET(fd, &(pollset->p->exceptset));
}
if ((int) fd > pollset->p->maxfd) {
pollset->p->maxfd = (int) fd;
}
pollset->nelts++;
return APR_SUCCESS;
}
static apr_status_t impl_pollset_remove(apr_pollset_t * pollset,
const apr_pollfd_t * descriptor)
{
apr_uint32_t i;
apr_os_sock_t fd;
if (descriptor->desc_type == APR_POLL_SOCKET) {
fd = descriptor->desc.s->socketdes;
}
else {
#if !APR_FILES_AS_SOCKETS
return APR_EBADF;
#else
fd = descriptor->desc.f->filedes;
#endif
}
for (i = 0; i < pollset->nelts; i++) {
if (descriptor->desc.s == pollset->p->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->p->query_set[i].desc.s) {
pollset->nelts--;
}
else {
pollset->p->query_set[dst] = pollset->p->query_set[i];
dst++;
}
}
FD_CLR(fd, &(pollset->p->readset));
FD_CLR(fd, &(pollset->p->writeset));
FD_CLR(fd, &(pollset->p->exceptset));
if (((int) fd == pollset->p->maxfd) && (pollset->p->maxfd > 0)) {
pollset->p->maxfd--;
}
return APR_SUCCESS;
}
}
return APR_NOTFOUND;
}
static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
apr_interval_time_t timeout,
apr_int32_t *num,
const apr_pollfd_t **descriptors)
{
int rs;
apr_uint32_t i, j;
struct timeval tv, *tvptr;
fd_set readset, writeset, exceptset;
apr_status_t rv = APR_SUCCESS;
#ifdef WIN32
/* On Win32, select() must be presented with at least one socket to
* poll on, or select() will return WSAEINVAL. So, we'll just
* short-circuit and bail now.
*/
if (pollset->nelts == 0) {
(*num) = 0;
if (timeout > 0) {
apr_sleep(timeout);
return APR_TIMEUP;
}
return APR_SUCCESS;
}
#endif
if (timeout < 0) {
tvptr = NULL;
}
else {
tv.tv_sec = (long) apr_time_sec(timeout);
tv.tv_usec = (long) apr_time_usec(timeout);
tvptr = &tv;
}
memcpy(&readset, &(pollset->p->readset), sizeof(fd_set));
memcpy(&writeset, &(pollset->p->writeset), sizeof(fd_set));
memcpy(&exceptset, &(pollset->p->exceptset), sizeof(fd_set));
#ifdef NETWARE
if (HAS_PIPES(pollset->p->set_type)) {
rs = pipe_select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
tvptr);
}
else
#endif
rs = select(pollset->p->maxfd + 1, &readset, &writeset, &exceptset,
tvptr);
(*num) = rs;
if (rs < 0) {
return apr_get_netos_error();
}
if (rs == 0) {
return APR_TIMEUP;
}
j = 0;
for (i = 0; i < pollset->nelts; i++) {
apr_os_sock_t fd;
if (pollset->p->query_set[i].desc_type == APR_POLL_SOCKET) {
fd = pollset->p->query_set[i].desc.s->socketdes;
}
else {
if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
pollset->p->query_set[i].desc.f == pollset->wakeup_pipe[0]) {
apr_pollset_drain_wakeup_pipe(pollset);
rv = APR_EINTR;
continue;
}
else {
#if !APR_FILES_AS_SOCKETS
return APR_EBADF;
#else
fd = pollset->p->query_set[i].desc.f->filedes;
#endif
}
}
if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
FD_ISSET(fd, &exceptset)) {
pollset->p->result_set[j] = pollset->p->query_set[i];
pollset->p->result_set[j].rtnevents = 0;
if (FD_ISSET(fd, &readset)) {
pollset->p->result_set[j].rtnevents |= APR_POLLIN;
}
if (FD_ISSET(fd, &writeset)) {
pollset->p->result_set[j].rtnevents |= APR_POLLOUT;
}
if (FD_ISSET(fd, &exceptset)) {
pollset->p->result_set[j].rtnevents |= APR_POLLERR;
}
j++;
}
}
if (((*num) = j) != 0)
rv = APR_SUCCESS;
if (descriptors)
*descriptors = pollset->p->result_set;
return rv;
}
static apr_pollset_provider_t impl = {
impl_pollset_create,
impl_pollset_add,
impl_pollset_remove,
impl_pollset_poll,
NULL,
"select"
};
apr_pollset_provider_t *apr_pollset_provider_select = &impl;