Print this page
OS-5518 devpoll write feigns success in the face of EINTR
OS-5520 epoll_ctl not allowed to emit EINTR
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-5459 epoll_ctl should throw EINVAL for loops
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
   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


  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


 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 
   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 2016 Joyent, Inc.
  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


  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, res;
 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


 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 retry:
 169         res = write(epfd, epoll, sizeof (epoll[0]) * (i + 1));
 170 
 171         if (res == -1) {
 172                 if (errno == EINTR) {
 173                         /*
 174                          * Linux does not document EINTR as an allowed error
 175                          * for epoll_ctl.  The write must be retried if it is
 176                          * not done automatically via SA_RESTART.
 177                          */
 178                         goto retry;
 179                 }
 180                 if (errno == ELOOP) {
 181                         /*
 182                          * Convert the specific /dev/poll error about an fd
 183                          * loop into what is expected from the Linux epoll
 184                          * interface.
 185                          */
 186                         errno = EINVAL;
 187                 }
 188                 return (-1);
 189         }
 190         return (0);
 191 }
 192 
 193 int
 194 epoll_wait(int epfd, struct epoll_event *events,
 195     int maxevents, int timeout)
 196 {
 197         struct dvpoll arg;
 198 
 199         if (maxevents <= 0) {
 200                 errno = EINVAL;
 201                 return (-1);
 202         }
 203 
 204         arg.dp_nfds = maxevents;
 205         arg.dp_timeout = timeout;
 206         arg.dp_fds = (pollfd_t *)events;
 207 
 208         return (ioctl(epfd, DP_POLL, &arg));
 209 }
 210