1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr.h" 18251875Speter#include "apr_poll.h" 19251875Speter#include "apr_time.h" 20251875Speter#include "apr_portable.h" 21251875Speter#include "apr_arch_file_io.h" 22251875Speter#include "apr_arch_networkio.h" 23251875Speter#include "apr_arch_poll_private.h" 24251875Speter#include "apr_arch_inherit.h" 25251875Speter 26251875Speter#ifdef HAVE_KQUEUE 27251875Speter 28251875Speterstatic apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags) 29251875Speter{ 30251875Speter apr_int16_t rv = 0; 31251875Speter 32251875Speter if (event == EVFILT_READ) 33251875Speter rv |= APR_POLLIN; 34251875Speter else if (event == EVFILT_WRITE) 35251875Speter rv |= APR_POLLOUT; 36251875Speter if (flags & EV_EOF) 37251875Speter rv |= APR_POLLHUP; 38251875Speter /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this 39251875Speter * implementation. 40251875Speter * TODO: See if EV_ERROR + certain system errors in the returned data field 41251875Speter * should map to APR_POLLNVAL. 42251875Speter */ 43251875Speter return rv; 44251875Speter} 45251875Speter 46251875Speterstruct apr_pollset_private_t 47251875Speter{ 48251875Speter int kqueue_fd; 49251875Speter struct kevent kevent; 50251875Speter apr_uint32_t setsize; 51251875Speter struct kevent *ke_set; 52251875Speter apr_pollfd_t *result_set; 53251875Speter#if APR_HAS_THREADS 54251875Speter /* A thread mutex to protect operations on the rings */ 55251875Speter apr_thread_mutex_t *ring_lock; 56251875Speter#endif 57251875Speter /* A ring containing all of the pollfd_t that are active */ 58251875Speter APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; 59251875Speter /* A ring of pollfd_t that have been used, and then _remove'd */ 60251875Speter APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; 61251875Speter /* A ring of pollfd_t where rings that have been _remove'd but 62251875Speter might still be inside a _poll */ 63251875Speter APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; 64251875Speter}; 65251875Speter 66251875Speterstatic apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) 67251875Speter{ 68251875Speter close(pollset->p->kqueue_fd); 69251875Speter return APR_SUCCESS; 70251875Speter} 71251875Speter 72251875Speterstatic apr_status_t impl_pollset_create(apr_pollset_t *pollset, 73251875Speter apr_uint32_t size, 74251875Speter apr_pool_t *p, 75251875Speter apr_uint32_t flags) 76251875Speter{ 77251875Speter apr_status_t rv; 78251875Speter pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); 79251875Speter#if APR_HAS_THREADS 80251875Speter if (flags & APR_POLLSET_THREADSAFE && 81251875Speter ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, 82251875Speter APR_THREAD_MUTEX_DEFAULT, 83251875Speter p)) != APR_SUCCESS)) { 84251875Speter pollset->p = NULL; 85251875Speter return rv; 86251875Speter } 87251875Speter#else 88251875Speter if (flags & APR_POLLSET_THREADSAFE) { 89251875Speter pollset->p = NULL; 90251875Speter return APR_ENOTIMPL; 91251875Speter } 92251875Speter#endif 93251875Speter 94251875Speter /* POLLIN and POLLOUT are represented in different returned 95251875Speter * events, so we need 2 entries per descriptor in the result set, 96251875Speter * both for what is returned by kevent() and what is returned to 97251875Speter * the caller of apr_pollset_poll() (since it doesn't spend the 98251875Speter * CPU to coalesce separate APR_POLLIN and APR_POLLOUT events 99251875Speter * for the same descriptor) 100251875Speter */ 101251875Speter pollset->p->setsize = 2 * size; 102251875Speter 103251875Speter pollset->p->ke_set = 104251875Speter (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent)); 105251875Speter 106251875Speter memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent)); 107251875Speter 108251875Speter pollset->p->kqueue_fd = kqueue(); 109251875Speter 110251875Speter if (pollset->p->kqueue_fd == -1) { 111251875Speter pollset->p = NULL; 112251875Speter return apr_get_netos_error(); 113251875Speter } 114251875Speter 115251875Speter { 116251875Speter int flags; 117251875Speter 118289166Speter if ((flags = fcntl(pollset->p->kqueue_fd, F_GETFD)) == -1) { 119289166Speter rv = errno; 120289166Speter close(pollset->p->kqueue_fd); 121289166Speter pollset->p = NULL; 122289166Speter return rv; 123289166Speter } 124251875Speter 125251875Speter flags |= FD_CLOEXEC; 126289166Speter if (fcntl(pollset->p->kqueue_fd, F_SETFD, flags) == -1) { 127289166Speter rv = errno; 128289166Speter close(pollset->p->kqueue_fd); 129289166Speter pollset->p = NULL; 130289166Speter return rv; 131289166Speter } 132251875Speter } 133251875Speter 134251875Speter pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t)); 135251875Speter 136251875Speter APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); 137251875Speter APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); 138251875Speter APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); 139251875Speter 140251875Speter return APR_SUCCESS; 141251875Speter} 142251875Speter 143251875Speterstatic apr_status_t impl_pollset_add(apr_pollset_t *pollset, 144251875Speter const apr_pollfd_t *descriptor) 145251875Speter{ 146251875Speter apr_os_sock_t fd; 147251875Speter pfd_elem_t *elem; 148251875Speter apr_status_t rv = APR_SUCCESS; 149251875Speter 150251875Speter pollset_lock_rings(); 151251875Speter 152251875Speter if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { 153251875Speter elem = APR_RING_FIRST(&(pollset->p->free_ring)); 154251875Speter APR_RING_REMOVE(elem, link); 155251875Speter } 156251875Speter else { 157251875Speter elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); 158251875Speter APR_RING_ELEM_INIT(elem, link); 159251875Speter } 160251875Speter elem->pfd = *descriptor; 161251875Speter 162251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 163251875Speter fd = descriptor->desc.s->socketdes; 164251875Speter } 165251875Speter else { 166251875Speter fd = descriptor->desc.f->filedes; 167251875Speter } 168251875Speter 169251875Speter if (descriptor->reqevents & APR_POLLIN) { 170251875Speter EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); 171251875Speter 172251875Speter if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 173251875Speter NULL) == -1) { 174251875Speter rv = apr_get_netos_error(); 175251875Speter } 176251875Speter } 177251875Speter 178251875Speter if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { 179251875Speter EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); 180251875Speter 181251875Speter if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 182251875Speter NULL) == -1) { 183251875Speter rv = apr_get_netos_error(); 184251875Speter } 185251875Speter } 186251875Speter 187251875Speter if (rv == APR_SUCCESS) { 188251875Speter APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); 189251875Speter } 190251875Speter else { 191251875Speter APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); 192251875Speter } 193251875Speter 194251875Speter pollset_unlock_rings(); 195251875Speter 196251875Speter return rv; 197251875Speter} 198251875Speter 199251875Speterstatic apr_status_t impl_pollset_remove(apr_pollset_t *pollset, 200251875Speter const apr_pollfd_t *descriptor) 201251875Speter{ 202251875Speter pfd_elem_t *ep; 203251875Speter apr_status_t rv; 204251875Speter apr_os_sock_t fd; 205251875Speter 206251875Speter pollset_lock_rings(); 207251875Speter 208251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 209251875Speter fd = descriptor->desc.s->socketdes; 210251875Speter } 211251875Speter else { 212251875Speter fd = descriptor->desc.f->filedes; 213251875Speter } 214251875Speter 215251875Speter rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ 216251875Speter if (descriptor->reqevents & APR_POLLIN) { 217251875Speter EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 218251875Speter 219251875Speter if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 220251875Speter NULL) != -1) { 221251875Speter rv = APR_SUCCESS; 222251875Speter } 223251875Speter } 224251875Speter 225251875Speter if (descriptor->reqevents & APR_POLLOUT) { 226251875Speter EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 227251875Speter 228251875Speter if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, 229251875Speter NULL) != -1) { 230251875Speter rv = APR_SUCCESS; 231251875Speter } 232251875Speter } 233251875Speter 234251875Speter for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); 235251875Speter ep != APR_RING_SENTINEL(&(pollset->p->query_ring), 236251875Speter pfd_elem_t, link); 237251875Speter ep = APR_RING_NEXT(ep, link)) { 238251875Speter 239251875Speter if (descriptor->desc.s == ep->pfd.desc.s) { 240251875Speter APR_RING_REMOVE(ep, link); 241251875Speter APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), 242251875Speter ep, pfd_elem_t, link); 243251875Speter break; 244251875Speter } 245251875Speter } 246251875Speter 247251875Speter pollset_unlock_rings(); 248251875Speter 249251875Speter return rv; 250251875Speter} 251251875Speter 252251875Speterstatic apr_status_t impl_pollset_poll(apr_pollset_t *pollset, 253251875Speter apr_interval_time_t timeout, 254251875Speter apr_int32_t *num, 255251875Speter const apr_pollfd_t **descriptors) 256251875Speter{ 257251875Speter int ret, i, j; 258251875Speter struct timespec tv, *tvptr; 259251875Speter apr_status_t rv = APR_SUCCESS; 260251875Speter apr_pollfd_t fd; 261251875Speter 262251875Speter if (timeout < 0) { 263251875Speter tvptr = NULL; 264251875Speter } 265251875Speter else { 266251875Speter tv.tv_sec = (long) apr_time_sec(timeout); 267251875Speter tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; 268251875Speter tvptr = &tv; 269251875Speter } 270251875Speter 271251875Speter ret = kevent(pollset->p->kqueue_fd, NULL, 0, pollset->p->ke_set, 272251875Speter pollset->p->setsize, tvptr); 273251875Speter (*num) = ret; 274251875Speter if (ret < 0) { 275251875Speter rv = apr_get_netos_error(); 276251875Speter } 277251875Speter else if (ret == 0) { 278251875Speter rv = APR_TIMEUP; 279251875Speter } 280251875Speter else { 281251875Speter for (i = 0, j = 0; i < ret; i++) { 282251875Speter fd = (((pfd_elem_t*)(pollset->p->ke_set[i].udata))->pfd); 283251875Speter if ((pollset->flags & APR_POLLSET_WAKEABLE) && 284251875Speter fd.desc_type == APR_POLL_FILE && 285251875Speter fd.desc.f == pollset->wakeup_pipe[0]) { 286251875Speter apr_pollset_drain_wakeup_pipe(pollset); 287251875Speter rv = APR_EINTR; 288251875Speter } 289251875Speter else { 290251875Speter pollset->p->result_set[j] = fd; 291251875Speter pollset->p->result_set[j].rtnevents = 292251875Speter get_kqueue_revent(pollset->p->ke_set[i].filter, 293251875Speter pollset->p->ke_set[i].flags); 294251875Speter j++; 295251875Speter } 296251875Speter } 297251875Speter if ((*num = j)) { /* any event besides wakeup pipe? */ 298251875Speter rv = APR_SUCCESS; 299251875Speter if (descriptors) { 300251875Speter *descriptors = pollset->p->result_set; 301251875Speter } 302251875Speter } 303251875Speter } 304251875Speter 305251875Speter 306251875Speter pollset_lock_rings(); 307251875Speter 308251875Speter /* Shift all PFDs in the Dead Ring to the Free Ring */ 309251875Speter APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), 310251875Speter pfd_elem_t, link); 311251875Speter 312251875Speter pollset_unlock_rings(); 313251875Speter 314251875Speter return rv; 315251875Speter} 316251875Speter 317251875Speterstatic apr_pollset_provider_t impl = { 318251875Speter impl_pollset_create, 319251875Speter impl_pollset_add, 320251875Speter impl_pollset_remove, 321251875Speter impl_pollset_poll, 322251875Speter impl_pollset_cleanup, 323251875Speter "kqueue" 324251875Speter}; 325251875Speter 326251875Speterapr_pollset_provider_t *apr_pollset_provider_kqueue = &impl; 327251875Speter 328251875Speterstatic apr_status_t cb_cleanup(void *b_) 329251875Speter{ 330251875Speter apr_pollcb_t *pollcb = (apr_pollcb_t *) b_; 331251875Speter close(pollcb->fd); 332251875Speter return APR_SUCCESS; 333251875Speter} 334251875Speter 335251875Speterstatic apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 336251875Speter apr_uint32_t size, 337251875Speter apr_pool_t *p, 338251875Speter apr_uint32_t flags) 339251875Speter{ 340251875Speter int fd; 341251875Speter 342251875Speter fd = kqueue(); 343251875Speter if (fd < 0) { 344251875Speter return apr_get_netos_error(); 345251875Speter } 346251875Speter 347251875Speter { 348251875Speter int flags; 349289166Speter apr_status_t rv; 350251875Speter 351289166Speter if ((flags = fcntl(fd, F_GETFD)) == -1) { 352289166Speter rv = errno; 353289166Speter close(fd); 354289166Speter pollcb->fd = -1; 355289166Speter return rv; 356289166Speter } 357251875Speter 358251875Speter flags |= FD_CLOEXEC; 359289166Speter if (fcntl(fd, F_SETFD, flags) == -1) { 360289166Speter rv = errno; 361289166Speter close(fd); 362289166Speter pollcb->fd = -1; 363289166Speter return rv; 364289166Speter } 365251875Speter } 366251875Speter 367251875Speter pollcb->fd = fd; 368251875Speter pollcb->pollset.ke = (struct kevent *)apr_pcalloc(p, 2 * size * sizeof(struct kevent)); 369251875Speter apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); 370251875Speter 371251875Speter return APR_SUCCESS; 372251875Speter} 373251875Speter 374251875Speterstatic apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 375251875Speter apr_pollfd_t *descriptor) 376251875Speter{ 377251875Speter apr_os_sock_t fd; 378251875Speter struct kevent ev; 379251875Speter apr_status_t rv = APR_SUCCESS; 380251875Speter 381251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 382251875Speter fd = descriptor->desc.s->socketdes; 383251875Speter } 384251875Speter else { 385251875Speter fd = descriptor->desc.f->filedes; 386251875Speter } 387251875Speter 388251875Speter if (descriptor->reqevents & APR_POLLIN) { 389251875Speter EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor); 390251875Speter 391251875Speter if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { 392251875Speter rv = apr_get_netos_error(); 393251875Speter } 394251875Speter } 395251875Speter 396251875Speter if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { 397251875Speter EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor); 398251875Speter 399251875Speter if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) { 400251875Speter rv = apr_get_netos_error(); 401251875Speter } 402251875Speter } 403251875Speter 404251875Speter return rv; 405251875Speter} 406251875Speter 407251875Speterstatic apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 408251875Speter apr_pollfd_t *descriptor) 409251875Speter{ 410251875Speter apr_status_t rv; 411251875Speter struct kevent ev; 412251875Speter apr_os_sock_t fd; 413251875Speter 414251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 415251875Speter fd = descriptor->desc.s->socketdes; 416251875Speter } 417251875Speter else { 418251875Speter fd = descriptor->desc.f->filedes; 419251875Speter } 420251875Speter 421251875Speter rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */ 422251875Speter if (descriptor->reqevents & APR_POLLIN) { 423251875Speter EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 424251875Speter 425251875Speter if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { 426251875Speter rv = APR_SUCCESS; 427251875Speter } 428251875Speter } 429251875Speter 430251875Speter if (descriptor->reqevents & APR_POLLOUT) { 431251875Speter EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 432251875Speter 433251875Speter if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) { 434251875Speter rv = APR_SUCCESS; 435251875Speter } 436251875Speter } 437251875Speter 438251875Speter return rv; 439251875Speter} 440251875Speter 441251875Speter 442251875Speterstatic apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 443251875Speter apr_interval_time_t timeout, 444251875Speter apr_pollcb_cb_t func, 445251875Speter void *baton) 446251875Speter{ 447251875Speter int ret, i; 448251875Speter struct timespec tv, *tvptr; 449251875Speter apr_status_t rv = APR_SUCCESS; 450251875Speter 451251875Speter if (timeout < 0) { 452251875Speter tvptr = NULL; 453251875Speter } 454251875Speter else { 455251875Speter tv.tv_sec = (long) apr_time_sec(timeout); 456251875Speter tv.tv_nsec = (long) apr_time_usec(timeout) * 1000; 457251875Speter tvptr = &tv; 458251875Speter } 459251875Speter 460251875Speter ret = kevent(pollcb->fd, NULL, 0, pollcb->pollset.ke, 2 * pollcb->nalloc, 461251875Speter tvptr); 462251875Speter 463251875Speter if (ret < 0) { 464251875Speter rv = apr_get_netos_error(); 465251875Speter } 466251875Speter else if (ret == 0) { 467251875Speter rv = APR_TIMEUP; 468251875Speter } 469251875Speter else { 470251875Speter for (i = 0; i < ret; i++) { 471251875Speter apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.ke[i].udata); 472251875Speter 473251875Speter pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter, 474251875Speter pollcb->pollset.ke[i].flags); 475251875Speter 476251875Speter rv = func(baton, pollfd); 477251875Speter 478251875Speter if (rv) { 479251875Speter return rv; 480251875Speter } 481251875Speter } 482251875Speter } 483251875Speter 484251875Speter return rv; 485251875Speter} 486251875Speter 487251875Speterstatic apr_pollcb_provider_t impl_cb = { 488251875Speter impl_pollcb_create, 489251875Speter impl_pollcb_add, 490251875Speter impl_pollcb_remove, 491251875Speter impl_pollcb_poll, 492251875Speter "kqueue" 493251875Speter}; 494251875Speter 495251875Speterapr_pollcb_provider_t *apr_pollcb_provider_kqueue = &impl_cb; 496251875Speter 497251875Speter#endif /* HAVE_KQUEUE */ 498