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 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 flags ^= EPOLL_CLOEXEC; 101 } 102 /* Reject unrecognized flags */ 103 if (flags != 0) { 104 errno = EINVAL; 105 return (-1); 106 } 107 108 if ((fd = open("/dev/poll", oflags)) == -1) 109 return (-1); 110 111 if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) { 112 (void) close(fd); 113 return (-1); 114 } 115 116 return (fd); 117 } 118 119 int 120 epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 121 { 122 dvpoll_epollfd_t epoll[2]; 123 uint32_t events, ev = 0; 124 int i = 0, res; 125 126 epoll[i].dpep_pollfd.fd = fd; 127 128 switch (op) { 129 case EPOLL_CTL_DEL: 130 ev = POLLREMOVE; 131 break; 132 133 case EPOLL_CTL_MOD: 134 /* 135 * In the modify case, we pass down two events: one to 136 * remove the event and another to add it back. 137 */ 138 epoll[i++].dpep_pollfd.events = POLLREMOVE; 139 epoll[i].dpep_pollfd.fd = fd; 140 /* FALLTHROUGH */ 141 142 case EPOLL_CTL_ADD: 143 /* 144 * Mask off the events that we ignore, and then swizzle the 145 * events for which our values differ from their epoll(7) 146 * equivalents. 147 */ 148 events = event->events; 149 ev = events & ~(EPOLLIGNORED | EPOLLSWIZZLED); 150 151 if (events & EPOLLRDHUP) 152 ev |= POLLRDHUP; 153 154 if (events & EPOLLET) 155 ev |= POLLET; 156 157 if (events & EPOLLONESHOT) 158 ev |= POLLONESHOT; 159 160 if (events & EPOLLWRNORM) 161 ev |= POLLWRNORM; 162 163 if (events & EPOLLWRBAND) 164 ev |= POLLWRBAND; 165 166 epoll[i].dpep_data = event->data.u64; 167 break; 168 169 default: 170 errno = EOPNOTSUPP; 171 return (-1); 172 } 173 174 epoll[i].dpep_pollfd.events = ev; 175 retry: 176 res = write(epfd, epoll, sizeof (epoll[0]) * (i + 1)); 177 178 if (res == -1) { 179 if (errno == EINTR) { 180 /* 181 * Linux does not document EINTR as an allowed error 182 * for epoll_ctl. The write must be retried if it is 183 * not done automatically via SA_RESTART. 184 */ 185 goto retry; 186 } 187 if (errno == ELOOP) { 188 /* 189 * Convert the specific /dev/poll error about an fd 190 * loop into what is expected from the Linux epoll 191 * interface. 192 */ 193 errno = EINVAL; 194 } 195 return (-1); 196 } 197 return (0); 198 } 199 200 int 201 epoll_wait(int epfd, struct epoll_event *events, 202 int maxevents, int timeout) 203 { 204 struct dvpoll arg; 205 206 if (maxevents <= 0) { 207 errno = EINVAL; 208 return (-1); 209 } 210 211 arg.dp_nfds = maxevents; 212 arg.dp_timeout = timeout; 213 arg.dp_fds = (pollfd_t *)events; 214 215 return (ioctl(epfd, DP_POLL, &arg)); 216 } 217 218 int 219 epoll_pwait(int epfd, struct epoll_event *events, 220 int maxevents, int timeout, const sigset_t *sigmask) 221 { 222 struct dvpoll arg; 223 224 if (maxevents <= 0) { 225 errno = EINVAL; 226 return (-1); 227 } 228 229 arg.dp_nfds = maxevents; 230 arg.dp_timeout = timeout; 231 arg.dp_fds = (pollfd_t *)events; 232 arg.dp_setp = (sigset_t *)sigmask; 233 234 return (ioctl(epfd, DP_PPOLL, &arg)); 235 } 236