diff options
Diffstat (limited to 'poll/unix/kqueue.c')
-rw-r--r-- | poll/unix/kqueue.c | 355 |
1 files changed, 147 insertions, 208 deletions
diff --git a/poll/unix/kqueue.c b/poll/unix/kqueue.c index 34ec1dd42..dbe785a15 100644 --- a/poll/unix/kqueue.c +++ b/poll/unix/kqueue.c @@ -14,10 +14,16 @@ * limitations under the License. */ +#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" -#ifdef POLLSET_USES_KQUEUE +#ifdef HAVE_KQUEUE static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) { @@ -25,28 +31,25 @@ static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) if (event == EVFILT_READ) rv |= APR_POLLIN; - if (event == EVFILT_WRITE) + else if (event == EVFILT_WRITE) rv |= APR_POLLOUT; if (flags & EV_EOF) rv |= APR_POLLHUP; - if (flags & EV_ERROR) - rv |= APR_POLLERR; - + /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this + * implementation. + * TODO: See if EV_ERROR + certain system errors in the returned data field + * should map to APR_POLLNVAL. + */ return rv; } -struct apr_pollset_t +struct apr_pollset_private_t { - apr_pool_t *pool; - apr_uint32_t nelts; - apr_uint32_t nalloc; int kqueue_fd; struct kevent kevent; + apr_uint32_t setsize; struct kevent *ke_set; apr_pollfd_t *result_set; - apr_uint32_t flags; - /* Pipe descriptors used for wakeup */ - apr_file_t *wakeup_pipe[2]; #if APR_HAS_THREADS /* A thread mutex to protect operations on the rings */ apr_thread_mutex_t *ring_lock; @@ -60,140 +63,77 @@ struct apr_pollset_t APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; }; -static apr_status_t backend_cleanup(void *p_) +static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) { - apr_pollset_t *pollset = (apr_pollset_t *) p_; - close(pollset->kqueue_fd); - if (pollset->flags & APR_POLLSET_WAKEABLE) { - /* Close both sides of the wakeup pipe */ - if (pollset->wakeup_pipe[0]) { - apr_file_close(pollset->wakeup_pipe[0]); - pollset->wakeup_pipe[0] = NULL; - } - if (pollset->wakeup_pipe[1]) { - apr_file_close(pollset->wakeup_pipe[1]); - pollset->wakeup_pipe[1] = NULL; - } - } + close(pollset->p->kqueue_fd); return APR_SUCCESS; } -/* Create a dummy wakeup pipe for interrupting the poller - */ -static apr_status_t create_wakeup_pipe(apr_pollset_t *pollset) +static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) { apr_status_t rv; - apr_pollfd_t fd; - - if ((rv = apr_file_pipe_create(&pollset->wakeup_pipe[0], - &pollset->wakeup_pipe[1], - pollset->pool)) != APR_SUCCESS) - return rv; - fd.reqevents = APR_POLLIN; - fd.desc_type = APR_POLL_FILE; - fd.desc.f = pollset->wakeup_pipe[0]; - /* Add the pipe to the pollset - */ - return apr_pollset_add(pollset, &fd); -} - -/* Read and discard what's ever in the wakeup pipe. - */ -static void 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 treads could call the wakeup. - * So simply drain out from the input side of the pipe all - * the data. - */ - if (nr != sizeof(rb)) - break; - } -} - -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)); + pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); #if APR_HAS_THREADS if (flags & APR_POLLSET_THREADSAFE && - ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock, + ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS)) { - *pollset = NULL; + pollset->p = NULL; return rv; } #else if (flags & APR_POLLSET_THREADSAFE) { - *pollset = NULL; + pollset->p = NULL; return APR_ENOTIMPL; } #endif - if (flags & APR_POLLSET_WAKEABLE) { - /* Add room for wakeup descriptor */ - size++; - } - (*pollset)->nelts = 0; - (*pollset)->nalloc = size; - (*pollset)->flags = flags; - (*pollset)->pool = p; + /* POLLIN and POLLOUT are represented in different returned + * events, so we need 2 entries per descriptor in the result set, + * both for what is returned by kevent() and what is returned to + * the caller of apr_pollset_poll() (since it doesn't spend the + * CPU to coalesce separate APR_POLLIN and APR_POLLOUT events + * for the same descriptor) + */ + pollset->p->setsize = 2 * size; - (*pollset)->ke_set = - (struct kevent *) apr_palloc(p, size * sizeof(struct kevent)); + pollset->p->ke_set = + (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent)); - memset((*pollset)->ke_set, 0, size * sizeof(struct kevent)); + memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent)); - (*pollset)->kqueue_fd = kqueue(); + pollset->p->kqueue_fd = kqueue(); - if ((*pollset)->kqueue_fd == -1) { + if (pollset->p->kqueue_fd == -1) { + pollset->p = NULL; return apr_get_netos_error(); } { int flags; - if ((flags = fcntl((*pollset)->kqueue_fd, F_GETFD)) == -1) + if ((flags = fcntl(pollset->p->kqueue_fd, F_GETFD)) == -1) return errno; flags |= FD_CLOEXEC; - if (fcntl((*pollset)->kqueue_fd, F_SETFD, flags) == -1) + if (fcntl(pollset->p->kqueue_fd, F_SETFD, flags) == -1) return errno; } - (*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); - if (flags & APR_POLLSET_WAKEABLE) { - /* Create wakeup pipe */ - if ((rv = create_wakeup_pipe(*pollset)) != APR_SUCCESS) { - close((*pollset)->kqueue_fd); - *pollset = NULL; - return rv; - } - } - apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup, - apr_pool_cleanup_null); + pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t)); - return rv; -} + APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); -APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t * pollset) -{ - return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup); + return APR_SUCCESS; } -APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, - const apr_pollfd_t *descriptor) +static apr_status_t impl_pollset_add(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) { apr_os_sock_t fd; pfd_elem_t *elem; @@ -201,8 +141,8 @@ APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, pollset_lock_rings(); - if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) { - elem = APR_RING_FIRST(&(pollset->free_ring)); + if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { + elem = APR_RING_FIRST(&(pollset->p->free_ring)); APR_RING_REMOVE(elem, link); } else { @@ -219,29 +159,28 @@ APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, } if (descriptor->reqevents & APR_POLLIN) { - EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); + EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); - if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0, + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, NULL) == -1) { rv = apr_get_netos_error(); } } if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { - EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); + EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); - if (kevent(pollset->kqueue_fd, &pollset->kevent, 1, NULL, 0, + if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, NULL) == -1) { rv = apr_get_netos_error(); } } if (rv == APR_SUCCESS) { - pollset->nelts++; - APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link); + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); } else { - APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link); + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); } pollset_unlock_rings(); @@ -249,11 +188,11 @@ APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset, return rv; } -APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, - const apr_pollfd_t *descriptor) +static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, + const apr_pollfd_t *descriptor) { pfd_elem_t *ep; - apr_status_t rv = APR_SUCCESS; + apr_status_t rv; apr_os_sock_t fd; pollset_lock_rings(); @@ -265,36 +204,35 @@ APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, fd = descriptor->desc.f->filedes; } + rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ if (descriptor->reqevents & APR_POLLIN) { - EV_SET(&pollset->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + EV_SET(&pollset->p->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 (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) != -1) { + rv = APR_SUCCESS; } } - if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { - EV_SET(&pollset->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + if (descriptor->reqevents & APR_POLLOUT) { + EV_SET(&pollset->p->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 (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, + NULL) != -1) { + rv = APR_SUCCESS; } } - 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)) { + for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->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; - } + if (descriptor->desc.s == ep->pfd.desc.s) { + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), + ep, pfd_elem_t, link); + break; } } @@ -303,10 +241,10 @@ APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset, 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) +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 ret, i, j; struct timespec tv, *tvptr; @@ -322,8 +260,8 @@ APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, tvptr = &tv; } - ret = kevent(pollset->kqueue_fd, NULL, 0, pollset->ke_set, pollset->nalloc, - tvptr); + ret = kevent(pollset->p->kqueue_fd, NULL, 0, pollset->p->ke_set, + pollset->p->setsize, tvptr); (*num) = ret; if (ret < 0) { rv = apr_get_netos_error(); @@ -333,72 +271,68 @@ APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset, } else { for (i = 0, j = 0; i < ret; i++) { - fd = (((pfd_elem_t*)(pollset->ke_set[i].udata))->pfd); + fd = (((pfd_elem_t*)(pollset->p->ke_set[i].udata))->pfd); if ((pollset->flags & APR_POLLSET_WAKEABLE) && fd.desc_type == APR_POLL_FILE && fd.desc.f == pollset->wakeup_pipe[0]) { - drain_wakeup_pipe(pollset); + apr_pollset_drain_wakeup_pipe(pollset); rv = APR_EINTR; } else { - pollset->result_set[j] = fd; - pollset->result_set[j].rtnevents = - get_kqueue_revent(pollset->ke_set[i].filter, - pollset->ke_set[i].flags); + pollset->p->result_set[j] = fd; + pollset->p->result_set[j].rtnevents = + get_kqueue_revent(pollset->p->ke_set[i].filter, + pollset->p->ke_set[i].flags); j++; } } - if ((*num = j)) + if ((*num = j)) { /* any event besides wakeup pipe? */ rv = APR_SUCCESS; - if (descriptors) { - *descriptors = pollset->result_set; + if (descriptors) { + *descriptors = pollset->p->result_set; + } } } pollset_lock_rings(); - /* Shift all PFDs in the Dead Ring to be Free Ring */ - APR_RING_CONCAT(&(pollset->free_ring), &(pollset->dead_ring), pfd_elem_t, link); + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), + pfd_elem_t, link); pollset_unlock_rings(); return rv; } -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; -} - -struct apr_pollcb_t { - apr_pool_t *pool; - apr_uint32_t nalloc; - struct kevent *pollset; - int kqfd; +static apr_pollset_provider_t impl = { + impl_pollset_create, + impl_pollset_add, + impl_pollset_remove, + impl_pollset_poll, + impl_pollset_cleanup, + "kqueue" }; +apr_pollset_provider_t *apr_pollset_provider_kqueue = &impl; + static apr_status_t cb_cleanup(void *b_) { apr_pollcb_t *pollcb = (apr_pollcb_t *) b_; - close(pollcb->kqfd); + close(pollcb->fd); return APR_SUCCESS; } - -APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, - apr_uint32_t size, - apr_pool_t *p, - apr_uint32_t flags) +static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t size, + apr_pool_t *p, + apr_uint32_t flags) { int fd; fd = kqueue(); if (fd < 0) { - *pollcb = NULL; return apr_get_netos_error(); } @@ -413,18 +347,15 @@ APR_DECLARE(apr_status_t) apr_pollcb_create(apr_pollcb_t **pollcb, return errno; } - *pollcb = apr_palloc(p, sizeof(**pollcb)); - (*pollcb)->nalloc = size; - (*pollcb)->pool = p; - (*pollcb)->kqfd = fd; - (*pollcb)->pollset = (struct kevent *)apr_pcalloc(p, size * sizeof(struct kevent)); - apr_pool_cleanup_register(p, *pollcb, cb_cleanup, cb_cleanup); + pollcb->fd = fd; + pollcb->pollset.ke = (struct kevent *)apr_pcalloc(p, 2 * size * sizeof(struct kevent)); + apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); return APR_SUCCESS; } -APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, - apr_pollfd_t *descriptor) +static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) { apr_os_sock_t fd; struct kevent ev; @@ -440,7 +371,7 @@ APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, if (descriptor->reqevents & APR_POLLIN) { EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor); - if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) { + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { rv = apr_get_netos_error(); } } @@ -448,7 +379,7 @@ APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor); - if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) { + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { rv = apr_get_netos_error(); } } @@ -456,10 +387,10 @@ APR_DECLARE(apr_status_t) apr_pollcb_add(apr_pollcb_t *pollcb, return rv; } -APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, - apr_pollfd_t *descriptor) +static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, + apr_pollfd_t *descriptor) { - apr_status_t rv = APR_SUCCESS; + apr_status_t rv; struct kevent ev; apr_os_sock_t fd; @@ -469,23 +400,21 @@ APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, else { fd = descriptor->desc.f->filedes; } - + + rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ if (descriptor->reqevents & APR_POLLIN) { EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); - if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) { - rv = APR_NOTFOUND; + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { + rv = APR_SUCCESS; } } - if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { - /* XXXX: this is less than optimal, shouldn't we still try to - * remove the FD even if it wasn't in the readset? - */ + if (descriptor->reqevents & APR_POLLOUT) { EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - if (kevent(pollcb->kqfd, &ev, 1, NULL, 0, NULL) == -1) { - rv = APR_NOTFOUND; + if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { + rv = APR_SUCCESS; } } @@ -493,10 +422,10 @@ APR_DECLARE(apr_status_t) apr_pollcb_remove(apr_pollcb_t *pollcb, } -APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, - apr_interval_time_t timeout, - apr_pollcb_cb_t func, - void *baton) +static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, + apr_interval_time_t timeout, + apr_pollcb_cb_t func, + void *baton) { int ret, i; struct timespec tv, *tvptr; @@ -511,7 +440,7 @@ APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, tvptr = &tv; } - ret = kevent(pollcb->kqfd, NULL, 0, pollcb->pollset, pollcb->nalloc, + ret = kevent(pollcb->fd, NULL, 0, pollcb->pollset.ke, 2 * pollcb->nalloc, tvptr); if (ret < 0) { @@ -522,10 +451,10 @@ APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, } else { for (i = 0; i < ret; i++) { - apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset[i].udata); + apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.ke[i].udata); - pollfd->rtnevents = get_kqueue_revent(pollcb->pollset[i].filter, - pollcb->pollset[i].flags); + pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter, + pollcb->pollset.ke[i].flags); rv = func(baton, pollfd); @@ -538,4 +467,14 @@ APR_DECLARE(apr_status_t) apr_pollcb_poll(apr_pollcb_t *pollcb, return rv; } -#endif /* POLLSET_USES_KQUEUE */ +static apr_pollcb_provider_t impl_cb = { + impl_pollcb_create, + impl_pollcb_add, + impl_pollcb_remove, + impl_pollcb_poll, + "kqueue" +}; + +apr_pollcb_provider_t *apr_pollcb_provider_kqueue = &impl_cb; + +#endif /* HAVE_KQUEUE */ |