"Fossies" - the Fresh Open Source Software Archive

Member "libev-4.33/ev_kqueue.c" (31 Oct 2019, 7088 Bytes) of package /linux/misc/libev-4.33.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ev_kqueue.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.27_vs_4.31.

    1 /*
    2  * libev kqueue backend
    3  *
    4  * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2016,2019 Marc Alexander Lehmann <libev@schmorp.de>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without modifica-
    8  * tion, are permitted provided that the following conditions are met:
    9  *
   10  *   1.  Redistributions of source code must retain the above copyright notice,
   11  *       this list of conditions and the following disclaimer.
   12  *
   13  *   2.  Redistributions in binary form must reproduce the above copyright
   14  *       notice, this list of conditions and the following disclaimer in the
   15  *       documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
   18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
   19  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
   20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
   21  * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
   25  * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   26  * OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * Alternatively, the contents of this file may be used under the terms of
   29  * the GNU General Public License ("GPL") version 2 or any later version,
   30  * in which case the provisions of the GPL are applicable instead of
   31  * the above. If you wish to allow the use of your version of this file
   32  * only under the terms of the GPL and not to allow others to use your
   33  * version of this file under the BSD license, indicate your decision
   34  * by deleting the provisions above and replace them with the notice
   35  * and other provisions required by the GPL. If you do not delete the
   36  * provisions above, a recipient may use your version of this file under
   37  * either the BSD or the GPL.
   38  */
   39 
   40 #include <sys/types.h>
   41 #include <sys/time.h>
   42 #include <sys/event.h>
   43 #include <string.h>
   44 #include <errno.h>
   45 
   46 inline_speed
   47 void
   48 kqueue_change (EV_P_ int fd, int filter, int flags, int fflags)
   49 {
   50   ++kqueue_changecnt;
   51   array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, array_needsize_noinit);
   52 
   53   EV_SET (&kqueue_changes [kqueue_changecnt - 1], fd, filter, flags, fflags, 0, 0);
   54 }
   55 
   56 /* OS X at least needs this */
   57 #ifndef EV_ENABLE
   58 # define EV_ENABLE 0
   59 #endif
   60 #ifndef NOTE_EOF
   61 # define NOTE_EOF 0
   62 #endif
   63 
   64 static void
   65 kqueue_modify (EV_P_ int fd, int oev, int nev)
   66 {
   67   if (oev != nev)
   68     {
   69       if (oev & EV_READ)
   70         kqueue_change (EV_A_ fd, EVFILT_READ , EV_DELETE, 0);
   71 
   72       if (oev & EV_WRITE)
   73         kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_DELETE, 0);
   74     }
   75 
   76   /* to detect close/reopen reliably, we have to re-add */
   77   /* event requests even when oev == nev */
   78 
   79   if (nev & EV_READ)
   80     kqueue_change (EV_A_ fd, EVFILT_READ , EV_ADD | EV_ENABLE, NOTE_EOF);
   81 
   82   if (nev & EV_WRITE)
   83     kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, NOTE_EOF);
   84 }
   85 
   86 static void
   87 kqueue_poll (EV_P_ ev_tstamp timeout)
   88 {
   89   int res, i;
   90   struct timespec ts;
   91 
   92   /* need to resize so there is enough space for errors */
   93   if (kqueue_changecnt > kqueue_eventmax)
   94     {
   95       ev_free (kqueue_events);
   96       kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_changecnt);
   97       kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
   98     }
   99 
  100   EV_RELEASE_CB;
  101   EV_TS_SET (ts, timeout);
  102   res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts);
  103   EV_ACQUIRE_CB;
  104   kqueue_changecnt = 0;
  105 
  106   if (ecb_expect_false (res < 0))
  107     {
  108       if (errno != EINTR)
  109         ev_syserr ("(libev) kqueue kevent");
  110 
  111       return;
  112     }
  113 
  114   for (i = 0; i < res; ++i)
  115     {
  116       int fd = kqueue_events [i].ident;
  117 
  118       if (ecb_expect_false (kqueue_events [i].flags & EV_ERROR))
  119         {
  120           int err = kqueue_events [i].data;
  121 
  122           /* we are only interested in errors for fds that we are interested in :) */
  123           if (anfds [fd].events)
  124             {
  125               if (err == ENOENT) /* resubmit changes on ENOENT */
  126                 kqueue_modify (EV_A_ fd, 0, anfds [fd].events);
  127               else if (err == EBADF) /* on EBADF, we re-check the fd */
  128                 {
  129                   if (fd_valid (fd))
  130                     kqueue_modify (EV_A_ fd, 0, anfds [fd].events);
  131                   else
  132                     {
  133                       assert (("libev: kqueue found invalid fd", 0));
  134                       fd_kill (EV_A_ fd);
  135                     }
  136                 }
  137               else /* on all other errors, we error out on the fd */
  138                 {
  139                   assert (("libev: kqueue found invalid fd", 0));
  140                   fd_kill (EV_A_ fd);
  141                 }
  142             }
  143         }
  144       else
  145         fd_event (
  146           EV_A_
  147           fd,
  148           kqueue_events [i].filter == EVFILT_READ ? EV_READ
  149           : kqueue_events [i].filter == EVFILT_WRITE ? EV_WRITE
  150           : 0
  151         );
  152     }
  153 
  154   if (ecb_expect_false (res == kqueue_eventmax))
  155     {
  156       ev_free (kqueue_events);
  157       kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_eventmax + 1);
  158       kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
  159     }
  160 }
  161 
  162 inline_size
  163 int
  164 kqueue_init (EV_P_ int flags)
  165 {
  166   /* initialize the kernel queue */
  167   kqueue_fd_pid = getpid ();
  168   if ((backend_fd = kqueue ()) < 0)
  169     return 0;
  170 
  171   fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
  172 
  173   backend_mintime = EV_TS_CONST (1e-9); /* apparently, they did the right thing in freebsd */
  174   backend_modify  = kqueue_modify;
  175   backend_poll    = kqueue_poll;
  176 
  177   kqueue_eventmax = 64; /* initial number of events receivable per poll */
  178   kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
  179 
  180   kqueue_changes   = 0;
  181   kqueue_changemax = 0;
  182   kqueue_changecnt = 0;
  183 
  184   return EVBACKEND_KQUEUE;
  185 }
  186 
  187 inline_size
  188 void
  189 kqueue_destroy (EV_P)
  190 {
  191   ev_free (kqueue_events);
  192   ev_free (kqueue_changes);
  193 }
  194 
  195 inline_size
  196 void
  197 kqueue_fork (EV_P)
  198 {
  199   /* some BSD kernels don't just destroy the kqueue itself,
  200    * but also close the fd, which isn't documented, and
  201    * impossible to support properly.
  202    * we remember the pid of the kqueue call and only close
  203    * the fd if the pid is still the same.
  204    * this leaks fds on sane kernels, but BSD interfaces are
  205    * notoriously buggy and rarely get fixed.
  206    */
  207   pid_t newpid = getpid ();
  208 
  209   if (newpid == kqueue_fd_pid)
  210     close (backend_fd);
  211 
  212   kqueue_fd_pid = newpid;
  213   while ((backend_fd = kqueue ()) < 0)
  214     ev_syserr ("(libev) kqueue");
  215 
  216   fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
  217 
  218   /* re-register interest in fds */
  219   fd_rearm_all (EV_A);
  220 }
  221 
  222 /* sys/event.h defines EV_ERROR */
  223 #undef EV_ERROR
  224