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