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>

@@ -8,11 +8,11 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
+ * Copyright 2016 Joyent, Inc.
  */
 
 #include <sys/types.h>
 #include <sys/epoll.h>
 #include <sys/devpoll.h>

@@ -112,11 +112,11 @@
 int
 epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
 {
         dvpoll_epollfd_t epoll[2];
         uint32_t events, ev = 0;
-        int i = 0;
+        int i = 0, res;
 
         epoll[i].dpep_pollfd.fd = fd;
 
         switch (op) {
         case EPOLL_CTL_DEL:

@@ -163,12 +163,33 @@
                 errno = EOPNOTSUPP;
                 return (-1);
         }
 
         epoll[i].dpep_pollfd.events = ev;
+retry:
+        res = write(epfd, epoll, sizeof (epoll[0]) * (i + 1));
 
-        return (write(epfd, epoll, sizeof (epoll[0]) * (i + 1)) == -1 ? -1 : 0);
+        if (res == -1) {
+                if (errno == EINTR) {
+                        /*
+                         * Linux does not document EINTR as an allowed error
+                         * for epoll_ctl.  The write must be retried if it is
+                         * not done automatically via SA_RESTART.
+                         */
+                        goto retry;
+                }
+                if (errno == ELOOP) {
+                        /*
+                         * Convert the specific /dev/poll error about an fd
+                         * loop into what is expected from the Linux epoll
+                         * interface.
+                         */
+                        errno = EINVAL;
+                }
+                return (-1);
+        }
+        return (0);
 }
 
 int
 epoll_wait(int epfd, struct epoll_event *events,
     int maxevents, int timeout)