"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/kqueue.c" (24 Nov 2020, 5909 Bytes) of package /linux/privat/minidlna-1.3.0.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 "kqueue.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2017 Gleb Smirnoff <glebius@FreeBSD.org>
    3  * Copyright (c) 2002-2017 Igor Sysoev
    4  * Copyright (c) 2011-2017 Nginx, Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/types.h>
   30 #include <sys/event.h>
   31 #include <assert.h>
   32 #include <errno.h>
   33 #include <stdlib.h>
   34 #include <stdio.h>
   35 #include <string.h>
   36 #include <unistd.h>
   37 
   38 #include "event.h"
   39 #include "log.h"
   40 
   41 static int kqueue_set(struct event *, short, u_short, u_int);
   42 
   43 static event_module_init_t kqueue_init;
   44 static event_module_fini_t kqueue_fini;
   45 static event_module_add_t kqueue_add;
   46 static event_module_del_t kqueue_del;
   47 static event_module_process_t kqueue_process;
   48 
   49 static int kq;
   50 static struct kevent *change_list;
   51 static struct kevent *event_list;
   52 static u_int nchanges;
   53 
   54 #define MAXCHANGES  128
   55 #define MAXEVENTS   128
   56 
   57 struct event_module event_module = {
   58     .add =      kqueue_add,
   59     .del =      kqueue_del,
   60     .process =  kqueue_process,
   61     .init =     kqueue_init,
   62     .fini =     kqueue_fini,
   63 };
   64 
   65 static int
   66 kqueue_init(void)
   67 {
   68 
   69     kq = kqueue();
   70     if (kq == -1)
   71         return (errno);
   72 
   73     change_list = calloc(MAXCHANGES, sizeof(struct kevent));
   74     event_list = calloc(MAXEVENTS, sizeof(struct kevent));
   75     if (change_list == NULL || event_list == NULL)
   76         return (ENOMEM);
   77 
   78     nchanges = 0;
   79 
   80     return (0);
   81 }
   82 
   83 static void
   84 kqueue_fini()
   85 {
   86 
   87     (void )close(kq);
   88     kq = -1;
   89 
   90     free(change_list);
   91     free(event_list);
   92     change_list = NULL;
   93     event_list = NULL;
   94     nchanges = 0;
   95 }
   96 
   97 static int
   98 kqueue_add(struct event *ev)
   99 {
  100     u_int fflags;
  101     u_short flags;
  102 
  103     if (ev->rdwr == EVFILT_VNODE) {
  104         flags = EV_ADD | EV_ENABLE | EV_CLEAR;
  105         fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND;
  106     } else {
  107         flags = EV_ADD | EV_ENABLE;
  108         fflags = 0;
  109     }
  110 
  111     DPRINTF(E_DEBUG, L_GENERAL, "kqueue_add %d\n", ev->fd);
  112     return (kqueue_set(ev, ev->rdwr, flags, fflags));
  113 }
  114 
  115 static int
  116 kqueue_del(struct event *ev, int flags)
  117 {
  118 
  119         /*
  120      * If the event is still not passed to a kernel,
  121      * we will not pass it.
  122      */
  123     assert(ev->fd >= 0);
  124     if (ev->index < nchanges &&
  125         change_list[ev->index].udata == ev) {
  126         if (ev->index < --nchanges) {
  127             struct event *ev0;
  128 
  129             ev0 = (struct event *)change_list[nchanges].udata;
  130             change_list[ev->index] = change_list[nchanges];
  131             ev0->index = ev->index;
  132         }
  133         return (0);
  134     }
  135 
  136     /*
  137      * when the file descriptor is closed the kqueue automatically deletes
  138      * its filters so we do not need to delete explicitly the event
  139      * before the closing the file descriptor.
  140      */
  141     if (flags & EV_FLAG_CLOSING)
  142         return (0);
  143 
  144     DPRINTF(E_DEBUG, L_GENERAL, "kqueue_del %d\n", ev->fd);
  145     return (kqueue_set(ev, ev->rdwr, EV_DELETE, 0));
  146 }
  147 
  148 static int
  149 kqueue_set(struct event *ev, short filter, u_short flags, u_int fflags)
  150 {
  151     struct kevent *kev;
  152     struct timespec ts;
  153 
  154     if (nchanges >= MAXCHANGES) {
  155         DPRINTF(E_INFO, L_GENERAL, "kqueue change list is filled up\n");
  156 
  157         ts.tv_sec = 0;
  158         ts.tv_nsec = 0;
  159 
  160         if (kevent(kq, change_list, (int) nchanges, NULL, 0, &ts) == -1) {
  161             DPRINTF(E_ERROR, L_GENERAL,"kevent() failed: %s\n", strerror(errno));
  162             return (errno);
  163         }
  164         nchanges = 0;
  165     }
  166 
  167     kev = &change_list[nchanges];
  168     kev->ident = ev->fd;
  169     kev->filter = filter;
  170     kev->flags = flags;
  171     kev->udata = ev;
  172     kev->fflags = fflags;
  173     kev->data = 0;
  174 
  175     ev->index = nchanges++;
  176 
  177     return (0);
  178 }
  179 
  180 static int
  181 kqueue_process(u_long timer)
  182 {
  183     struct event *ev;
  184     int events, n, i;
  185     struct timespec ts, *tp;
  186 
  187     n = (int) nchanges;
  188     nchanges = 0;
  189 
  190     if (timer == 0) {
  191         tp = NULL;
  192     } else {
  193         ts.tv_sec = timer / 1000;
  194         ts.tv_nsec = (timer % 1000) * 1000000;
  195         tp = &ts;
  196     }
  197 
  198     DPRINTF(E_DEBUG, L_GENERAL, "kevent timer: %lu, changes: %d\n",
  199         timer, n);
  200 
  201     events = kevent(kq, change_list, n, event_list, MAXEVENTS, tp);
  202 
  203     if (events == -1) {
  204         if (errno == EINTR)
  205             return (errno);
  206         DPRINTF(E_FATAL, L_GENERAL, "kevent(): %s. EXITING\n", strerror(errno));
  207     }
  208 
  209     DPRINTF(E_DEBUG, L_GENERAL, "kevent events: %d\n", events);
  210 
  211     if (events == 0) {
  212         if (timer != 0)
  213             return (0);
  214         DPRINTF(E_FATAL, L_GENERAL, "kevent() returned no events. EXITING\n");
  215     }
  216 
  217     for (i = 0; i < events; i++) {
  218         if (event_list[i].flags & EV_ERROR) {
  219             DPRINTF(E_ERROR, L_GENERAL,
  220                 "kevent() error %d on %d filter:%d flags:0x%x\n",
  221                 (int)event_list[i].data, (int)event_list[i].ident,
  222                 event_list[i].filter, event_list[i].flags);
  223             continue;
  224         }
  225 
  226         ev = (struct event *)event_list[i].udata;
  227 
  228         switch (event_list[i].filter) {
  229         case EVFILT_READ:
  230         case EVFILT_WRITE:
  231             ev->process(ev);
  232             break;
  233         case EVFILT_VNODE:
  234             ev->process_vnode(ev, event_list[i].fflags);
  235             break;
  236         default:
  237             DPRINTF(E_ERROR, L_GENERAL,
  238                 "unexpected kevent() filter %d",
  239                 event_list[i].filter);
  240             continue;
  241         }
  242     }
  243 
  244     return (0);
  245 }