diff options
Diffstat (limited to 'contrib/apr/poll/unix/pollset.c')
-rw-r--r-- | contrib/apr/poll/unix/pollset.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/contrib/apr/poll/unix/pollset.c b/contrib/apr/poll/unix/pollset.c new file mode 100644 index 000000000000..1a7396b4bc4b --- /dev/null +++ b/contrib/apr/poll/unix/pollset.c @@ -0,0 +1,344 @@ +/* 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" +#include "apr_arch_inherit.h" + +static apr_pollset_method_e pollset_default_method = POLLSET_DEFAULT_METHOD; + +#if !APR_FILES_AS_SOCKETS +#if defined (WIN32) + +/* Create a dummy wakeup socket pipe for interrupting the poller + */ +static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) +{ + apr_status_t rv; + + if ((rv = apr_file_socket_pipe_create(&pollset->wakeup_pipe[0], + &pollset->wakeup_pipe[1], + pollset->pool)) != APR_SUCCESS) + return rv; + + pollset->wakeup_pfd.p = pollset->pool; + pollset->wakeup_pfd.reqevents = APR_POLLIN; + pollset->wakeup_pfd.desc_type = APR_POLL_FILE; + pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; + + return apr_pollset_add(pollset, &pollset->wakeup_pfd); +} + +#else /* !WIN32 */ +static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) +{ + return APR_ENOTIMPL; +} + +static apr_status_t apr_file_socket_pipe_close(apr_file_t *file) +{ + return APR_ENOTIMPL; +} + +#endif /* WIN32 */ +#else /* APR_FILES_AS_SOCKETS */ + +/* Create a dummy wakeup pipe for interrupting the poller + */ +static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) +{ + apr_status_t rv; + + if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], + &pollset->wakeup_pipe[1], + pollset->pool)) != APR_SUCCESS) + return rv; + + pollset->wakeup_pfd.p = pollset->pool; + pollset->wakeup_pfd.reqevents = APR_POLLIN; + pollset->wakeup_pfd.desc_type = APR_POLL_FILE; + pollset->wakeup_pfd.desc.f = pollset->wakeup_pipe[0]; + + { + int flags; + + if ((flags = fcntl(pollset->wakeup_pipe[0]->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(pollset->wakeup_pipe[0]->filedes, F_SETFD, flags) == -1) + return errno; + } + { + int flags; + + if ((flags = fcntl(pollset->wakeup_pipe[1]->filedes, F_GETFD)) == -1) + return errno; + + flags |= FD_CLOEXEC; + if (fcntl(pollset->wakeup_pipe[1]->filedes, F_SETFD, flags) == -1) + return errno; + } + + return apr_pollset_add(pollset, &pollset->wakeup_pfd); +} +#endif /* !APR_FILES_AS_SOCKETS */ + +/* Read and discard what's ever in the wakeup pipe. + */ +void apr_pollset_drain_wakeup_pipe(apr_pollset_t *pollset) +{ + char rb[512]; + apr_size_t nr = sizeof(rb); + + while (apr_file_read(pollset->wakeup_pipe[0], rb, &nr) == APR_SUCCESS) { + /* Although we write just one byte to the other end of the pipe + * during wakeup, multiple threads could call the wakeup. + * So simply drain out from the input side of the pipe all + * the data. + */ + if (nr != sizeof(rb)) + break; + } +} + +static apr_status_t pollset_cleanup(void *p) +{ + apr_pollset_t *pollset = (apr_pollset_t *) p; + if (pollset->provider->cleanup) { + (*pollset->provider->cleanup)(pollset); + } + if (pollset->flags & APR_POLLSET_WAKEABLE) { + /* Close both sides of the wakeup pipe */ + if (pollset->wakeup_pipe[0]) { +#if APR_FILES_AS_SOCKETS + apr_file_close(pollset->wakeup_pipe[0]); +#else + apr_file_socket_pipe_close(pollset->wakeup_pipe[0]); +#endif + pollset->wakeup_pipe[0] = NULL; + } + if (pollset->wakeup_pipe[1]) { +#if APR_FILES_AS_SOCKETS + apr_file_close(pollset->wakeup_pipe[1]); +#else + apr_file_socket_pipe_close(pollset->wakeup_pipe[1]); +#endif + pollset->wakeup_pipe[1] = NULL; + } + } + + return APR_SUCCESS; +} + +#if defined(HAVE_KQUEUE) +extern apr_pollset_provider_t *apr_pollset_provider_kqueue; +#endif +#if defined(HAVE_PORT_CREATE) +extern apr_pollset_provider_t *apr_pollset_provider_port; +#endif +#if defined(HAVE_EPOLL) +extern apr_pollset_provider_t *apr_pollset_provider_epoll; +#endif +#if defined(HAVE_POLL) +extern apr_pollset_provider_t *apr_pollset_provider_poll; +#endif +extern apr_pollset_provider_t *apr_pollset_provider_select; + +static apr_pollset_provider_t *pollset_provider(apr_pollset_method_e method) +{ + apr_pollset_provider_t *provider = NULL; + switch (method) { + case APR_POLLSET_KQUEUE: +#if defined(HAVE_KQUEUE) + provider = apr_pollset_provider_kqueue; +#endif + break; + case APR_POLLSET_PORT: +#if defined(HAVE_PORT_CREATE) + provider = apr_pollset_provider_port; +#endif + break; + case APR_POLLSET_EPOLL: +#if defined(HAVE_EPOLL) + provider = apr_pollset_provider_epoll; +#endif + break; + case APR_POLLSET_POLL: +#if defined(HAVE_POLL) + provider = apr_pollset_provider_poll; +#endif + break; + case APR_POLLSET_SELECT: + provider = apr_pollset_provider_select; + break; + case APR_POLLSET_DEFAULT: + break; + } + return provider; +} + +APR_DECLARE(apr_status_t) apr_pollset_create_ex(apr_pollset_t **ret_pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags, + apr_pollset_method_e method) +{ + apr_status_t rv; + apr_pollset_t *pollset; + apr_pollset_provider_t *provider = NULL; + + *ret_pollset = NULL; + + #ifdef WIN32 + /* Favor WSAPoll if supported. + * This will work only if ws2_32.dll has WSAPoll funtion. + * In other cases it will fall back to select() method unless + * the APR_POLLSET_NODEFAULT is added to the flags. + */ + if (method == APR_POLLSET_DEFAULT) { + method = APR_POLLSET_POLL; + } + #endif + + if (method == APR_POLLSET_DEFAULT) + method = pollset_default_method; + while (provider == NULL) { + provider = pollset_provider(method); + if (!provider) { + if ((flags & APR_POLLSET_NODEFAULT) == APR_POLLSET_NODEFAULT) + return APR_ENOTIMPL; + if (method == pollset_default_method) + return APR_ENOTIMPL; + method = pollset_default_method; + } + } + if (flags & APR_POLLSET_WAKEABLE) { + /* Add room for wakeup descriptor */ + size++; + } + + pollset = apr_palloc(p, sizeof(*pollset)); + pollset->nelts = 0; + pollset->nalloc = size; + pollset->pool = p; + pollset->flags = flags; + pollset->provider = provider; + + rv = (*provider->create)(pollset, size, p, flags); + if (rv == APR_ENOTIMPL) { + if (method == pollset_default_method) { + return rv; + } + provider = pollset_provider(pollset_default_method); + if (!provider) { + return APR_ENOTIMPL; + } + rv = (*provider->create)(pollset, size, p, flags); + if (rv != APR_SUCCESS) { + return rv; + } + pollset->provider = provider; + } + else if (rv != APR_SUCCESS) { + return rv; + } + if (flags & APR_POLLSET_WAKEABLE) { + /* Create wakeup pipe */ + if ((rv = create_wakeup_pipe(pollset)) != APR_SUCCESS) { + return rv; + } + } + if ((flags & APR_POLLSET_WAKEABLE) || provider->cleanup) + apr_pool_cleanup_register(p, pollset, pollset_cleanup, + apr_pool_cleanup_null); + + *ret_pollset = pollset; + return APR_SUCCESS; +} + +APR_DECLARE(const char *) apr_pollset_method_name(apr_pollset_t *pollset) +{ + return pollset->provider->name; +} + +APR_DECLARE(const char *) apr_poll_method_defname() +{ + apr_pollset_provider_t *provider = NULL; + + provider = pollset_provider(pollset_default_method); + if (provider) + return provider->name; + else + return "unknown"; +} + +APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) +{ + apr_pollset_method_e method = APR_POLLSET_DEFAULT; + return apr_pollset_create_ex(pollset, size, p, flags, method); +} + +APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) +{ + if (pollset->flags & APR_POLLSET_WAKEABLE || + pollset->provider->cleanup) + return apr_pool_cleanup_run(pollset->pool, pollset, + pollset_cleanup); + else + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_pollset_wakeup(apr_pollset_t *pollset) +{ + if (pollset->flags & APR_POLLSET_WAKEABLE) + return apr_file_putc(1, pollset->wakeup_pipe[1]); + else + return APR_EINIT; +} + +APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + return (*pollset->provider->add)(pollset, descriptor); +} + +APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) +{ + return (*pollset->provider->remove)(pollset, descriptor); +} + +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) +{ + return (*pollset->provider->poll)(pollset, timeout, num, descriptors); +} |