/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2016 Joyent, Inc. */ #include #include #include #include #include #include #include /* * Events that match their epoll(7) equivalents. */ #if EPOLLIN != POLLIN #error value of EPOLLIN does not match value of POLLIN #endif #if EPOLLPRI != POLLPRI #error value of EPOLLPRI does not match value of POLLPRI #endif #if EPOLLOUT != POLLOUT #error value of EPOLLOUT does not match value of POLLOUT #endif #if EPOLLRDNORM != POLLRDNORM #error value of EPOLLRDNORM does not match value of POLLRDNORM #endif #if EPOLLRDBAND != POLLRDBAND #error value of EPOLLRDBAND does not match value of POLLRDBAND #endif #if EPOLLERR != POLLERR #error value of EPOLLERR does not match value of POLLERR #endif #if EPOLLHUP != POLLHUP #error value of EPOLLHUP does not match value of POLLHUP #endif /* * Events that we ignore entirely. They can be set in events, but they will * never be returned. */ #define EPOLLIGNORED (EPOLLMSG | EPOLLWAKEUP) /* * Events that we swizzle into other bit positions. */ #define EPOLLSWIZZLED \ (EPOLLRDHUP | EPOLLONESHOT | EPOLLET | EPOLLWRBAND | EPOLLWRNORM) int epoll_create(int size) { int fd; /* * From the epoll_create() man page: "Since Linux 2.6.8, the size * argument is ignored, but must be greater than zero." You keep using * that word "ignored"... */ if (size <= 0) { errno = EINVAL; return (-1); } if ((fd = open("/dev/poll", O_RDWR)) == -1) return (-1); if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) { (void) close(fd); return (-1); } return (fd); } int epoll_create1(int flags) { int fd, oflags = O_RDWR; if (flags & EPOLL_CLOEXEC) { oflags |= O_CLOEXEC; flags ^= EPOLL_CLOEXEC; } /* Reject unrecognized flags */ if (flags != 0) { errno = EINVAL; return (-1); } if ((fd = open("/dev/poll", oflags)) == -1) return (-1); if (ioctl(fd, DP_EPOLLCOMPAT, 0) == -1) { (void) close(fd); return (-1); } return (fd); } 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, res; epoll[i].dpep_pollfd.fd = fd; switch (op) { case EPOLL_CTL_DEL: ev = POLLREMOVE; break; case EPOLL_CTL_MOD: /* * In the modify case, we pass down two events: one to * remove the event and another to add it back. */ epoll[i++].dpep_pollfd.events = POLLREMOVE; epoll[i].dpep_pollfd.fd = fd; /* FALLTHROUGH */ case EPOLL_CTL_ADD: /* * Mask off the events that we ignore, and then swizzle the * events for which our values differ from their epoll(7) * equivalents. */ events = event->events; ev = events & ~(EPOLLIGNORED | EPOLLSWIZZLED); if (events & EPOLLRDHUP) ev |= POLLRDHUP; if (events & EPOLLET) ev |= POLLET; if (events & EPOLLONESHOT) ev |= POLLONESHOT; if (events & EPOLLWRNORM) ev |= POLLWRNORM; if (events & EPOLLWRBAND) ev |= POLLWRBAND; epoll[i].dpep_data = event->data.u64; break; default: errno = EOPNOTSUPP; return (-1); } epoll[i].dpep_pollfd.events = ev; retry: res = write(epfd, epoll, sizeof (epoll[0]) * (i + 1)); 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) { struct dvpoll arg; if (maxevents <= 0) { errno = EINVAL; return (-1); } arg.dp_nfds = maxevents; arg.dp_timeout = timeout; arg.dp_fds = (pollfd_t *)events; return (ioctl(epfd, DP_POLL, &arg)); } int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask) { struct dvpoll arg; if (maxevents <= 0) { errno = EINVAL; return (-1); } arg.dp_nfds = maxevents; arg.dp_timeout = timeout; arg.dp_fds = (pollfd_t *)events; arg.dp_setp = (sigset_t *)sigmask; return (ioctl(epfd, DP_PPOLL, &arg)); }