xref: /illumos-gate/usr/src/lib/libc/port/sys/epoll.c (revision 9a686fbc186e8e2a64e9a5094d44c7d6fa0ea167)
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 }
208