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/emulation/linux/linux_epoll.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  * Copyright (c) 2007 Roman Divacky
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include "opt_compat.h"
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/kern_syscall.h>
   32 #include <sys/event.h>
   33 #include <sys/lock.h>
   34 #include <sys/mplock2.h>
   35 #include <sys/malloc.h>
   36 #include <sys/ptrace.h>
   37 #include <sys/proc.h>
   38 #include <sys/signalvar.h>
   39 #include <sys/sysent.h>
   40 #include <sys/sysproto.h>
   41 #include <sys/file.h>
   42 
   43 #include <vm/vm.h>
   44 #include <vm/vm_param.h>
   45 #include <vm/vm_page.h>
   46 #include <vm/vm_extern.h>
   47 #include <sys/exec.h>
   48 #include <sys/kernel.h>
   49 #include <sys/module.h>
   50 #include <machine/cpu.h>
   51 
   52 #include "i386/linux.h"
   53 #include "i386/linux_proto.h"
   54 #include "linux_signal.h"
   55 #include "linux_util.h"
   56 #include "linux_epoll.h"
   57 
   58 
   59 /* Create a new epoll file descriptor. */
   60 int
   61 sys_linux_epoll_create(struct linux_epoll_create_args *args)
   62 {
   63         struct kqueue_args k_args;
   64 
   65         if (args->size <= 0)
   66                 return (EINVAL);
   67         /* args->size is unused. Linux ignores it as well. */
   68 
   69         return (sys_kqueue(&k_args));
   70 }
   71 
   72 /* Structure converting function from epoll to kevent. */
   73 static void
   74 linux_epoll_to_kevent(int fd, struct linux_epoll_event *event, struct kevent *kevent)
   75 {
   76         int filter = 0;
   77         int flags = kevent->flags;
   78 
   79         if (event->events & LINUX_EPOLLIN)
   80                 filter |= EVFILT_READ;
   81         if (event->events & LINUX_EPOLLOUT)
   82                 filter |= EVFILT_WRITE;
   83         if (event->events & LINUX_EPOLLPRI)
   84                 filter |= EVFILT_READ;
   85         if (event->events & LINUX_EPOLLET)
   86                 flags |= EV_CLEAR;
   87         if (event->events & LINUX_EPOLLONESHOT)
   88                 flags |= EV_ONESHOT;
   89 
   90         EV_SET(kevent, fd, filter, flags, 0, 0, NULL);
   91 }
   92 
   93 /*
   94  * Structure converting function from kevent to epoll. In a case
   95  * this is called on error in registration we store the error in
   96  * event->data and pick it up later in linux_epoll_ctl().
   97  */
   98 static void
   99 linux_kevent_to_epoll(struct kevent *kevent, struct linux_epoll_event *event)
  100 {
  101         if (kevent->flags & EV_ERROR) {
  102                 event->data = kevent->data;
  103                 return;
  104         }
  105         switch (kevent->filter) {
  106         case EVFILT_READ:
  107                 if (kevent->data > 0)
  108                         event->events = LINUX_EPOLLIN;
  109                 event->data = kevent->ident;
  110                 break;
  111         case EVFILT_WRITE:
  112                 if (kevent->data > 0)
  113                         event->events = LINUX_EPOLLOUT;
  114                 event->data = kevent->ident;
  115                 break;
  116         }
  117 }
  118 
  119 /*
  120  * Copyout callback used by kevent. This converts kevent
  121  * events to epoll events and copies them back to the
  122  * userspace. This is also called on error on registering
  123  * of the filter.
  124  */
  125 static int
  126 linux_kev_copyout(void *arg, struct kevent *kevp, int count, int *res)
  127 {
  128         struct kevent_args *uap;
  129         struct linux_epoll_event *eep;
  130         int error, i;
  131 
  132         uap = (struct kevent_args*) arg;
  133 
  134         eep = kmalloc(sizeof(*eep) * count, M_TEMP, M_WAITOK | M_ZERO);
  135 
  136         for (i = 0; i < count; i++) {
  137                 linux_kevent_to_epoll(&kevp[i], &eep[i]);
  138         }
  139 
  140         error = copyout(eep, uap->eventlist, count * sizeof(*eep));
  141         if (error == 0) {
  142                 uap->eventlist = (struct kevent *)((char *)uap->eventlist + count * sizeof(*eep));
  143                 *res += count;
  144         }
  145 
  146         kfree(eep, M_TEMP);
  147         return (error);
  148 }
  149 
  150 /*
  151  * Copyin callback used by kevent. This copies already
  152  * converted filters to the kevent internal memory.
  153  */
  154 static int
  155 linux_kev_copyin(void *arg, struct kevent *kevp, int maxevents, int *events)
  156 {
  157         struct kevent_args *uap;
  158 
  159         uap = (struct kevent_args*) arg;
  160 
  161         memcpy(kevp, uap->changelist, maxevents * sizeof(*kevp));
  162 
  163         uap->changelist += maxevents;
  164         *events = maxevents;
  165 
  166         return (0);
  167 }
  168 
  169 /*
  170  * Load epoll filter, convert it to kevent filter
  171  * and load it into kevent subsystem.
  172  */
  173 int
  174 sys_linux_epoll_ctl(struct linux_epoll_ctl_args *args)
  175 {
  176         struct thread *td = curthread;
  177         struct proc *p = td->td_proc;
  178         struct kevent_args k_args;
  179         struct kevent kev;
  180         struct kqueue *kq;
  181         struct linux_epoll_event le;
  182         struct file *fp = NULL;
  183         int error;
  184 
  185         error = copyin(args->event, &le, sizeof(le));
  186         if (error)
  187                 return (error);
  188 #ifdef DEBUG
  189         if (ldebug(epoll_ctl))
  190                 kprintf(ARGS(epoll_ctl,"%i, %i, %i, %u"), args->epfd, args->op,
  191                         args->fd, le.events);
  192 #endif
  193         k_args.fd = args->epfd;
  194         k_args.changelist = &kev;
  195         /* The epoll can register only 1 filter at once. */
  196         k_args.nchanges = 1;
  197         k_args.eventlist = NULL;
  198         k_args.nevents = 0;
  199         k_args.timeout = NULL;
  200 
  201         switch (args->op) {
  202         case LINUX_EPOLL_CTL_ADD:
  203                         kev.flags = EV_ADD | EV_ENABLE;
  204                 break;
  205         case LINUX_EPOLL_CTL_MOD:
  206                         /* TODO: DELETE && ADD maybe? */
  207                         return (EINVAL);
  208                 break;
  209         case LINUX_EPOLL_CTL_DEL:
  210                         kev.flags = EV_DELETE | EV_DISABLE;
  211                 break;
  212         }
  213         linux_epoll_to_kevent(args->fd, &le, &kev);
  214 
  215         fp = holdfp(p->p_fd, args->epfd, -1);
  216         if (fp == NULL)
  217                 return (EBADF);
  218         if (fp->f_type != DTYPE_KQUEUE) {
  219                 fdrop(fp);
  220                 return (EBADF);
  221         }
  222 
  223         kq = (struct kqueue *)fp->f_data;
  224 
  225         error = kern_kevent(kq, 0, &k_args.sysmsg_result, &k_args,
  226             linux_kev_copyin, linux_kev_copyout, NULL);
  227         /* Check if there was an error during registration. */
  228         if (error == 0 && k_args.sysmsg_result != 0) {
  229                 /* The copyout callback stored the error there. */
  230                 error = le.data;
  231         }
  232 
  233         fdrop(fp);
  234         return (error);
  235 }
  236 
  237 /*
  238  * Wait for a filter to be triggered on the epoll file descriptor. */
  239 int
  240 sys_linux_epoll_wait(struct linux_epoll_wait_args *args)
  241 {
  242         struct thread *td = curthread;
  243         struct proc *p = td->td_proc;
  244         struct timespec ts;
  245         struct kqueue *kq;
  246         struct file *fp = NULL;
  247         struct kevent_args k_args;
  248         int error;
  249 
  250         /* Convert from milliseconds to timespec. */
  251         ts.tv_sec = args->timeout / 1000;
  252         ts.tv_nsec = (args->timeout % 1000) * 1000 * 1000;
  253 
  254         k_args.fd = args->epfd;
  255         k_args.changelist = NULL;
  256         k_args.nchanges = 0;
  257         /*
  258          * We don't mind the bogus type-cast because
  259          * our copyout function knows about this and
  260          * handles it correctly.
  261          */
  262         k_args.eventlist = (struct kevent *)args->events;
  263         k_args.nevents = args->maxevents;
  264         k_args.timeout = &ts;
  265 
  266         fp = holdfp(p->p_fd, args->epfd, -1);
  267         if (fp == NULL)
  268                 return (EBADF);
  269         if (fp->f_type != DTYPE_KQUEUE) {
  270                 fdrop(fp);
  271                 return (EBADF);
  272         }
  273 
  274         kq = (struct kqueue *)fp->f_data;
  275 
  276         error = kern_kevent(kq, args->maxevents, &args->sysmsg_result,
  277             &k_args, linux_kev_copyin, linux_kev_copyout, &ts);
  278 
  279         fdrop(fp);
  280         /* translation? */
  281         return (error);
  282 }

Cache object: 9f5b4bfc13f7c5527aca31236b8f5a96


[ 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.