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