1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr.h"
18#include "apr_poll.h"
19#include "apr_time.h"
20#include "apr_portable.h"
21#include "apr_arch_file_io.h"
22#include "apr_arch_networkio.h"
23#include "apr_arch_poll_private.h"
24#include "apr_arch_inherit.h"
25
26#ifdef HAVE_KQUEUE
27
28static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags)
29{
30    apr_int16_t rv = 0;
31
32    if (event == EVFILT_READ)
33        rv |= APR_POLLIN;
34    else if (event == EVFILT_WRITE)
35        rv |= APR_POLLOUT;
36    if (flags & EV_EOF)
37        rv |= APR_POLLHUP;
38    /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this
39     * implementation.
40     * TODO: See if EV_ERROR + certain system errors in the returned data field
41     * should map to APR_POLLNVAL.
42     */
43    return rv;
44}
45
46struct apr_pollset_private_t
47{
48    int kqueue_fd;
49    struct kevent kevent;
50    apr_uint32_t setsize;
51    struct kevent *ke_set;
52    apr_pollfd_t *result_set;
53#if APR_HAS_THREADS
54    /* A thread mutex to protect operations on the rings */
55    apr_thread_mutex_t *ring_lock;
56#endif
57    /* A ring containing all of the pollfd_t that are active */
58    APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
59    /* A ring of pollfd_t that have been used, and then _remove'd */
60    APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
61    /* A ring of pollfd_t where rings that have been _remove'd but
62       might still be inside a _poll */
63    APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
64};
65
66static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset)
67{
68    close(pollset->p->kqueue_fd);
69    return APR_SUCCESS;
70}
71
72static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
73                                        apr_uint32_t size,
74                                        apr_pool_t *p,
75                                        apr_uint32_t flags)
76{
77    apr_status_t rv;
78    pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
79#if APR_HAS_THREADS
80    if (flags & APR_POLLSET_THREADSAFE &&
81        ((rv = apr_thread_mutex_create(&pollset->p->ring_lock,
82                                       APR_THREAD_MUTEX_DEFAULT,
83                                       p)) != APR_SUCCESS)) {
84        pollset->p = NULL;
85        return rv;
86    }
87#else
88    if (flags & APR_POLLSET_THREADSAFE) {
89        pollset->p = NULL;
90        return APR_ENOTIMPL;
91    }
92#endif
93
94    /* POLLIN and POLLOUT are represented in different returned
95     * events, so we need 2 entries per descriptor in the result set,
96     * both for what is returned by kevent() and what is returned to
97     * the caller of apr_pollset_poll() (since it doesn't spend the
98     * CPU to coalesce separate APR_POLLIN and APR_POLLOUT events
99     * for the same descriptor)
100     */
101    pollset->p->setsize = 2 * size;
102
103    pollset->p->ke_set =
104        (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent));
105
106    memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent));
107
108    pollset->p->kqueue_fd = kqueue();
109
110    if (pollset->p->kqueue_fd == -1) {
111        pollset->p = NULL;
112        return apr_get_netos_error();
113    }
114
115    {
116        int flags;
117
118        if ((flags = fcntl(pollset->p->kqueue_fd, F_GETFD)) == -1)
119            return errno;
120
121        flags |= FD_CLOEXEC;
122        if (fcntl(pollset->p->kqueue_fd, F_SETFD, flags) == -1)
123            return errno;
124    }
125
126    pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t));
127
128    APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link);
129    APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link);
130    APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link);
131
132    return APR_SUCCESS;
133}
134
135static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
136                                     const apr_pollfd_t *descriptor)
137{
138    apr_os_sock_t fd;
139    pfd_elem_t *elem;
140    apr_status_t rv = APR_SUCCESS;
141
142    pollset_lock_rings();
143
144    if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) {
145        elem = APR_RING_FIRST(&(pollset->p->free_ring));
146        APR_RING_REMOVE(elem, link);
147    }
148    else {
149        elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
150        APR_RING_ELEM_INIT(elem, link);
151    }
152    elem->pfd = *descriptor;
153
154    if (descriptor->desc_type == APR_POLL_SOCKET) {
155        fd = descriptor->desc.s->socketdes;
156    }
157    else {
158        fd = descriptor->desc.f->filedes;
159    }
160
161    if (descriptor->reqevents & APR_POLLIN) {
162        EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem);
163
164        if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0,
165                   NULL) == -1) {
166            rv = apr_get_netos_error();
167        }
168    }
169
170    if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
171        EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem);
172
173        if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0,
174                   NULL) == -1) {
175            rv = apr_get_netos_error();
176        }
177    }
178
179    if (rv == APR_SUCCESS) {
180        APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link);
181    }
182    else {
183        APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link);
184    }
185
186    pollset_unlock_rings();
187
188    return rv;
189}
190
191static apr_status_t impl_pollset_remove(apr_pollset_t *pollset,
192                                        const apr_pollfd_t *descriptor)
193{
194    pfd_elem_t *ep;
195    apr_status_t rv;
196    apr_os_sock_t fd;
197
198    pollset_lock_rings();
199
200    if (descriptor->desc_type == APR_POLL_SOCKET) {
201        fd = descriptor->desc.s->socketdes;
202    }
203    else {
204        fd = descriptor->desc.f->filedes;
205    }
206
207    rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */
208    if (descriptor->reqevents & APR_POLLIN) {
209        EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
210
211        if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0,
212                   NULL) != -1) {
213            rv = APR_SUCCESS;
214        }
215    }
216
217    if (descriptor->reqevents & APR_POLLOUT) {
218        EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
219
220        if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0,
221                   NULL) != -1) {
222            rv = APR_SUCCESS;
223        }
224    }
225
226    for (ep = APR_RING_FIRST(&(pollset->p->query_ring));
227         ep != APR_RING_SENTINEL(&(pollset->p->query_ring),
228                                 pfd_elem_t, link);
229         ep = APR_RING_NEXT(ep, link)) {
230
231        if (descriptor->desc.s == ep->pfd.desc.s) {
232            APR_RING_REMOVE(ep, link);
233            APR_RING_INSERT_TAIL(&(pollset->p->dead_ring),
234                                 ep, pfd_elem_t, link);
235            break;
236        }
237    }
238
239    pollset_unlock_rings();
240
241    return rv;
242}
243
244static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
245                                      apr_interval_time_t timeout,
246                                      apr_int32_t *num,
247                                      const apr_pollfd_t **descriptors)
248{
249    int ret, i, j;
250    struct timespec tv, *tvptr;
251    apr_status_t rv = APR_SUCCESS;
252    apr_pollfd_t fd;
253
254    if (timeout < 0) {
255        tvptr = NULL;
256    }
257    else {
258        tv.tv_sec = (long) apr_time_sec(timeout);
259        tv.tv_nsec = (long) apr_time_usec(timeout) * 1000;
260        tvptr = &tv;
261    }
262
263    ret = kevent(pollset->p->kqueue_fd, NULL, 0, pollset->p->ke_set,
264                 pollset->p->setsize, tvptr);
265    (*num) = ret;
266    if (ret < 0) {
267        rv = apr_get_netos_error();
268    }
269    else if (ret == 0) {
270        rv = APR_TIMEUP;
271    }
272    else {
273        for (i = 0, j = 0; i < ret; i++) {
274            fd = (((pfd_elem_t*)(pollset->p->ke_set[i].udata))->pfd);
275            if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
276                fd.desc_type == APR_POLL_FILE &&
277                fd.desc.f == pollset->wakeup_pipe[0]) {
278                apr_pollset_drain_wakeup_pipe(pollset);
279                rv = APR_EINTR;
280            }
281            else {
282                pollset->p->result_set[j] = fd;
283                pollset->p->result_set[j].rtnevents =
284                        get_kqueue_revent(pollset->p->ke_set[i].filter,
285                                          pollset->p->ke_set[i].flags);
286                j++;
287            }
288        }
289        if ((*num = j)) { /* any event besides wakeup pipe? */
290            rv = APR_SUCCESS;
291            if (descriptors) {
292                *descriptors = pollset->p->result_set;
293            }
294        }
295    }
296
297
298    pollset_lock_rings();
299
300    /* Shift all PFDs in the Dead Ring to the Free Ring */
301    APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring),
302                    pfd_elem_t, link);
303
304    pollset_unlock_rings();
305
306    return rv;
307}
308
309static apr_pollset_provider_t impl = {
310    impl_pollset_create,
311    impl_pollset_add,
312    impl_pollset_remove,
313    impl_pollset_poll,
314    impl_pollset_cleanup,
315    "kqueue"
316};
317
318apr_pollset_provider_t *apr_pollset_provider_kqueue = &impl;
319
320static apr_status_t cb_cleanup(void *b_)
321{
322    apr_pollcb_t *pollcb = (apr_pollcb_t *) b_;
323    close(pollcb->fd);
324    return APR_SUCCESS;
325}
326
327static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb,
328                                       apr_uint32_t size,
329                                       apr_pool_t *p,
330                                       apr_uint32_t flags)
331{
332    int fd;
333
334    fd = kqueue();
335    if (fd < 0) {
336        return apr_get_netos_error();
337    }
338
339    {
340        int flags;
341
342        if ((flags = fcntl(fd, F_GETFD)) == -1)
343            return errno;
344
345        flags |= FD_CLOEXEC;
346        if (fcntl(fd, F_SETFD, flags) == -1)
347            return errno;
348    }
349
350    pollcb->fd = fd;
351    pollcb->pollset.ke = (struct kevent *)apr_pcalloc(p, 2 * size * sizeof(struct kevent));
352    apr_pool_cleanup_register(p, pollcb, cb_cleanup, apr_pool_cleanup_null);
353
354    return APR_SUCCESS;
355}
356
357static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb,
358                                    apr_pollfd_t *descriptor)
359{
360    apr_os_sock_t fd;
361    struct kevent ev;
362    apr_status_t rv = APR_SUCCESS;
363
364    if (descriptor->desc_type == APR_POLL_SOCKET) {
365        fd = descriptor->desc.s->socketdes;
366    }
367    else {
368        fd = descriptor->desc.f->filedes;
369    }
370
371    if (descriptor->reqevents & APR_POLLIN) {
372        EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, descriptor);
373
374        if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) {
375            rv = apr_get_netos_error();
376        }
377    }
378
379    if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) {
380        EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, descriptor);
381
382        if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) == -1) {
383            rv = apr_get_netos_error();
384        }
385    }
386
387    return rv;
388}
389
390static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb,
391                                       apr_pollfd_t *descriptor)
392{
393    apr_status_t rv;
394    struct kevent ev;
395    apr_os_sock_t fd;
396
397    if (descriptor->desc_type == APR_POLL_SOCKET) {
398        fd = descriptor->desc.s->socketdes;
399    }
400    else {
401        fd = descriptor->desc.f->filedes;
402    }
403
404    rv = APR_NOTFOUND; /* unless at least one of the specified conditions is */
405    if (descriptor->reqevents & APR_POLLIN) {
406        EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
407
408        if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) {
409            rv = APR_SUCCESS;
410        }
411    }
412
413    if (descriptor->reqevents & APR_POLLOUT) {
414        EV_SET(&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
415
416        if (kevent(pollcb->fd, &ev, 1, NULL, 0, NULL) != -1) {
417            rv = APR_SUCCESS;
418        }
419    }
420
421    return rv;
422}
423
424
425static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb,
426                                     apr_interval_time_t timeout,
427                                     apr_pollcb_cb_t func,
428                                     void *baton)
429{
430    int ret, i;
431    struct timespec tv, *tvptr;
432    apr_status_t rv = APR_SUCCESS;
433
434    if (timeout < 0) {
435        tvptr = NULL;
436    }
437    else {
438        tv.tv_sec = (long) apr_time_sec(timeout);
439        tv.tv_nsec = (long) apr_time_usec(timeout) * 1000;
440        tvptr = &tv;
441    }
442
443    ret = kevent(pollcb->fd, NULL, 0, pollcb->pollset.ke, 2 * pollcb->nalloc,
444                 tvptr);
445
446    if (ret < 0) {
447        rv = apr_get_netos_error();
448    }
449    else if (ret == 0) {
450        rv = APR_TIMEUP;
451    }
452    else {
453        for (i = 0; i < ret; i++) {
454            apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.ke[i].udata);
455
456            pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter,
457                                                  pollcb->pollset.ke[i].flags);
458
459            rv = func(baton, pollfd);
460
461            if (rv) {
462                return rv;
463            }
464        }
465    }
466
467    return rv;
468}
469
470static apr_pollcb_provider_t impl_cb = {
471    impl_pollcb_create,
472    impl_pollcb_add,
473    impl_pollcb_remove,
474    impl_pollcb_poll,
475    "kqueue"
476};
477
478apr_pollcb_provider_t *apr_pollcb_provider_kqueue = &impl_cb;
479
480#endif /* HAVE_KQUEUE */
481