aboutsummaryrefslogtreecommitdiff
path: root/contrib/apr/poll/unix/pollset.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/apr/poll/unix/pollset.c')
-rw-r--r--contrib/apr/poll/unix/pollset.c344
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);
+}