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#if defined(HAVE_EPOLL) 27251875Speter 28251875Speterstatic apr_int16_t get_epoll_event(apr_int16_t event) 29251875Speter{ 30251875Speter apr_int16_t rv = 0; 31251875Speter 32251875Speter if (event & APR_POLLIN) 33251875Speter rv |= EPOLLIN; 34251875Speter if (event & APR_POLLPRI) 35251875Speter rv |= EPOLLPRI; 36251875Speter if (event & APR_POLLOUT) 37251875Speter rv |= EPOLLOUT; 38251875Speter /* APR_POLLNVAL is not handled by epoll. EPOLLERR and EPOLLHUP are return-only */ 39251875Speter 40251875Speter return rv; 41251875Speter} 42251875Speter 43251875Speterstatic apr_int16_t get_epoll_revent(apr_int16_t event) 44251875Speter{ 45251875Speter apr_int16_t rv = 0; 46251875Speter 47251875Speter if (event & EPOLLIN) 48251875Speter rv |= APR_POLLIN; 49251875Speter if (event & EPOLLPRI) 50251875Speter rv |= APR_POLLPRI; 51251875Speter if (event & EPOLLOUT) 52251875Speter rv |= APR_POLLOUT; 53251875Speter if (event & EPOLLERR) 54251875Speter rv |= APR_POLLERR; 55251875Speter if (event & EPOLLHUP) 56251875Speter rv |= APR_POLLHUP; 57251875Speter /* APR_POLLNVAL is not handled by epoll. */ 58251875Speter 59251875Speter return rv; 60251875Speter} 61251875Speter 62251875Speterstruct apr_pollset_private_t 63251875Speter{ 64251875Speter int epoll_fd; 65251875Speter struct epoll_event *pollset; 66251875Speter apr_pollfd_t *result_set; 67251875Speter#if APR_HAS_THREADS 68251875Speter /* A thread mutex to protect operations on the rings */ 69251875Speter apr_thread_mutex_t *ring_lock; 70251875Speter#endif 71251875Speter /* A ring containing all of the pollfd_t that are active */ 72251875Speter APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring; 73251875Speter /* A ring of pollfd_t that have been used, and then _remove()'d */ 74251875Speter APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring; 75251875Speter /* A ring of pollfd_t where rings that have been _remove()`ed but 76251875Speter might still be inside a _poll() */ 77251875Speter APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring; 78251875Speter}; 79251875Speter 80251875Speterstatic apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset) 81251875Speter{ 82251875Speter close(pollset->p->epoll_fd); 83251875Speter return APR_SUCCESS; 84251875Speter} 85251875Speter 86251875Speter 87251875Speterstatic apr_status_t impl_pollset_create(apr_pollset_t *pollset, 88251875Speter apr_uint32_t size, 89251875Speter apr_pool_t *p, 90251875Speter apr_uint32_t flags) 91251875Speter{ 92251875Speter apr_status_t rv; 93251875Speter int fd; 94251875Speter 95251875Speter#ifdef HAVE_EPOLL_CREATE1 96251875Speter fd = epoll_create1(EPOLL_CLOEXEC); 97251875Speter#else 98251875Speter fd = epoll_create(size); 99251875Speter#endif 100251875Speter if (fd < 0) { 101251875Speter pollset->p = NULL; 102251875Speter return apr_get_netos_error(); 103251875Speter } 104251875Speter 105251875Speter#ifndef HAVE_EPOLL_CREATE1 106251875Speter { 107289166Speter int fd_flags; 108251875Speter 109289166Speter if ((fd_flags = fcntl(fd, F_GETFD)) == -1) { 110289166Speter rv = errno; 111289166Speter close(fd); 112289166Speter pollset->p = NULL; 113289166Speter return rv; 114289166Speter } 115251875Speter 116289166Speter fd_flags |= FD_CLOEXEC; 117289166Speter if (fcntl(fd, F_SETFD, fd_flags) == -1) { 118289166Speter rv = errno; 119289166Speter close(fd); 120289166Speter pollset->p = NULL; 121289166Speter return rv; 122289166Speter } 123251875Speter } 124251875Speter#endif 125251875Speter 126251875Speter pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); 127251875Speter#if APR_HAS_THREADS 128251875Speter if ((flags & APR_POLLSET_THREADSAFE) && 129251875Speter !(flags & APR_POLLSET_NOCOPY) && 130251875Speter ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, 131251875Speter APR_THREAD_MUTEX_DEFAULT, 132251875Speter p)) != APR_SUCCESS)) { 133289166Speter close(fd); 134251875Speter pollset->p = NULL; 135251875Speter return rv; 136251875Speter } 137251875Speter#else 138251875Speter if (flags & APR_POLLSET_THREADSAFE) { 139289166Speter close(fd); 140251875Speter pollset->p = NULL; 141251875Speter return APR_ENOTIMPL; 142251875Speter } 143251875Speter#endif 144251875Speter pollset->p->epoll_fd = fd; 145251875Speter pollset->p->pollset = apr_palloc(p, size * sizeof(struct epoll_event)); 146251875Speter pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t)); 147251875Speter 148251875Speter if (!(flags & APR_POLLSET_NOCOPY)) { 149251875Speter APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); 150251875Speter APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); 151251875Speter APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); 152251875Speter } 153251875Speter return APR_SUCCESS; 154251875Speter} 155251875Speter 156251875Speterstatic apr_status_t impl_pollset_add(apr_pollset_t *pollset, 157251875Speter const apr_pollfd_t *descriptor) 158251875Speter{ 159251875Speter struct epoll_event ev = {0}; 160251875Speter int ret = -1; 161251875Speter pfd_elem_t *elem = NULL; 162251875Speter apr_status_t rv = APR_SUCCESS; 163251875Speter 164251875Speter ev.events = get_epoll_event(descriptor->reqevents); 165251875Speter 166251875Speter if (pollset->flags & APR_POLLSET_NOCOPY) { 167251875Speter ev.data.ptr = (void *)descriptor; 168251875Speter } 169251875Speter else { 170251875Speter pollset_lock_rings(); 171251875Speter 172251875Speter if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { 173251875Speter elem = APR_RING_FIRST(&(pollset->p->free_ring)); 174251875Speter APR_RING_REMOVE(elem, link); 175251875Speter } 176251875Speter else { 177251875Speter elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); 178251875Speter APR_RING_ELEM_INIT(elem, link); 179251875Speter } 180251875Speter elem->pfd = *descriptor; 181251875Speter ev.data.ptr = elem; 182251875Speter } 183251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 184251875Speter ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_ADD, 185251875Speter descriptor->desc.s->socketdes, &ev); 186251875Speter } 187251875Speter else { 188251875Speter ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_ADD, 189251875Speter descriptor->desc.f->filedes, &ev); 190251875Speter } 191251875Speter 192251875Speter if (0 != ret) { 193251875Speter rv = apr_get_netos_error(); 194251875Speter } 195251875Speter 196251875Speter if (!(pollset->flags & APR_POLLSET_NOCOPY)) { 197251875Speter if (rv != APR_SUCCESS) { 198251875Speter APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); 199251875Speter } 200251875Speter else { 201251875Speter APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); 202251875Speter } 203251875Speter pollset_unlock_rings(); 204251875Speter } 205251875Speter 206251875Speter return rv; 207251875Speter} 208251875Speter 209251875Speterstatic apr_status_t impl_pollset_remove(apr_pollset_t *pollset, 210251875Speter const apr_pollfd_t *descriptor) 211251875Speter{ 212251875Speter pfd_elem_t *ep; 213251875Speter apr_status_t rv = APR_SUCCESS; 214251875Speter struct epoll_event ev = {0}; /* ignored, but must be passed with 215251875Speter * kernel < 2.6.9 216251875Speter */ 217251875Speter int ret = -1; 218251875Speter 219251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 220251875Speter ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_DEL, 221251875Speter descriptor->desc.s->socketdes, &ev); 222251875Speter } 223251875Speter else { 224251875Speter ret = epoll_ctl(pollset->p->epoll_fd, EPOLL_CTL_DEL, 225251875Speter descriptor->desc.f->filedes, &ev); 226251875Speter } 227251875Speter if (ret < 0) { 228251875Speter rv = APR_NOTFOUND; 229251875Speter } 230251875Speter 231251875Speter if (!(pollset->flags & APR_POLLSET_NOCOPY)) { 232251875Speter pollset_lock_rings(); 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 250251875Speter return rv; 251251875Speter} 252251875Speter 253251875Speterstatic apr_status_t impl_pollset_poll(apr_pollset_t *pollset, 254251875Speter apr_interval_time_t timeout, 255251875Speter apr_int32_t *num, 256251875Speter const apr_pollfd_t **descriptors) 257251875Speter{ 258251875Speter int ret, i, j; 259251875Speter apr_status_t rv = APR_SUCCESS; 260251875Speter apr_pollfd_t *fdptr; 261251875Speter 262251875Speter if (timeout > 0) { 263251875Speter timeout /= 1000; 264251875Speter } 265251875Speter 266251875Speter ret = epoll_wait(pollset->p->epoll_fd, pollset->p->pollset, pollset->nalloc, 267251875Speter timeout); 268251875Speter (*num) = ret; 269251875Speter 270251875Speter if (ret < 0) { 271251875Speter rv = apr_get_netos_error(); 272251875Speter } 273251875Speter else if (ret == 0) { 274251875Speter rv = APR_TIMEUP; 275251875Speter } 276251875Speter else { 277251875Speter for (i = 0, j = 0; i < ret; i++) { 278251875Speter if (pollset->flags & APR_POLLSET_NOCOPY) { 279251875Speter fdptr = (apr_pollfd_t *)(pollset->p->pollset[i].data.ptr); 280251875Speter } 281251875Speter else { 282251875Speter fdptr = &(((pfd_elem_t *) (pollset->p->pollset[i].data.ptr))->pfd); 283251875Speter } 284251875Speter /* Check if the polled descriptor is our 285251875Speter * wakeup pipe. In that case do not put it result set. 286251875Speter */ 287251875Speter if ((pollset->flags & APR_POLLSET_WAKEABLE) && 288251875Speter fdptr->desc_type == APR_POLL_FILE && 289251875Speter fdptr->desc.f == pollset->wakeup_pipe[0]) { 290251875Speter apr_pollset_drain_wakeup_pipe(pollset); 291251875Speter rv = APR_EINTR; 292251875Speter } 293251875Speter else { 294251875Speter pollset->p->result_set[j] = *fdptr; 295251875Speter pollset->p->result_set[j].rtnevents = 296251875Speter get_epoll_revent(pollset->p->pollset[i].events); 297251875Speter j++; 298251875Speter } 299251875Speter } 300251875Speter if (((*num) = j)) { /* any event besides wakeup pipe? */ 301251875Speter rv = APR_SUCCESS; 302251875Speter 303251875Speter if (descriptors) { 304251875Speter *descriptors = pollset->p->result_set; 305251875Speter } 306251875Speter } 307251875Speter } 308251875Speter 309251875Speter if (!(pollset->flags & APR_POLLSET_NOCOPY)) { 310251875Speter pollset_lock_rings(); 311251875Speter 312251875Speter /* Shift all PFDs in the Dead Ring to the Free Ring */ 313251875Speter APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), pfd_elem_t, link); 314251875Speter 315251875Speter pollset_unlock_rings(); 316251875Speter } 317251875Speter 318251875Speter return rv; 319251875Speter} 320251875Speter 321251875Speterstatic apr_pollset_provider_t impl = { 322251875Speter impl_pollset_create, 323251875Speter impl_pollset_add, 324251875Speter impl_pollset_remove, 325251875Speter impl_pollset_poll, 326251875Speter impl_pollset_cleanup, 327251875Speter "epoll" 328251875Speter}; 329251875Speter 330251875Speterapr_pollset_provider_t *apr_pollset_provider_epoll = &impl; 331251875Speter 332251875Speterstatic apr_status_t cb_cleanup(void *p_) 333251875Speter{ 334251875Speter apr_pollcb_t *pollcb = (apr_pollcb_t *) p_; 335251875Speter close(pollcb->fd); 336251875Speter return APR_SUCCESS; 337251875Speter} 338251875Speter 339251875Speterstatic apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, 340251875Speter apr_uint32_t size, 341251875Speter apr_pool_t *p, 342251875Speter apr_uint32_t flags) 343251875Speter{ 344251875Speter int fd; 345251875Speter 346251875Speter#ifdef HAVE_EPOLL_CREATE1 347251875Speter fd = epoll_create1(EPOLL_CLOEXEC); 348251875Speter#else 349251875Speter fd = epoll_create(size); 350251875Speter#endif 351251875Speter 352251875Speter if (fd < 0) { 353251875Speter return apr_get_netos_error(); 354251875Speter } 355251875Speter 356251875Speter#ifndef HAVE_EPOLL_CREATE1 357251875Speter { 358289166Speter int fd_flags; 359289166Speter apr_status_t rv; 360251875Speter 361289166Speter if ((fd_flags = fcntl(fd, F_GETFD)) == -1) { 362289166Speter rv = errno; 363289166Speter close(fd); 364289166Speter pollcb->fd = -1; 365289166Speter return rv; 366289166Speter } 367251875Speter 368289166Speter fd_flags |= FD_CLOEXEC; 369289166Speter if (fcntl(fd, F_SETFD, fd_flags) == -1) { 370289166Speter rv = errno; 371289166Speter close(fd); 372289166Speter pollcb->fd = -1; 373289166Speter return rv; 374289166Speter } 375251875Speter } 376251875Speter#endif 377251875Speter 378251875Speter pollcb->fd = fd; 379251875Speter pollcb->pollset.epoll = apr_palloc(p, size * sizeof(struct epoll_event)); 380251875Speter apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null); 381251875Speter 382251875Speter return APR_SUCCESS; 383251875Speter} 384251875Speter 385251875Speterstatic apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb, 386251875Speter apr_pollfd_t *descriptor) 387251875Speter{ 388251875Speter struct epoll_event ev; 389251875Speter int ret; 390251875Speter 391251875Speter ev.events = get_epoll_event(descriptor->reqevents); 392251875Speter ev.data.ptr = (void *)descriptor; 393251875Speter 394251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 395251875Speter ret = epoll_ctl(pollcb->fd, EPOLL_CTL_ADD, 396251875Speter descriptor->desc.s->socketdes, &ev); 397251875Speter } 398251875Speter else { 399251875Speter ret = epoll_ctl(pollcb->fd, EPOLL_CTL_ADD, 400251875Speter descriptor->desc.f->filedes, &ev); 401251875Speter } 402251875Speter 403251875Speter if (ret == -1) { 404251875Speter return apr_get_netos_error(); 405251875Speter } 406251875Speter 407251875Speter return APR_SUCCESS; 408251875Speter} 409251875Speter 410251875Speterstatic apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb, 411251875Speter apr_pollfd_t *descriptor) 412251875Speter{ 413251875Speter apr_status_t rv = APR_SUCCESS; 414251875Speter struct epoll_event ev = {0}; /* ignored, but must be passed with 415251875Speter * kernel < 2.6.9 416251875Speter */ 417251875Speter int ret = -1; 418251875Speter 419251875Speter if (descriptor->desc_type == APR_POLL_SOCKET) { 420251875Speter ret = epoll_ctl(pollcb->fd, EPOLL_CTL_DEL, 421251875Speter descriptor->desc.s->socketdes, &ev); 422251875Speter } 423251875Speter else { 424251875Speter ret = epoll_ctl(pollcb->fd, EPOLL_CTL_DEL, 425251875Speter descriptor->desc.f->filedes, &ev); 426251875Speter } 427251875Speter 428251875Speter if (ret < 0) { 429251875Speter rv = APR_NOTFOUND; 430251875Speter } 431251875Speter 432251875Speter return rv; 433251875Speter} 434251875Speter 435251875Speter 436251875Speterstatic apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb, 437251875Speter apr_interval_time_t timeout, 438251875Speter apr_pollcb_cb_t func, 439251875Speter void *baton) 440251875Speter{ 441251875Speter int ret, i; 442251875Speter apr_status_t rv = APR_SUCCESS; 443251875Speter 444251875Speter if (timeout > 0) { 445251875Speter timeout /= 1000; 446251875Speter } 447251875Speter 448251875Speter ret = epoll_wait(pollcb->fd, pollcb->pollset.epoll, pollcb->nalloc, 449251875Speter timeout); 450251875Speter if (ret < 0) { 451251875Speter rv = apr_get_netos_error(); 452251875Speter } 453251875Speter else if (ret == 0) { 454251875Speter rv = APR_TIMEUP; 455251875Speter } 456251875Speter else { 457251875Speter for (i = 0; i < ret; i++) { 458251875Speter apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.epoll[i].data.ptr); 459251875Speter pollfd->rtnevents = get_epoll_revent(pollcb->pollset.epoll[i].events); 460251875Speter 461251875Speter rv = func(baton, pollfd); 462251875Speter if (rv) { 463251875Speter return rv; 464251875Speter } 465251875Speter } 466251875Speter } 467251875Speter 468251875Speter return rv; 469251875Speter} 470251875Speter 471251875Speterstatic apr_pollcb_provider_t impl_cb = { 472251875Speter impl_pollcb_create, 473251875Speter impl_pollcb_add, 474251875Speter impl_pollcb_remove, 475251875Speter impl_pollcb_poll, 476251875Speter "epoll" 477251875Speter}; 478251875Speter 479251875Speterapr_pollcb_provider_t *apr_pollcb_provider_epoll = &impl_cb; 480251875Speter 481251875Speter#endif /* HAVE_EPOLL */ 482