1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/types.h>
  17 #include <sys/epoll.h>
  18 #include <sys/devpoll.h>
  19 #include <unistd.h>
  20 #include <errno.h>
  21 #include <fcntl.h>
  22 #include <poll.h>
  23 
  24 /*
  25  * Events that match their epoll(7) equivalents.
  26  */
  27 #if EPOLLIN != POLLIN
  28 #error value of EPOLLIN does not match value of POLLIN
  29 #endif
  30 
  31 #if EPOLLPRI != POLLPRI
  32 #error value of EPOLLPRI does not match value of POLLPRI
  33 #endif
  34 
  35 #if EPOLLOUT != POLLOUT
  36 #error value of EPOLLOUT does not match value of POLLOUT
  37 #endif
  38 
  39 #if EPOLLRDNORM != POLLRDNORM
  40 #error value of EPOLLRDNORM does not match value of POLLRDNORM
  41 #endif
  42 
  43 #if EPOLLRDBAND != POLLRDBAND
  44 #error value of EPOLLRDBAND does not match value of POLLRDBAND
  45 #endif
  46 
  47 #if EPOLLERR != POLLERR
  48 #error value of EPOLLERR does not match value of POLLERR
  49 #endif
  50 
  51 #if EPOLLHUP != POLLHUP
  52 #error value of EPOLLHUP does not match value of POLLHUP
  53 #endif
  54 
  55 /*
  56  * Events that we ignore entirely.  They can be set in events, but they will
  57  * never be returned.
  58  */
  59 #define EPOLLIGNORED    (EPOLLMSG | EPOLLWAKEUP)
  60 
  61 /*
  62  * Events that we swizzle into other bit positions.
  63  */
  64 #define EPOLLSWIZZLED   \
  65         (EPOLLRDHUP | EPOLLONESHOT | EPOLLET | EPOLLWRBAND | EPOLLWRNORM)
  66 
  67 int
  68 epoll_create(int size)
  69 {
  70         int fd;
  71 
  72         /*
  73          * From the epoll_create() man page:  "Since Linux 2.6.8, the size
  74          * argument is ignored, but must be greater than zero."  You keep using
  75          * that word "ignored"...
  76          */
  77         if (size <= 0) {
  78                 errno = EINVAL;
  79                 return (-1);
  80         }
  81 
  82         if ((fd = open("/dev/poll", O_RDWR)) == -1)
  83                 return (-1);
  84 
  85         if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) {
  86                 (void) close(fd);
  87                 return (-1);
  88         }
  89 
  90         return (fd);
  91 }
  92 
  93 int
  94 epoll_create1(int flags)
  95 {
  96         int fd, oflags = O_RDWR;
  97 
  98         if (flags & EPOLL_CLOEXEC)
  99                 oflags |= O_CLOEXEC;
 100 
 101         if ((fd = open("/dev/poll", oflags)) == -1)
 102                 return (-1);
 103 
 104         if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) {
 105                 (void) close(fd);
 106                 return (-1);
 107         }
 108 
 109         return (fd);
 110 }
 111 
 112 int
 113 epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
 114 {
 115         dvpoll_epollfd_t epoll[2];
 116         uint32_t events, ev = 0;
 117         int i = 0;
 118 
 119         epoll[i].dpep_pollfd.fd = fd;
 120 
 121         switch (op) {
 122         case EPOLL_CTL_DEL:
 123                 ev = POLLREMOVE;
 124                 break;
 125 
 126         case EPOLL_CTL_MOD:
 127                 /*
 128                  * In the modify case, we pass down two events:  one to
 129                  * remove the event and another to add it back.
 130                  */
 131                 epoll[i++].dpep_pollfd.events = POLLREMOVE;
 132                 epoll[i].dpep_pollfd.fd = fd;
 133                 /* FALLTHROUGH */
 134 
 135         case EPOLL_CTL_ADD:
 136                 /*
 137                  * Mask off the events that we ignore, and then swizzle the
 138                  * events for which our values differ from their epoll(7)
 139                  * equivalents.
 140                  */
 141                 events = event->events;
 142                 ev = events & ~(EPOLLIGNORED | EPOLLSWIZZLED);
 143 
 144                 if (events & EPOLLRDHUP)
 145                         ev |= POLLRDHUP;
 146 
 147                 if (events & EPOLLET)
 148                         ev |= POLLET;
 149 
 150                 if (events & EPOLLONESHOT)
 151                         ev |= POLLONESHOT;
 152 
 153                 if (events & EPOLLWRNORM)
 154                         ev |= POLLWRNORM;
 155 
 156                 if (events & EPOLLWRBAND)
 157                         ev |= POLLWRBAND;
 158 
 159                 epoll[i].dpep_data = event->data.u64;
 160                 break;
 161 
 162         default:
 163                 errno = EOPNOTSUPP;
 164                 return (-1);
 165         }
 166 
 167         epoll[i].dpep_pollfd.events = ev;
 168 
 169         return (write(epfd, epoll, sizeof (epoll[0]) * (i + 1)) == -1 ? -1 : 0);
 170 }
 171 
 172 int
 173 epoll_wait(int epfd, struct epoll_event *events,
 174     int maxevents, int timeout)
 175 {
 176         struct dvpoll arg;
 177 
 178         if (maxevents <= 0) {
 179                 errno = EINVAL;
 180                 return (-1);
 181         }
 182 
 183         arg.dp_nfds = maxevents;
 184         arg.dp_timeout = timeout;
 185         arg.dp_fds = (pollfd_t *)events;
 186 
 187         return (ioctl(epfd, DP_POLL, &arg));
 188 }
 189 
 190 int
 191 epoll_pwait(int epfd, struct epoll_event *events,
 192     int maxevents, int timeout, const sigset_t *sigmask)
 193 {
 194         struct dvpoll arg;
 195 
 196         if (maxevents <= 0) {
 197                 errno = EINVAL;
 198                 return (-1);
 199         }
 200 
 201         arg.dp_nfds = maxevents;
 202         arg.dp_timeout = timeout;
 203         arg.dp_fds = (pollfd_t *)events;
 204         arg.dp_setp = (sigset_t *)sigmask;
 205 
 206         return (ioctl(epfd, DP_PPOLL, &arg));
 207 }