--- libev/ev_kqueue.c 2010/03/27 02:26:27 1.42 +++ libev/ev_kqueue.c 2019/07/01 20:47:38 1.60 @@ -1,19 +1,19 @@ /* * libev kqueue backend * - * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann + * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2016,2019 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -43,11 +43,12 @@ #include #include -void inline_speed +inline_speed +void kqueue_change (EV_P_ int fd, int filter, int flags, int fflags) { ++kqueue_changecnt; - array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, EMPTY2); + array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, array_needsize_noinit); EV_SET (&kqueue_changes [kqueue_changecnt - 1], fd, filter, flags, fflags, 0, 0); } @@ -97,31 +98,30 @@ } EV_RELEASE_CB; - ts.tv_sec = (time_t)timeout; - ts.tv_nsec = (long)((timeout - (ev_tstamp)ts.tv_sec) * 1e9); + EV_TS_SET (ts, timeout); res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts); EV_ACQUIRE_CB; kqueue_changecnt = 0; - if (expect_false (res < 0)) - { + if (ecb_expect_false (res < 0)) + { if (errno != EINTR) - ev_syserr ("(libev) kevent"); + ev_syserr ("(libev) kqueue kevent"); return; - } + } for (i = 0; i < res; ++i) { int fd = kqueue_events [i].ident; - if (expect_false (kqueue_events [i].flags & EV_ERROR)) + if (ecb_expect_false (kqueue_events [i].flags & EV_ERROR)) { - int err = kqueue_events [i].data; + int err = kqueue_events [i].data; /* we are only interested in errors for fds that we are interested in :) */ if (anfds [fd].events) - { + { if (err == ENOENT) /* resubmit changes on ENOENT */ kqueue_modify (EV_A_ fd, 0, anfds [fd].events); else if (err == EBADF) /* on EBADF, we re-check the fd */ @@ -129,11 +129,17 @@ if (fd_valid (fd)) kqueue_modify (EV_A_ fd, 0, anfds [fd].events); else - fd_kill (EV_A_ fd); + { + assert (("libev: kqueue found invalid fd", 0)); + fd_kill (EV_A_ fd); + } } else /* on all other errors, we error out on the fd */ - fd_kill (EV_A_ fd); - } + { + assert (("libev: kqueue found invalid fd", 0)); + fd_kill (EV_A_ fd); + } + } } else fd_event ( @@ -145,7 +151,7 @@ ); } - if (expect_false (res == kqueue_eventmax)) + if (ecb_expect_false (res == kqueue_eventmax)) { ev_free (kqueue_events); kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_eventmax + 1); @@ -153,18 +159,20 @@ } } -int inline_size +inline_size +int kqueue_init (EV_P_ int flags) { - /* Initalize the kernel queue */ + /* initialize the kernel queue */ + kqueue_fd_pid = getpid (); if ((backend_fd = kqueue ()) < 0) return 0; fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */ - backend_fudge = 0.; - backend_modify = kqueue_modify; - backend_poll = kqueue_poll; + backend_mintime = 1e-9; /* apparently, they did the right thing in freebsd */ + backend_modify = kqueue_modify; + backend_poll = kqueue_poll; kqueue_eventmax = 64; /* initial number of events receivable per poll */ kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax); @@ -176,18 +184,32 @@ return EVBACKEND_KQUEUE; } -void inline_size +inline_size +void kqueue_destroy (EV_P) { ev_free (kqueue_events); ev_free (kqueue_changes); } -void inline_size +inline_size +void kqueue_fork (EV_P) { - close (backend_fd); + /* some BSD kernels don't just destroy the kqueue itself, + * but also close the fd, which isn't documented, and + * impossible to support properly. + * we remember the pid of the kqueue call and only close + * the fd if the pid is still the same. + * this leaks fds on sane kernels, but BSD interfaces are + * notoriously buggy and rarely get fixed. + */ + pid_t newpid = getpid (); + if (newpid == kqueue_fd_pid) + close (backend_fd); + + kqueue_fd_pid = newpid; while ((backend_fd = kqueue ()) < 0) ev_syserr ("(libev) kqueue"); @@ -197,3 +219,6 @@ fd_rearm_all (EV_A); } +/* sys/event.h defines EV_ERROR */ +#undef EV_ERROR +