The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sys_eventfd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2014 Dmitry Chagin <dchagin@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/malloc.h>
   35 #include <sys/limits.h>
   36 #include <sys/lock.h>
   37 #include <sys/mutex.h>
   38 #include <sys/types.h>
   39 #include <sys/user.h>
   40 #include <sys/fcntl.h>
   41 #include <sys/file.h>
   42 #include <sys/filedesc.h>
   43 #include <sys/filio.h>
   44 #include <sys/stat.h>
   45 #include <sys/errno.h>
   46 #include <sys/event.h>
   47 #include <sys/poll.h>
   48 #include <sys/proc.h>
   49 #include <sys/uio.h>
   50 #include <sys/selinfo.h>
   51 #include <sys/eventfd.h>
   52 
   53 #include <security/audit/audit.h>
   54 
   55 _Static_assert(EFD_CLOEXEC == O_CLOEXEC, "Mismatched EFD_CLOEXEC");
   56 _Static_assert(EFD_NONBLOCK == O_NONBLOCK, "Mismatched EFD_NONBLOCK");
   57 
   58 MALLOC_DEFINE(M_EVENTFD, "eventfd", "eventfd structures");
   59 
   60 static fo_rdwr_t        eventfd_read;
   61 static fo_rdwr_t        eventfd_write;
   62 static fo_ioctl_t       eventfd_ioctl;
   63 static fo_poll_t        eventfd_poll;
   64 static fo_kqfilter_t    eventfd_kqfilter;
   65 static fo_stat_t        eventfd_stat;
   66 static fo_close_t       eventfd_close;
   67 static fo_fill_kinfo_t  eventfd_fill_kinfo;
   68 
   69 static struct fileops eventfdops = {
   70         .fo_read = eventfd_read,
   71         .fo_write = eventfd_write,
   72         .fo_truncate = invfo_truncate,
   73         .fo_ioctl = eventfd_ioctl,
   74         .fo_poll = eventfd_poll,
   75         .fo_kqfilter = eventfd_kqfilter,
   76         .fo_stat = eventfd_stat,
   77         .fo_close = eventfd_close,
   78         .fo_chmod = invfo_chmod,
   79         .fo_chown = invfo_chown,
   80         .fo_sendfile = invfo_sendfile,
   81         .fo_fill_kinfo = eventfd_fill_kinfo,
   82         .fo_flags = DFLAG_PASSABLE
   83 };
   84 
   85 static void     filt_eventfddetach(struct knote *kn);
   86 static int      filt_eventfdread(struct knote *kn, long hint);
   87 static int      filt_eventfdwrite(struct knote *kn, long hint);
   88 
   89 static struct filterops eventfd_rfiltops = {
   90         .f_isfd = 1,
   91         .f_detach = filt_eventfddetach,
   92         .f_event = filt_eventfdread
   93 };
   94 
   95 static struct filterops eventfd_wfiltops = {
   96         .f_isfd = 1,
   97         .f_detach = filt_eventfddetach,
   98         .f_event = filt_eventfdwrite
   99 };
  100 
  101 struct eventfd {
  102         eventfd_t       efd_count;
  103         uint32_t        efd_flags;
  104         struct selinfo  efd_sel;
  105         struct mtx      efd_lock;
  106 };
  107 
  108 int
  109 eventfd_create_file(struct thread *td, struct file *fp, uint32_t initval,
  110     int flags)
  111 {
  112         struct eventfd *efd;
  113         int fflags;
  114 
  115         AUDIT_ARG_FFLAGS(flags);
  116         AUDIT_ARG_VALUE(initval);
  117 
  118         efd = malloc(sizeof(*efd), M_EVENTFD, M_WAITOK | M_ZERO);
  119         efd->efd_flags = flags;
  120         efd->efd_count = initval;
  121         mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF);
  122         knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock);
  123 
  124         fflags = FREAD | FWRITE;
  125         if ((flags & EFD_NONBLOCK) != 0)
  126                 fflags |= FNONBLOCK;
  127         finit(fp, fflags, DTYPE_EVENTFD, efd, &eventfdops);
  128 
  129         return (0);
  130 }
  131 
  132 static int
  133 eventfd_close(struct file *fp, struct thread *td)
  134 {
  135         struct eventfd *efd;
  136 
  137         efd = fp->f_data;
  138         seldrain(&efd->efd_sel);
  139         knlist_destroy(&efd->efd_sel.si_note);
  140         mtx_destroy(&efd->efd_lock);
  141         free(efd, M_EVENTFD);
  142         return (0);
  143 }
  144 
  145 static int
  146 eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
  147     int flags, struct thread *td)
  148 {
  149         struct eventfd *efd;
  150         eventfd_t count;
  151         int error;
  152 
  153         if (uio->uio_resid < sizeof(eventfd_t))
  154                 return (EINVAL);
  155 
  156         error = 0;
  157         efd = fp->f_data;
  158         mtx_lock(&efd->efd_lock);
  159         while (error == 0 && efd->efd_count == 0) {
  160                 if ((fp->f_flag & FNONBLOCK) != 0) {
  161                         mtx_unlock(&efd->efd_lock);
  162                         return (EAGAIN);
  163                 }
  164                 error = mtx_sleep(&efd->efd_count, &efd->efd_lock, PCATCH,
  165                     "efdrd", 0);
  166         }
  167         if (error == 0) {
  168                 MPASS(efd->efd_count > 0);
  169                 if ((efd->efd_flags & EFD_SEMAPHORE) != 0) {
  170                         count = 1;
  171                         --efd->efd_count;
  172                 } else {
  173                         count = efd->efd_count;
  174                         efd->efd_count = 0;
  175                 }
  176                 KNOTE_LOCKED(&efd->efd_sel.si_note, 0);
  177                 selwakeup(&efd->efd_sel);
  178                 wakeup(&efd->efd_count);
  179                 mtx_unlock(&efd->efd_lock);
  180                 error = uiomove(&count, sizeof(eventfd_t), uio);
  181         } else
  182                 mtx_unlock(&efd->efd_lock);
  183 
  184         return (error);
  185 }
  186 
  187 static int
  188 eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
  189     int flags, struct thread *td)
  190 {
  191         struct eventfd *efd;
  192         eventfd_t count;
  193         int error;
  194 
  195         if (uio->uio_resid < sizeof(eventfd_t))
  196                 return (EINVAL);
  197 
  198         error = uiomove(&count, sizeof(eventfd_t), uio);
  199         if (error != 0)
  200                 return (error);
  201         if (count == UINT64_MAX)
  202                 return (EINVAL);
  203 
  204         efd = fp->f_data;
  205         mtx_lock(&efd->efd_lock);
  206 retry:
  207         if (UINT64_MAX - efd->efd_count <= count) {
  208                 if ((fp->f_flag & FNONBLOCK) != 0) {
  209                         mtx_unlock(&efd->efd_lock);
  210                         /* Do not not return the number of bytes written */
  211                         uio->uio_resid += sizeof(eventfd_t);
  212                         return (EAGAIN);
  213                 }
  214                 error = mtx_sleep(&efd->efd_count, &efd->efd_lock,
  215                     PCATCH, "efdwr", 0);
  216                 if (error == 0)
  217                         goto retry;
  218         }
  219         if (error == 0) {
  220                 MPASS(UINT64_MAX - efd->efd_count > count);
  221                 efd->efd_count += count;
  222                 KNOTE_LOCKED(&efd->efd_sel.si_note, 0);
  223                 selwakeup(&efd->efd_sel);
  224                 wakeup(&efd->efd_count);
  225         }
  226         mtx_unlock(&efd->efd_lock);
  227 
  228         return (error);
  229 }
  230 
  231 static int
  232 eventfd_poll(struct file *fp, int events, struct ucred *active_cred,
  233     struct thread *td)
  234 {
  235         struct eventfd *efd;
  236         int revents;
  237 
  238         efd = fp->f_data;
  239         revents = 0;
  240         mtx_lock(&efd->efd_lock);
  241         if ((events & (POLLIN | POLLRDNORM)) != 0 && efd->efd_count > 0)
  242                 revents |= events & (POLLIN | POLLRDNORM);
  243         if ((events & (POLLOUT | POLLWRNORM)) != 0 && UINT64_MAX - 1 >
  244             efd->efd_count)
  245                 revents |= events & (POLLOUT | POLLWRNORM);
  246         if (revents == 0)
  247                 selrecord(td, &efd->efd_sel);
  248         mtx_unlock(&efd->efd_lock);
  249 
  250         return (revents);
  251 }
  252 
  253 static int
  254 eventfd_kqfilter(struct file *fp, struct knote *kn)
  255 {
  256         struct eventfd *efd = fp->f_data;
  257 
  258         mtx_lock(&efd->efd_lock);
  259         switch (kn->kn_filter) {
  260         case EVFILT_READ:
  261                 kn->kn_fop = &eventfd_rfiltops;
  262                 break;
  263         case EVFILT_WRITE:
  264                 kn->kn_fop = &eventfd_wfiltops;
  265                 break;
  266         default:
  267                 mtx_unlock(&efd->efd_lock);
  268                 return (EINVAL);
  269         }
  270 
  271         kn->kn_hook = efd;
  272         knlist_add(&efd->efd_sel.si_note, kn, 1);
  273         mtx_unlock(&efd->efd_lock);
  274 
  275         return (0);
  276 }
  277 
  278 static void
  279 filt_eventfddetach(struct knote *kn)
  280 {
  281         struct eventfd *efd = kn->kn_hook;
  282 
  283         mtx_lock(&efd->efd_lock);
  284         knlist_remove(&efd->efd_sel.si_note, kn, 1);
  285         mtx_unlock(&efd->efd_lock);
  286 }
  287 
  288 static int
  289 filt_eventfdread(struct knote *kn, long hint)
  290 {
  291         struct eventfd *efd = kn->kn_hook;
  292         int ret;
  293 
  294         mtx_assert(&efd->efd_lock, MA_OWNED);
  295         kn->kn_data = (int64_t)efd->efd_count;
  296         ret = efd->efd_count > 0;
  297 
  298         return (ret);
  299 }
  300 
  301 static int
  302 filt_eventfdwrite(struct knote *kn, long hint)
  303 {
  304         struct eventfd *efd = kn->kn_hook;
  305         int ret;
  306 
  307         mtx_assert(&efd->efd_lock, MA_OWNED);
  308         kn->kn_data = (int64_t)(UINT64_MAX - 1 - efd->efd_count);
  309         ret = UINT64_MAX - 1 > efd->efd_count;
  310 
  311         return (ret);
  312 }
  313 
  314 static int
  315 eventfd_ioctl(struct file *fp, u_long cmd, void *data,
  316     struct ucred *active_cred, struct thread *td)
  317 {
  318         switch (cmd) {
  319         case FIONBIO:
  320         case FIOASYNC:
  321                 return (0);
  322         }
  323 
  324         return (ENOTTY);
  325 }
  326 
  327 static int
  328 eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred)
  329 {
  330         bzero((void *)st, sizeof *st);
  331         st->st_mode = S_IFIFO;
  332         return (0);
  333 }
  334 
  335 static int
  336 eventfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
  337 {
  338         struct eventfd *efd = fp->f_data;
  339 
  340         kif->kf_type = KF_TYPE_EVENTFD;
  341         mtx_lock(&efd->efd_lock);
  342         kif->kf_un.kf_eventfd.kf_eventfd_value = efd->efd_count;
  343         kif->kf_un.kf_eventfd.kf_eventfd_flags = efd->efd_flags;
  344         kif->kf_un.kf_eventfd.kf_eventfd_addr = (uintptr_t)efd;
  345         mtx_unlock(&efd->efd_lock);
  346         return (0);
  347 }

Cache object: a83841e27253b3538bfc80660eef19a1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.