summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--include/apr_poll.h5
-rw-r--r--include/arch/unix/apr_arch_poll_private.h92
-rw-r--r--poll/unix/epoll.c270
-rw-r--r--poll/unix/kqueue.c288
-rw-r--r--poll/unix/poll.c722
-rw-r--r--poll/unix/select.c392
7 files changed, 1072 insertions, 704 deletions
diff --git a/CHANGES b/CHANGES
index 09a4d9cd5..1a5130701 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,13 @@ Changes for APR 1.1.0
and upgrading it to do SHA-256. Not yet ready for prime time.
[Ben Laurie]
+ *) Added the APR_POLLSET_THREADSAFE flag. This allows multiple threads
+ to call the Pollset Add or Remove functions in a thread safe manner.
+ Currently only EPoll and KQueue support this flag. [Paul Querna]
+
+ *) Split poll/unix/poll.c into separate files for each Poll or Pollset
+ implementation. [Paul Querna]
+
*) Rewrite apr_file_printf to handle arbitrary length strings.
PR 28029. [Chris Knight <Christopher.D.Knight nasa.gov>,
Garrett Rooney <rooneg electricjellyfish.net>]
diff --git a/include/apr_poll.h b/include/apr_poll.h
index cc8920824..0584b09f3 100644
--- a/include/apr_poll.h
+++ b/include/apr_poll.h
@@ -50,6 +50,11 @@ extern "C" {
#define APR_POLLHUP 0x020 /**< Hangup occurred */
#define APR_POLLNVAL 0x040 /**< Descriptior invalid */
+/**
+ * Pollset Flags
+ */
+#define APR_POLLSET_THREADSAFE 0x001 /**< Adding or Removing a Descriptor is thread safe */
+
/** Used in apr_pollfd_t to determine what the apr_descriptor is */
typedef enum {
APR_NO_DESC, /**< nothing here */
diff --git a/include/arch/unix/apr_arch_poll_private.h b/include/arch/unix/apr_arch_poll_private.h
new file mode 100644
index 000000000..5a9ee6e6e
--- /dev/null
+++ b/include/arch/unix/apr_arch_poll_private.h
@@ -0,0 +1,92 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#ifndef APR_ARCH_POLL_PRIVATE_H
+#define APR_ARCH_POLL_PRIVATE_H
+
+#include "apr.h"
+#include "apr_poll.h"
+#include "apr_time.h"
+#include "apr_portable.h"
+#include "apr_arch_networkio.h"
+#include "apr_arch_file_io.h"
+
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#if HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+#ifdef HAVE_KQUEUE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_EPOLL
+#include <sys/epoll.h>
+#endif
+
+#ifdef NETWARE
+#define HAS_SOCKETS(dt) (dt == APR_POLL_SOCKET) ? 1 : 0
+#define HAS_PIPES(dt) (dt == APR_POLL_FILE) ? 1 : 0
+#endif
+
+/* Choose the best method platform specific to use in apr_pollset */
+#ifdef HAVE_KQUEUE
+#define POLLSET_USES_KQUEUE
+#elif defined(HAVE_EPOLL)
+#define POLLSET_USES_EPOLL
+#elif defined(HAVE_POLL)
+#define POLLSET_USES_POLL
+#else
+#define POLLSET_USES_SELECT
+#endif
+
+#ifdef HAVE_POLL
+#define POLL_USES_POLL
+#else
+#define POLL_USES_SELECT
+#endif
+
+#if defined(POLLSET_USES_KQUEUE) || defined(POLLSET_USES_EPOLL)
+
+#include "apr_ring.h"
+
+#if APR_HAS_THREADS
+#include "apr_thread_mutex.h"
+#define pollset_lock_rings() \
+ if(pollset->flags & APR_POLLSET_THREADSAFE) \
+ apr_thread_mutex_lock(pollset->ring_lock);
+#define pollset_unlock_rings() \
+ if(pollset->flags & APR_POLLSET_THREADSAFE) \
+ apr_thread_mutex_unlock(pollset->ring_lock);
+#else
+#define pollset_lock_rings()
+#define pollset_unlock_rings()
+#endif
+
+typedef struct pfd_elem_t pfd_elem_t;
+
+struct pfd_elem_t {
+ APR_RING_ENTRY(pfd_elem_t) link;
+ apr_pollfd_t pfd;
+};
+
+#endif
+
+#endif /* APR_ARCH_POLL_PRIVATE_H */
diff --git a/poll/unix/epoll.c b/poll/unix/epoll.c
new file mode 100644
index 000000000..9bc4a7d9c
--- /dev/null
+++ b/poll/unix/epoll.c
@@ -0,0 +1,270 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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_arch_poll_private.h"
+
+#ifdef POLLSET_USES_EPOLL
+
+static apr_int16_t get_epoll_event(apr_int16_t event)
+{
+ apr_int16_t rv = 0;
+
+ if (event & APR_POLLIN)
+ rv |= EPOLLIN;
+ if (event & APR_POLLPRI)
+ rv |= EPOLLPRI;
+ if (event & APR_POLLOUT)
+ rv |= EPOLLOUT;
+ if (event & APR_POLLERR)
+ rv |= EPOLLERR;
+ if (event & APR_POLLHUP)
+ rv |= EPOLLHUP;
+ /* APR_POLLNVAL is not handled by epoll. */
+
+ return rv;
+}
+
+static apr_int16_t get_epoll_revent(apr_int16_t event)
+{
+ apr_int16_t rv = 0;
+
+ if (event & EPOLLIN)
+ rv |= APR_POLLIN;
+ if (event & EPOLLPRI)
+ rv |= APR_POLLPRI;
+ if (event & EPOLLOUT)
+ rv |= APR_POLLOUT;
+ if (event & EPOLLERR)
+ rv |= APR_POLLERR;
+ if (event & EPOLLHUP)
+ rv |= APR_POLLHUP;
+ /* APR_POLLNVAL is not handled by epoll. */
+
+ return rv;
+}
+
+struct apr_pollset_t
+{
+ apr_pool_t *pool;
+ apr_uint32_t nelts;
+ apr_uint32_t nalloc;
+ int epoll_fd;
+ struct epoll_event *pollset;
+ apr_pollfd_t *result_set;
+ apr_uint32_t flags;
+#if APR_HAS_THREADS
+ /* A thread mutex to protect operations on the rings */
+ apr_thread_mutex_t *ring_lock;
+#endif
+ /* A ring containing all of the pollfd_t that are active */
+ APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
+ /* A ring of pollfd_t that have been used, and then _remove()'d */
+ APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
+ /* A ring of pollfd_t where rings that have been _remove()`ed but
+ might still be inside a _poll() */
+ APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
+};
+
+static apr_status_t backend_cleanup(void *p_)
+{
+ apr_pollset_t *pollset = (apr_pollset_t *) p_;
+ close(pollset->epoll_fd);
+ return APR_SUCCESS;
+}
+
+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_status_t rv;
+
+ *pollset = apr_palloc(p, sizeof(**pollset));
+#if APR_HAS_THREADS
+ if (flags & APR_POLLSET_THREADSAFE &&
+ ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
+ APR_THREAD_MUTEX_DEFAULT,
+ p) != APR_SUCCESS))) {
+ *pollset = NULL;
+ return rv;
+ }
+#else
+ if (flags & APR_POLLSET_THREADSAFE) {
+ *pollset = NULL;
+ return APR_ENOTIMPL;
+ }
+#endif
+ (*pollset)->nelts = 0;
+ (*pollset)->nalloc = size;
+ (*pollset)->flags = flags;
+ (*pollset)->pool = p;
+ (*pollset)->epoll_fd = epoll_create(size);
+ (*pollset)->pollset = apr_palloc(p, size * sizeof(struct epoll_event));
+ apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
+ apr_pool_cleanup_null);
+ (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+
+ APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
+ APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
+ APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
+{
+ return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ struct epoll_event ev;
+ int ret = -1;
+ pfd_elem_t *elem;
+ apr_status_t rv = APR_SUCCESS;
+
+ pollset_lock_rings();
+
+ if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
+ elem = APR_RING_FIRST(&(pollset->free_ring));
+ APR_RING_REMOVE(elem, link);
+ }
+ else {
+ elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
+ APR_RING_ELEM_INIT(elem, link);
+ }
+ elem->pfd = *descriptor;
+
+ ev.events = get_epoll_event(descriptor->reqevents);
+ ev.data.ptr = elem;
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
+ descriptor->desc.s->socketdes, &ev);
+ }
+ else {
+ ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
+ descriptor->desc.f->filedes, &ev);
+ }
+
+ if (0 != ret) {
+ rv = APR_EBADF;
+ APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
+ }
+ else {
+ pollset->nelts++;
+ APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ pfd_elem_t *ep;
+ apr_status_t rv = APR_SUCCESS;
+ struct epoll_event ev;
+ int ret = -1;
+
+ pollset_lock_rings();
+
+ ev.events = get_epoll_event(descriptor->reqevents);
+
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
+ descriptor->desc.s->socketdes, &ev);
+ }
+ else {
+ ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
+ descriptor->desc.f->filedes, &ev);
+ }
+ if (ret < 0) {
+ rv = APR_NOTFOUND;
+ }
+
+ if (!APR_RING_EMPTY(&(pollset->query_ring), pfd_elem_t, link)) {
+ for (ep = APR_RING_FIRST(&(pollset->query_ring));
+ ep != APR_RING_SENTINEL(&(pollset->query_ring),
+ pfd_elem_t, link);
+ ep = APR_RING_NEXT(ep, link)) {
+
+ if (descriptor->desc.s == ep->pfd.desc.s) {
+ APR_RING_REMOVE(ep, link);
+ APR_RING_INSERT_TAIL(&(pollset->dead_ring),
+ ep, pfd_elem_t, link);
+ break;
+ }
+ }
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+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 ret, i;
+ apr_status_t rv = APR_SUCCESS;
+ pfd_elem_t *ep;
+
+ if (timeout > 0) {
+ timeout /= 1000;
+ }
+
+ ret = epoll_wait(pollset->epoll_fd, pollset->pollset, pollset->nalloc,
+ timeout);
+ (*num) = ret;
+
+ if (ret < 0) {
+ rv = apr_get_netos_error();
+ }
+ else if (ret == 0) {
+ rv = APR_TIMEUP;
+ }
+ else {
+ for (i = 0; i < ret; i++) {
+ pollset->result_set[i] =
+ (((pfd_elem_t *) (pollset->pollset[i].data.ptr))->pfd);
+ pollset->result_set[i].rtnevents =
+ get_epoll_revent(pollset->pollset[i].events);
+ }
+
+ if (descriptors) {
+ *descriptors = pollset->result_set;
+ }
+ }
+
+ pollset_lock_rings();
+
+ /* Shift all PFDs in the Dead Ring to be Free Ring */
+ while (!APR_RING_EMPTY(&(pollset->dead_ring), pfd_elem_t, link)) {
+ ep = APR_RING_FIRST(&(pollset->dead_ring));
+ APR_RING_REMOVE(ep, link);
+ APR_RING_INSERT_TAIL(&(pollset->free_ring), ep, pfd_elem_t, link);
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+#endif /* POLLSET_USES_EPOLL */
diff --git a/poll/unix/kqueue.c b/poll/unix/kqueue.c
new file mode 100644
index 000000000..daf46369d
--- /dev/null
+++ b/poll/unix/kqueue.c
@@ -0,0 +1,288 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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_arch_poll_private.h"
+
+#ifdef POLLSET_USES_KQUEUE
+
+static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags)
+{
+ apr_int16_t rv = 0;
+
+ if (event & EVFILT_READ)
+ rv |= APR_POLLIN;
+ if (event & EVFILT_WRITE)
+ rv |= APR_POLLOUT;
+ if (flags & EV_EOF)
+ rv |= APR_POLLHUP;
+ if (flags & EV_ERROR)
+ rv |= APR_POLLERR;
+
+ return rv;
+}
+
+struct apr_pollset_t
+{
+ apr_pool_t *pool;
+ apr_uint32_t nelts;
+ apr_uint32_t nalloc;
+ int kqueue_fd;
+ struct kevent kevent;
+ struct kevent *ke_set;
+ apr_pollfd_t *result_set;
+ apr_uint32_t flags;
+#if APR_HAS_THREADS
+ /* A thread mutex to protect operations on the rings */
+ apr_thread_mutex_t *ring_lock;
+#endif
+ /* A ring containing all of the pollfd_t that are active */
+ APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
+ /* A ring of pollfd_t that have been used, and then _remove'd */
+ APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
+ /* A ring of pollfd_t where rings that have been _remove'd but
+ might still be inside a _poll */
+ APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
+};
+
+static apr_status_t backend_cleanup(void *p_)
+{
+ apr_pollset_t *pollset = (apr_pollset_t *) p_;
+ close(pollset->kqueue_fd);
+ return APR_SUCCESS;
+}
+
+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_status_t rv = APR_SUCCESS;
+ *pollset = apr_palloc(p, sizeof(**pollset));
+#if APR_HAS_THREADS
+ if (flags & APR_POLLSET_THREADSAFE &&
+ ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
+ APR_THREAD_MUTEX_DEFAULT,
+ p) != APR_SUCCESS))) {
+ *pollset = NULL;
+ return rv;
+ }
+#else
+ if (flags & APR_POLLSET_THREADSAFE) {
+ *pollset = NULL;
+ return APR_ENOTIMPL;
+ }
+#endif
+ (*pollset)->nelts = 0;
+ (*pollset)->nalloc = size;
+ (*pollset)->flags = flags;
+ (*pollset)->pool = p;
+
+ (*pollset)->ke_set =
+ (struct kevent *) apr_palloc(p, size * sizeof(struct kevent));
+
+ memset((*pollset)->ke_set, 0, size * sizeof(struct kevent));
+
+ (*pollset)->kqueue_fd = kqueue();
+
+ if ((*pollset)->kqueue_fd == -1) {
+ return APR_ENOMEM;
+ }
+
+ apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
+ apr_pool_cleanup_null);
+
+ (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+
+ APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
+ APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
+ APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
+
+ return rv;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset)
+{
+ return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ apr_os_sock_t fd;
+ pfd_elem_t *elem;
+ apr_status_t rv = APR_SUCCESS;
+
+ pollset_lock_rings();
+
+ if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
+ elem = APR_RING_FIRST(&(pollset->free_ring));
+ APR_RING_REMOVE(elem, link);
+ }
+ else {
+ elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
+ APR_RING_ELEM_INIT(elem, link);
+ }
+ elem->pfd = *descriptor;
+
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ fd = descriptor->desc.s->socketdes;
+ }
+ else {
+ fd = descriptor->desc.f->filedes;
+ }
+
+ if (descriptor->reqevents & APR_POLLIN) {
+ EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem);
+
+ if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
+ NULL) == -1) {
+ rv = APR_ENOMEM;
+ }
+ }
+
+ if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
+ EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem);
+
+ if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
+ NULL) == -1) {
+ rv = APR_ENOMEM;
+ }
+ }
+
+ if (rv == APR_SUCCESS) {
+ pollset->nelts++;
+ APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
+ }
+ else {
+ APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
+ const apr_pollfd_t *descriptor)
+{
+ pfd_elem_t *ep;
+ apr_status_t rv = APR_SUCCESS;
+ apr_os_sock_t fd;
+
+ pollset_lock_rings();
+
+ if (descriptor->desc_type == APR_POLL_SOCKET) {
+ fd = descriptor->desc.s->socketdes;
+ }
+ else {
+ fd = descriptor->desc.f->filedes;
+ }
+
+ if (descriptor->reqevents & APR_POLLIN) {
+ EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+
+ if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
+ NULL) == -1) {
+ rv = APR_NOTFOUND;
+ }
+ }
+
+ if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
+ EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+
+ if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
+ NULL) == -1) {
+ rv = APR_NOTFOUND;
+ }
+ }
+
+ if (!APR_RING_EMPTY(&(pollset->query_ring), pfd_elem_t, link)) {
+ for (ep = APR_RING_FIRST(&(pollset->query_ring));
+ ep != APR_RING_SENTINEL(&(pollset->query_ring),
+ pfd_elem_t, link);
+ ep = APR_RING_NEXT(ep, link)) {
+
+ if (descriptor->desc.s == ep->pfd.desc.s) {
+ APR_RING_REMOVE(ep, link);
+ APR_RING_INSERT_TAIL(&(pollset->dead_ring),
+ ep, pfd_elem_t, link);
+ break;
+ }
+ }
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+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 ret, i;
+ pfd_elem_t *ep;
+ struct timespec tv, *tvptr;
+ apr_status_t rv = APR_SUCCESS;
+
+ if (timeout < 0) {
+ tvptr = NULL;
+ }
+ else {
+ tv.tv_sec = (long) apr_time_sec(timeout);
+ tv.tv_nsec = (long) apr_time_msec(timeout);
+ tvptr = &tv;
+ }
+
+ ret = kevent(pollset->kqueue_fd, NULL, 0, pollset->ke_set, pollset->nalloc,
+ tvptr);
+ (*num) = ret;
+ if (ret < 0) {
+ rv = apr_get_netos_error();
+ }
+ else if (ret == 0) {
+ rv = APR_TIMEUP;
+ }
+ else {
+ for (i = 0; i < ret; i++) {
+ pollset->result_set[i] =
+ (((pfd_elem_t*)(pollset->ke_set[i].udata))->pfd);
+ pollset->result_set[i].rtnevents =
+ get_kqueue_revent(pollset->ke_set[i].filter,
+ pollset->ke_set[i].flags);
+ }
+
+ if (descriptors) {
+ *descriptors = pollset->result_set;
+ }
+ }
+
+
+ pollset_lock_rings();
+
+ /* Shift all PFDs in the Dead Ring to be Free Ring */
+ while (!APR_RING_EMPTY(&(pollset->dead_ring), pfd_elem_t, link)) {
+ ep = APR_RING_FIRST(&(pollset->dead_ring));
+ APR_RING_REMOVE(ep, link);
+ APR_RING_INSERT_TAIL(&(pollset->free_ring), ep, pfd_elem_t, link);
+ }
+
+ pollset_unlock_rings();
+
+ return rv;
+}
+
+#endif /* POLLSET_USES_KQUEUE */
diff --git a/poll/unix/poll.c b/poll/unix/poll.c
index 42ecb480d..b2da05079 100644
--- a/poll/unix/poll.c
+++ b/poll/unix/poll.c
@@ -13,94 +13,9 @@
* limitations under the License.
*/
-#include "apr.h"
-#include "apr_poll.h"
-#include "apr_time.h"
-#include "apr_portable.h"
-#include "apr_arch_networkio.h"
-#include "apr_arch_file_io.h"
-#if HAVE_POLL_H
-#include <poll.h>
-#endif
-#if HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-
-#ifdef HAVE_KQUEUE
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#endif
-
-#ifdef HAVE_EPOLL
-#include <sys/epoll.h>
-#endif
-
-#ifdef NETWARE
-#define HAS_SOCKETS(dt) (dt == APR_POLL_SOCKET) ? 1 : 0
-#define HAS_PIPES(dt) (dt == APR_POLL_FILE) ? 1 : 0
-#endif
-
-#ifdef HAVE_KQUEUE
-static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags)
-{
- apr_int16_t rv = 0;
-
- if (event & EVFILT_READ)
- rv |= APR_POLLIN;
- if (event & EVFILT_WRITE)
- rv |= APR_POLLOUT;
- if (flags & EV_EOF)
- rv |= APR_POLLHUP;
- if (flags & EV_ERROR)
- rv |= APR_POLLERR;
-
- return rv;
-}
-
-#endif
+#include "apr_arch_poll_private.h"
-#ifdef HAVE_EPOLL
-static apr_int16_t get_epoll_event(apr_int16_t event)
-{
- apr_int16_t rv = 0;
-
- if (event & APR_POLLIN)
- rv |= EPOLLIN;
- if (event & APR_POLLPRI)
- rv |= EPOLLPRI;
- if (event & APR_POLLOUT)
- rv |= EPOLLOUT;
- if (event & APR_POLLERR)
- rv |= EPOLLERR;
- if (event & APR_POLLHUP)
- rv |= EPOLLHUP;
- /* APR_POLLNVAL is not handled by epoll. */
-
- return rv;
-}
-
-static apr_int16_t get_epoll_revent(apr_int16_t event)
-{
- apr_int16_t rv = 0;
-
- if (event & EPOLLIN)
- rv |= APR_POLLIN;
- if (event & EPOLLPRI)
- rv |= APR_POLLPRI;
- if (event & EPOLLOUT)
- rv |= APR_POLLOUT;
- if (event & EPOLLERR)
- rv |= APR_POLLERR;
- if (event & EPOLLHUP)
- rv |= APR_POLLHUP;
- /* APR_POLLNVAL is not handled by epoll. */
-
- return rv;
-}
-#endif
-
-#ifdef HAVE_POLL /* We can just use poll to do our socket polling. */
+#if defined(POLL_USES_POLL) || defined(POLLSET_USES_POLL)
static apr_int16_t get_event(apr_int16_t event)
{
@@ -142,6 +57,11 @@ static apr_int16_t get_revent(apr_int16_t event)
return rv;
}
+#endif /* POLL_USES_POLL || POLLSET_USES_POLL */
+
+
+#ifdef POLL_USES_POLL
+
#define SMALL_POLLSET_LIMIT 8
APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num,
@@ -216,298 +136,55 @@ APR_DECLARE(apr_status_t) apr_poll(apr_pollfd_t *aprset, apr_int32_t num,
}
-#else /* Use select to mimic poll */
-
-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
-
- 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();
- }
-
- 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;
- }
- }
+#endif /* POLL_USES_POLL */
- return APR_SUCCESS;
-}
-#endif
+#ifdef POLLSET_USES_POLL
-struct apr_pollset_t {
+struct apr_pollset_t
+{
apr_pool_t *pool;
-
apr_uint32_t nelts;
apr_uint32_t nalloc;
-#ifdef HAVE_KQUEUE
- int kqueue_fd;
- struct kevent kevent;
- struct kevent *ke_set;
-#elif defined(HAVE_EPOLL)
- int epoll_fd;
- struct epoll_event *pollset;
-#elif defined(HAVE_POLL)
struct pollfd *pollset;
-#else
- fd_set readset, writeset, exceptset;
- int maxfd;
-#endif
apr_pollfd_t *query_set;
apr_pollfd_t *result_set;
-
-#ifdef NETWARE
- int set_type;
-#endif
};
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-static apr_status_t backend_cleanup(void *p_)
-{
- apr_pollset_t *pollset = (apr_pollset_t *)p_;
-#ifdef HAVE_KQUEUE
- close(pollset->kqueue_fd);
-#elif defined(HAVE_EPOLL)
- close(pollset->epoll_fd);
-#endif
- return APR_SUCCESS;
-}
-#endif /* HAVE_KQUEUE || HAVE_EPOLL */
-
APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
apr_uint32_t size,
apr_pool_t *p,
apr_uint32_t flags)
{
-#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL) && !defined(HAVE_POLL) && defined(FD_SETSIZE)
- if (size > FD_SETSIZE) {
+ if (flags & APR_POLLSET_THREADSAFE) {
*pollset = NULL;
- return APR_EINVAL;
+ return APR_ENOTIMPL;
}
-#endif
+
*pollset = apr_palloc(p, sizeof(**pollset));
(*pollset)->nelts = 0;
(*pollset)->nalloc = size;
(*pollset)->pool = p;
-#ifdef HAVE_KQUEUE
- (*pollset)->ke_set = (struct kevent*)apr_palloc(p, size * sizeof(struct kevent));
- memset((*pollset)->ke_set, 0, size * sizeof(struct kevent));
- (*pollset)->kqueue_fd = kqueue();
- if ((*pollset)->kqueue_fd == -1) {
- return APR_ENOMEM;
- }
- apr_pool_cleanup_register(p, (void*)(*pollset), backend_cleanup,
- apr_pool_cleanup_null);
-#elif defined(HAVE_EPOLL)
- (*pollset)->epoll_fd = epoll_create(size);
- (*pollset)->pollset = apr_palloc(p, size * sizeof(struct epoll_event));
- apr_pool_cleanup_register(p, (void*)(*pollset), backend_cleanup,
- apr_pool_cleanup_null);
-#elif defined(HAVE_POLL)
(*pollset)->pollset = apr_palloc(p, size * sizeof(struct pollfd));
-#else
- FD_ZERO(&((*pollset)->readset));
- FD_ZERO(&((*pollset)->writeset));
- FD_ZERO(&((*pollset)->exceptset));
- (*pollset)->maxfd = 0;
-#ifdef NETWARE
- (*pollset)->set_type = APR_NO_DESC;
-#endif
-#endif
(*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
(*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
-
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
{
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
- return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
-#else
return APR_SUCCESS;
-#endif
}
APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
const apr_pollfd_t *descriptor)
{
-#ifdef HAVE_KQUEUE
- apr_os_sock_t fd;
-#elif defined(HAVE_EPOLL)
- struct epoll_event ev;
- int ret = -1;
-#else
-#if !defined(HAVE_POLL)
- apr_os_sock_t fd;
-#endif
-#endif
-
if (pollset->nelts == pollset->nalloc) {
return APR_ENOMEM;
}
pollset->query_set[pollset->nelts] = *descriptor;
-#ifdef HAVE_KQUEUE
- if (descriptor->desc_type == APR_POLL_SOCKET) {
- fd = descriptor->desc.s->socketdes;
- }
- else {
- fd = descriptor->desc.f->filedes;
- }
-
- if (descriptor->reqevents & APR_POLLIN) {
- EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
-
- if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
- NULL) == -1) {
- return APR_ENOMEM;
- }
- }
-
- if (descriptor->reqevents & APR_POLLOUT) {
- EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
-
- if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
- NULL) == -1) {
- return APR_ENOMEM;
- }
- }
-
-#elif defined(HAVE_EPOLL)
- ev.events = get_epoll_event(descriptor->reqevents);
- if (descriptor->desc_type == APR_POLL_SOCKET) {
- ev.data.fd = descriptor->desc.s->socketdes;
- ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
- descriptor->desc.s->socketdes, &ev);
- }
- else {
- ev.data.fd = descriptor->desc.f->filedes;
- ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
- descriptor->desc.f->filedes, &ev);
- }
- if (0 != ret) {
- return APR_EBADF;
- }
-#elif defined(HAVE_POLL)
-
if (descriptor->desc_type == APR_POLL_SOCKET) {
pollset->pollset[pollset->nelts].fd = descriptor->desc.s->socketdes;
}
@@ -515,59 +192,10 @@ APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
pollset->pollset[pollset->nelts].fd = descriptor->desc.f->filedes;
}
- pollset->pollset[pollset->nelts].events = get_event(descriptor->reqevents);
-#else
- if (descriptor->desc_type == APR_POLL_SOCKET) {
-#ifdef NETWARE
- /* NetWare can't handle mixed descriptor types in select() */
- if (HAS_PIPES(pollset->set_type)) {
- return APR_EBADF;
- }
- else {
- pollset->set_type = APR_POLL_SOCKET;
- }
-#endif
- fd = descriptor->desc.s->socketdes;
- }
- else {
-#if !APR_FILES_AS_SOCKETS
- return APR_EBADF;
-#else
-#ifdef NETWARE
- /* NetWare can't handle mixed descriptor types in select() */
- if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->set_type)) {
- pollset->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->readset));
- }
- if (descriptor->reqevents & APR_POLLOUT) {
- FD_SET(fd, &(pollset->writeset));
- }
- if (descriptor->reqevents &
- (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
- FD_SET(fd, &(pollset->exceptset));
- }
- if ((int)fd > pollset->maxfd) {
- pollset->maxfd = (int)fd;
- }
-#endif
+ pollset->pollset[pollset->nelts].events =
+ get_event(descriptor->reqevents);
pollset->nelts++;
+
return APR_SUCCESS;
}
@@ -575,97 +203,8 @@ APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
const apr_pollfd_t *descriptor)
{
apr_uint32_t i;
-#ifdef HAVE_KQUEUE
apr_os_sock_t fd;
-#elif defined(HAVE_EPOLL)
- struct epoll_event ev;
- int ret = -1;
-#elif !defined(HAVE_POLL)
- apr_os_sock_t fd;
-#endif
-#ifdef HAVE_KQUEUE
- 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->query_set[dst] = pollset->query_set[i];
- dst++;
- }
- }
-
- if (descriptor->desc_type == APR_POLL_SOCKET) {
- fd = descriptor->desc.s->socketdes;
- }
- else {
- fd = descriptor->desc.f->filedes;
- }
-
- if (descriptor->reqevents & APR_POLLIN) {
- EV_SET(&pollset->kevent, fd,
- EVFILT_READ, EV_DELETE, 0, 0, NULL);
-
- if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
- NULL) == -1) {
- return APR_EBADF;
- }
- }
-
- if (descriptor->reqevents & APR_POLLOUT) {
- EV_SET(&pollset->kevent, fd,
- EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
-
- if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0,
- NULL) == -1) {
- return APR_EBADF;
- }
- }
-
- return APR_SUCCESS;
- }
- }
-#elif defined(HAVE_EPOLL)
- 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->query_set[dst] = pollset->query_set[i];
- dst++;
- }
- }
- ev.events = get_epoll_event(descriptor->reqevents);
- if (descriptor->desc_type == APR_POLL_SOCKET) {
- ev.data.fd = descriptor->desc.s->socketdes;
- ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
- descriptor->desc.s->socketdes, &ev);
- }
- else {
- ev.data.fd = descriptor->desc.f->filedes;
- ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_DEL,
- descriptor->desc.f->filedes, &ev);
- }
- if (ret < 0) {
- return APR_EBADF;
- }
-
- return APR_SUCCESS;
- }
- }
-#elif defined(HAVE_POLL)
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 */
@@ -686,105 +225,8 @@ APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
}
}
-#else /* no poll */
- 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->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->query_set[dst] = pollset->query_set[i];
- dst++;
- }
- }
- FD_CLR(fd, &(pollset->readset));
- FD_CLR(fd, &(pollset->writeset));
- FD_CLR(fd, &(pollset->exceptset));
- if (((int)fd == pollset->maxfd) && (pollset->maxfd > 0)) {
- pollset->maxfd--;
- }
- return APR_SUCCESS;
- }
- }
-#endif /* no poll */
-
return APR_NOTFOUND;
}
-#ifdef HAVE_KQUEUE
-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, j, r = 0;
- struct timespec tv, *tvptr;
-
- if (timeout < 0) {
- tvptr = NULL;
- }
- else {
- tv.tv_sec = (long)apr_time_sec(timeout);
- tv.tv_nsec = (long)apr_time_msec(timeout);
- tvptr = &tv;
- }
-
- rv = kevent(pollset->kqueue_fd, NULL, 0, pollset->ke_set, pollset->nelts,
- tvptr);
- (*num) = rv;
- if (rv < 0) {
- return apr_get_netos_error();
- }
- if (rv == 0) {
- return APR_TIMEUP;
- }
-
- /* TODO: Is there a better way to re-associate our data? */
- for (i = 0; i < pollset->nelts; i++) {
- apr_os_sock_t fd;
- if (pollset->query_set[i].desc_type == APR_POLL_SOCKET) {
- fd = pollset->query_set[i].desc.s->socketdes;
- }
- else {
- fd = pollset->query_set[i].desc.f->filedes;
- }
- for (j = 0; j < rv; j++) {
- if (pollset->ke_set[j].ident == fd ) {
- pollset->result_set[r] = pollset->query_set[i];
- pollset->result_set[r].rtnevents =
- get_kqueue_revent(pollset->ke_set[j].filter,
- pollset->ke_set[j].flags);
- r++;
- }
- }
- }
-
- (*num) = r;
-
- if (descriptors) {
- *descriptors = pollset->result_set;
- }
-
- return APR_SUCCESS;
-}
-
-#elif defined(HAVE_EPOLL)
APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
apr_interval_time_t timeout,
@@ -792,59 +234,6 @@ APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
const apr_pollfd_t **descriptors)
{
int rv;
- apr_uint32_t i, j, k;
-
- if (timeout > 0) {
- timeout /= 1000;
- }
-
- rv = epoll_wait(pollset->epoll_fd, pollset->pollset, pollset->nelts,
- timeout);
- (*num) = rv;
- if (rv < 0) {
- return apr_get_netos_error();
- }
- if (rv == 0) {
- return APR_TIMEUP;
- }
- j = 0;
- for (i = 0; i < pollset->nelts; i++) {
- if (pollset->pollset[i].events != 0) {
- /* TODO: Is there a better way to re-associate our data? */
- for (k = 0; k < pollset->nelts; k++) {
- if (pollset->query_set[k].desc_type == APR_POLL_SOCKET &&
- pollset->query_set[k].desc.s->socketdes ==
- pollset->pollset[i].data.fd) {
- pollset->result_set[j] = pollset->query_set[k];
- pollset->result_set[j].rtnevents =
- get_epoll_revent(pollset->pollset[i].events);
- j++;
- break;
- }
- else if (pollset->query_set[k].desc_type == APR_POLL_FILE
- && pollset->query_set[k].desc.f->filedes ==
- pollset->pollset[i].data.fd) {
- pollset->result_set[j] = pollset->query_set[k];
- pollset->result_set[j].rtnevents =
- get_epoll_revent(pollset->pollset[i].events);
- j++;
- break;
- }
- }
- }
- }
- if (descriptors) {
- *descriptors = pollset->result_set;
- }
- return APR_SUCCESS;
-}
-#elif defined(HAVE_POLL)
-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, j;
if (timeout > 0) {
@@ -872,79 +261,4 @@ APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
return APR_SUCCESS;
}
-#else /* no poll */
-
-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, j;
- struct timeval tv, *tvptr;
- fd_set readset, writeset, exceptset;
-
- 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->readset), sizeof(fd_set));
- memcpy(&writeset, &(pollset->writeset), sizeof(fd_set));
- memcpy(&exceptset, &(pollset->exceptset), sizeof(fd_set));
-
-#ifdef NETWARE
- if (HAS_PIPES(pollset->set_type)) {
- rv = pipe_select(pollset->maxfd + 1, &readset, &writeset, &exceptset, tvptr);
- }
- else
-#endif
- rv = select(pollset->maxfd + 1, &readset, &writeset, &exceptset, tvptr);
-
- (*num) = rv;
- if (rv < 0) {
- return apr_get_netos_error();
- }
- if (rv == 0) {
- return APR_TIMEUP;
- }
- j = 0;
- for (i = 0; i < pollset->nelts; i++) {
- apr_os_sock_t fd;
- if (pollset->query_set[i].desc_type == APR_POLL_SOCKET) {
- fd = pollset->query_set[i].desc.s->socketdes;
- }
- else {
-#if !APR_FILES_AS_SOCKETS
- return APR_EBADF;
-#else
- fd = pollset->query_set[i].desc.f->filedes;
-#endif
- }
- if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
- FD_ISSET(fd, &exceptset)) {
- pollset->result_set[j] = pollset->query_set[i];
- pollset->result_set[j].rtnevents = 0;
- if (FD_ISSET(fd, &readset)) {
- pollset->result_set[j].rtnevents |= APR_POLLIN;
- }
- if (FD_ISSET(fd, &writeset)) {
- pollset->result_set[j].rtnevents |= APR_POLLOUT;
- }
- if (FD_ISSET(fd, &exceptset)) {
- pollset->result_set[j].rtnevents |= APR_POLLERR;
- }
- j++;
- }
- }
-
- if (descriptors)
- *descriptors = pollset->result_set;
- return APR_SUCCESS;
-}
-
-#endif /* no poll */
+#endif /* POLLSET_USES_POLL */
diff --git a/poll/unix/select.c b/poll/unix/select.c
new file mode 100644
index 000000000..c1b657e44
--- /dev/null
+++ b/poll/unix/select.c
@@ -0,0 +1,392 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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_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
+
+ 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();
+ }
+
+ 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;
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+#endif /* POLL_USES_SELECT */
+
+#ifdef POLLSET_USES_SELECT
+
+struct apr_pollset_t
+{
+ apr_pool_t *pool;
+
+ apr_uint32_t nelts;
+ apr_uint32_t nalloc;
+ fd_set readset, writeset, exceptset;
+ int maxfd;
+ apr_pollfd_t *query_set;
+ apr_pollfd_t *result_set;
+#ifdef NETWARE
+ int set_type;
+#endif
+};
+
+APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
+ apr_uint32_t size,
+ apr_pool_t *p,
+ apr_uint32_t flags)
+{
+ if (flags & APR_POLLSET_THREADSAFE) {
+ *pollset = NULL;
+ return APR_ENOTIMPL;
+ }
+#ifdef FD_SETSIZE
+ if (size > FD_SETSIZE) {
+ *pollset = NULL;
+ return APR_EINVAL;
+ }
+#endif
+ *pollset = apr_palloc(p, sizeof(**pollset));
+ (*pollset)->nelts = 0;
+ (*pollset)->nalloc = size;
+ (*pollset)->pool = p;
+ FD_ZERO(&((*pollset)->readset));
+ FD_ZERO(&((*pollset)->writeset));
+ FD_ZERO(&((*pollset)->exceptset));
+ (*pollset)->maxfd = 0;
+#ifdef NETWARE
+ (*pollset)->set_type = APR_NO_DESC;
+#endif
+ (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+ (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset)
+{
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_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->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->set_type)) {
+ return APR_EBADF;
+ }
+ else {
+ pollset->set_type = APR_POLL_SOCKET;
+ }
+#endif
+ fd = descriptor->desc.s->socketdes;
+ }
+ else {
+#if !APR_FILES_AS_SOCKETS
+ return APR_EBADF;
+#else
+#ifdef NETWARE
+ /* NetWare can't handle mixed descriptor types in select() */
+ if (descriptor->desc.f->is_pipe && !HAS_SOCKETS(pollset->set_type)) {
+ pollset->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->readset));
+ }
+ if (descriptor->reqevents & APR_POLLOUT) {
+ FD_SET(fd, &(pollset->writeset));
+ }
+ if (descriptor->reqevents &
+ (APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL)) {
+ FD_SET(fd, &(pollset->exceptset));
+ }
+ if ((int) fd > pollset->maxfd) {
+ pollset->maxfd = (int) fd;
+ }
+ pollset->nelts++;
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_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->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->query_set[dst] = pollset->query_set[i];
+ dst++;
+ }
+ }
+ FD_CLR(fd, &(pollset->readset));
+ FD_CLR(fd, &(pollset->writeset));
+ FD_CLR(fd, &(pollset->exceptset));
+ if (((int) fd == pollset->maxfd) && (pollset->maxfd > 0)) {
+ pollset->maxfd--;
+ }
+ return APR_SUCCESS;
+ }
+ }
+
+ return APR_NOTFOUND;
+}
+
+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, j;
+ struct timeval tv, *tvptr;
+ fd_set readset, writeset, exceptset;
+
+ 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->readset), sizeof(fd_set));
+ memcpy(&writeset, &(pollset->writeset), sizeof(fd_set));
+ memcpy(&exceptset, &(pollset->exceptset), sizeof(fd_set));
+
+#ifdef NETWARE
+ if (HAS_PIPES(pollset->set_type)) {
+ rv = pipe_select(pollset->maxfd + 1, &readset, &writeset, &exceptset,
+ tvptr);
+ }
+ else
+#endif
+ rv = select(pollset->maxfd + 1, &readset, &writeset, &exceptset,
+ tvptr);
+
+ (*num) = rv;
+ if (rv < 0) {
+ return apr_get_netos_error();
+ }
+ if (rv == 0) {
+ return APR_TIMEUP;
+ }
+ j = 0;
+ for (i = 0; i < pollset->nelts; i++) {
+ apr_os_sock_t fd;
+ if (pollset->query_set[i].desc_type == APR_POLL_SOCKET) {
+ fd = pollset->query_set[i].desc.s->socketdes;
+ }
+ else {
+#if !APR_FILES_AS_SOCKETS
+ return APR_EBADF;
+#else
+ fd = pollset->query_set[i].desc.f->filedes;
+#endif
+ }
+ if (FD_ISSET(fd, &readset) || FD_ISSET(fd, &writeset) ||
+ FD_ISSET(fd, &exceptset)) {
+ pollset->result_set[j] = pollset->query_set[i];
+ pollset->result_set[j].rtnevents = 0;
+ if (FD_ISSET(fd, &readset)) {
+ pollset->result_set[j].rtnevents |= APR_POLLIN;
+ }
+ if (FD_ISSET(fd, &writeset)) {
+ pollset->result_set[j].rtnevents |= APR_POLLOUT;
+ }
+ if (FD_ISSET(fd, &exceptset)) {
+ pollset->result_set[j].rtnevents |= APR_POLLERR;
+ }
+ j++;
+ }
+ }
+
+ if (descriptors)
+ *descriptors = pollset->result_set;
+ return APR_SUCCESS;
+}
+
+#endif /* POLLSET_USES_SELECT */