1 /* ==========================================================================
2  * kpoll.c - Brew of Linux epoll, BSD kqueue, and Solaris Ports.
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2012  William Ahern
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to permit
11  * persons to whom the Software is furnished to do so, subject to the
12  * following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * ==========================================================================
25  */
26 #include <stddef.h>	/* NULL offsetof */
27 
28 #include <string.h>	/* memset(3) */
29 
30 #include <time.h>	/* struct timespec */
31 
32 #include <errno.h>	/* errno */
33 
34 #include <poll.h>	/* POLLIN POLLOUT */
35 
36 #include <unistd.h>	/* [FEATURES] read(2) write(2) */
37 
38 #ifndef __GLIBC_PREREQ
39 #define __GLIBC_PREREQ(m, n) 0
40 #endif
41 
42 #ifndef HAVE_KQUEUE
43 #define HAVE_KQUEUE (__FreeBSD__ || __NetBSD__ || __OpenBSD__ || __APPLE__)
44 #endif
45 
46 #ifndef HAVE_EPOLL
47 #define HAVE_EPOLL (__linux__)
48 #endif
49 
50 #ifndef HAVE_PORTS
51 #define HAVE_PORTS (__sun)
52 #endif
53 
54 #ifndef HAVE_EPOLL_CREATE1
55 #define HAVE_EPOLL_CREATE1 (HAVE_EPOLL && __GLIBC_PREREQ(2, 9))
56 #endif
57 
58 #ifndef HAVE_PIPE2
59 #define HAVE_PIPE2 __GLIBC_PREREQ(2, 9)
60 #endif
61 
62 #if HAVE_EPOLL
63 #include <sys/epoll.h>	/* struct epoll_event epoll_create(2) epoll_ctl(2) epoll_wait(2) */
64 #elif HAVE_PORTS
65 #include <port.h>	/* PORT_SOURCE_FD port_associate(2) port_disassociate(2) port_getn(2) port_alert(2) */
66 #else
67 #include <sys/event.h>	/* EVFILT_READ EVFILT_WRITE EV_SET EV_ADD EV_DELETE struct kevent kqueue(2) kevent(2) */
68 #endif
69 
70 #include <sys/queue.h>	/* LIST_ENTRY LIST_HEAD LIST_REMOVE LIST_INSERT_HEAD */
71 
72 #include <fcntl.h>	/* F_GETFL F_SETFL F_GETFD F_SETFD FD_CLOEXEC O_NONBLOCK O_CLOEXEC fcntl(2) */
73 
74 
75 #define KPOLL_MAXWAIT 32
76 
77 #define countof(a) (sizeof (a) / sizeof *(a))
78 
79 #if __GNUC__ >= 3
80 #define unlikely(expr) __builtin_expect((expr), 0)
81 #else
82 #define unlikely(expr) (expr)
83 #endif
84 
85 
setnonblock(int fd)86 static int setnonblock(int fd) {
87 	int flags;
88 
89 	if (-1 == (flags = fcntl(fd, F_GETFL)))
90 		return errno;
91 
92 	if (!(flags & O_NONBLOCK)) {
93 		if (-1 == fcntl(fd, F_SETFL, (flags | O_NONBLOCK)))
94 			return errno;
95 	}
96 
97 	return 0;
98 } /* setnonblock() */
99 
100 
setcloexec(int fd)101 static int setcloexec(int fd) {
102 	int flags;
103 
104 	if (-1 == (flags = fcntl(fd, F_GETFD)))
105 		return errno;
106 
107 	if (!(flags & FD_CLOEXEC)) {
108 		if (-1 == fcntl(fd, F_SETFD, (flags | FD_CLOEXEC)))
109 			return errno;
110 	}
111 
112 	return 0;
113 } /* setcloexec() */
114 
115 
closefd(int * fd)116 static void closefd(int *fd) {
117 	if (*fd >= 0) {
118 		while (0 != close(*fd) && errno == EINTR)
119 			;;
120 		*fd = -1;
121 	}
122 } /* closefd() */
123 
124 
125 #if HAVE_EPOLL
126 typedef struct epoll_event event_t;
127 #elif HAVE_PORTS
128 typedef port_event_t event_t;
129 #else
130 /* NetBSD uses intptr_t while others use void * for .udata */
131 #define EV_SETx(ev, a, b, c, d, e, f) EV_SET((ev), (a), (b), (c), (d), (e), ((__typeof__((ev)->udata))(f)))
132 
133 typedef struct kevent event_t;
134 #endif
135 
136 
event_udata(const event_t * event)137 static inline void *event_udata(const event_t *event) {
138 #if HAVE_EPOLL
139 	return event->data.ptr;
140 #elif HAVE_PORTS
141 	return event->portev_user;
142 #else
143 	return (void *)event->udata;
144 #endif
145 } /* event_udata() */
146 
147 
event_pending(const event_t * event)148 static inline short event_pending(const event_t *event) {
149 #if HAVE_EPOLL
150 	return event->events;
151 #elif HAVE_PORTS
152 	return event->portev_events;
153 #else
154 	return (event->filter == EVFILT_READ)? POLLIN : (event->filter == EVFILT_WRITE)? POLLOUT : 0;
155 #endif
156 } /* event_pending() */
157 
158 
159 struct kpollfd {
160 	int fd;
161 	short events;
162 	short revents;
163 	LIST_ENTRY(kpollfd) le;
164 }; /* struct kpollfd */
165 
166 
167 struct kpoll {
168 	int fd;
169 
170 	LIST_HEAD(, kpollfd) pending;
171 	LIST_HEAD(, kpollfd) polling;
172 	LIST_HEAD(, kpollfd) dormant;
173 
174 	struct {
175 		struct kpollfd event;
176 		int fd[2];
177 	} alert;
178 }; /* struct kpoll */
179 
180 
kpoll_move(struct kpoll * kp,struct kpollfd * fd)181 static void kpoll_move(struct kpoll *kp, struct kpollfd *fd) {
182 	LIST_REMOVE(fd, le);
183 
184 	if (fd->revents)
185 		LIST_INSERT_HEAD(&kp->pending, fd, le);
186 	else if (fd->events)
187 		LIST_INSERT_HEAD(&kp->polling, fd, le);
188 	else
189 		LIST_INSERT_HEAD(&kp->dormant, fd, le);
190 } /* kpoll_move() */
191 
192 
kpoll_next(struct kpoll * kp)193 static struct kpollfd *kpoll_next(struct kpoll *kp) {
194 	return LIST_FIRST(&kp->pending);
195 } /* kpoll_next() */
196 
197 
kpoll_ctl(struct kpoll * kp,struct kpollfd * fd,short events)198 static int kpoll_ctl(struct kpoll *kp, struct kpollfd *fd, short events) {
199 	int error = 0;
200 
201 	if (fd->events == events)
202 		goto reset;
203 
204 #if HAVE_EPOLL
205 	struct epoll_event event;
206 	int op;
207 
208 	op = (!fd->events)? EPOLL_CTL_ADD : (!events)? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
209 
210 	memset(&event, 0, sizeof event);
211 
212 	event.events = events;
213 	event.data.ptr = fd;
214 
215 	if (0 != epoll_ctl(kp->fd, op, fd->fd, &event))
216 		goto error;
217 
218 	fd->events = events;
219 #elif HAVE_PORTS
220 	if (!events) {
221 		if (0 != port_dissociate(kp->fd, PORT_SOURCE_FD, fd->fd))
222 			goto error;
223 	} else {
224 		if (0 != port_associate(kp->fd, PORT_SOURCE_FD, fd->fd, events, fd))
225 			goto error;
226 	}
227 
228 	fd->events = events;
229 #else
230 	struct kevent event;
231 
232 	if (events & POLLIN) {
233 		if (!(fd->events & POLLIN)) {
234 			EV_SETx(&event, fd->fd, EVFILT_READ, EV_ADD, 0, 0, fd);
235 
236 			if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
237 				goto error;
238 
239 			fd->events |= POLLIN;
240 		}
241 	} else if (fd->events & POLLIN) {
242 		EV_SETx(&event, fd->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
243 
244 		if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
245 			goto error;
246 
247 		fd->events &= ~POLLIN;
248 	}
249 
250 	if (events & POLLOUT) {
251 		if (!(fd->events & POLLOUT)) {
252 			EV_SETx(&event, fd->fd, EVFILT_WRITE, EV_ADD, 0, 0, fd);
253 
254 			if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
255 				goto error;
256 
257 			fd->events |= POLLOUT;
258 		}
259 	} else if (fd->events & POLLOUT) {
260 		EV_SETx(&event, fd->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
261 
262 		if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
263 			goto error;
264 
265 		fd->events &= ~POLLOUT;
266 	}
267 #endif
268 
269 reset:
270 	fd->revents = 0;
271 
272 	kpoll_move(kp, fd);
273 
274 	return error;
275 error:
276 	error = errno;
277 
278 	goto reset;
279 } /* kpoll_ctl() */
280 
281 
kpoll_add(struct kpoll * kp,struct kpollfd * pfd,int fd)282 static void kpoll_add(struct kpoll *kp, struct kpollfd *pfd, int fd) {
283 	pfd->fd = fd;
284 	pfd->events = 0;
285 	pfd->revents = 0;
286 
287 	LIST_INSERT_HEAD(&kp->dormant, pfd, le);
288 } /* kpoll_add() */
289 
290 
kpoll_del(struct kpoll * kp,struct kpollfd * fd)291 static void kpoll_del(struct kpoll *kp, struct kpollfd *fd) {
292 	kpoll_ctl(kp, fd, 0);
293 
294 	LIST_REMOVE(fd, le);
295 } /* kpoll_del() */
296 
297 
kpoll_alert(struct kpoll * kp)298 static int kpoll_alert(struct kpoll *kp) {
299 #if HAVE_PORTS
300 	return (!port_alert(kp->fd, PORT_ALERT_SET, POLLIN, &kp->alert.event))? 0 : errno;
301 #else
302 	while (1 != write(kp->alert.fd[1], "!", 1)) {
303 		switch (errno) {
304 		case EINTR:
305 			continue;
306 		case EAGAIN:
307 			return 0;
308 		default:
309 			return errno;
310 		}
311 	}
312 
313 	return kpoll_ctl(kp, &kp->alert.event, POLLIN);
314 #endif
315 } /* kpoll_alert() */
316 
317 
kpoll_calm(struct kpoll * kp)318 static int kpoll_calm(struct kpoll *kp) {
319 #if HAVE_PORTS
320 	return (!port_alert(kp->fd, PORT_ALERT_SET, 0, &kp->alert.event))? 0 : errno;
321 #else
322 	char buf[512];
323 
324 	while (read(kp->alert.fd[0], buf, sizeof buf) > 0)
325 		;;
326 
327 	return kpoll_ctl(kp, &kp->alert.event, POLLIN);
328 #endif
329 } /* kpoll_calm() */
330 
331 
ms2ts_(struct timespec * ts,int ms)332 static inline struct timespec *ms2ts_(struct timespec *ts, int ms) {
333 	if (ms < 0) return 0;
334 	ts->tv_sec = ms / 1000;
335 	ts->tv_nsec = (ms % 1000) * 1000000;
336 	return ts;
337 } /* ms2ts_() */
338 
339 #define ms2ts(ms) (ms2ts_(&(struct timespec){ 0, 0 }, (ms)))
340 
341 
kpoll_wait(struct kpoll * kp,int timeout)342 static int kpoll_wait(struct kpoll *kp, int timeout) {
343 	event_t event[KPOLL_MAXWAIT];
344 	struct kpollfd *fd;
345 	int error;
346 
347 	if (!LIST_EMPTY(&kp->pending))
348 		return 0;
349 
350 #if HAVE_EPOLL
351 	int i, n;
352 
353 	if (-1 == (n = epoll_wait(kp->fd, event, (int)countof(event), timeout)))
354 		return (errno == EINTR)? 0 : errno;
355 #elif HAVE_PORTS
356 	uint_t i, n = 1;
357 
358 	if (0 != port_getn(kp->fd, event, countof(event), &n, ms2ts(timeout)))
359 		return (errno == ETIME || errno == EINTR)? 0 : errno;
360 #else
361 	int i, n;
362 
363 	if (-1 == (n = kevent(kp->fd, NULL, 0, event, (int)countof(event), ms2ts(timeout))))
364 		return (errno == EINTR)? 0 : errno;
365 #endif
366 
367 	for (i = 0; i < n; i++) {
368 		fd = event_udata(&event[i]);
369 #if HAVE_PORTS
370 		fd->events = 0;
371 #endif
372 
373 		if (unlikely(fd == &kp->alert.event)) {
374 			if ((error = kpoll_calm(kp)))
375 				return error;
376 		} else {
377 			fd->revents |= event_pending(&event[i]);
378 			kpoll_move(kp, fd);
379 		}
380 	}
381 
382 	return 0;
383 } /* kpoll_wait() */
384 
385 
alert_init(struct kpoll * kp)386 static int alert_init(struct kpoll *kp) {
387 #if HAVE_PORTS
388 	return 0;
389 #else
390 	int error;
391 
392 #if HAVE_PIPE2
393 	if (0 != pipe2(kp->alert.fd, O_CLOEXEC|O_NONBLOCK))
394 		return errno;
395 #else
396 	if (0 != pipe(kp->alert.fd))
397 		return errno;
398 
399 	for (int i = 0; i < 2; i++) {
400 		if ((error = setcloexec(kp->alert.fd[i]))
401 		||  (error = setnonblock(kp->alert.fd[i])))
402 			return error;
403 	}
404 #endif
405 
406 	kpoll_add(kp, &kp->alert.event, kp->alert.fd[0]);
407 
408 	return kpoll_ctl(kp, &kp->alert.event, POLLIN);
409 #endif
410 } /* alert_init() */
411 
412 
alert_destroy(struct kpoll * kp)413 static void alert_destroy(struct kpoll *kp) {
414 #if HAVE_PORTS
415 	(void)0;
416 #else
417 	closefd(&kp->alert.fd[0]);
418 	closefd(&kp->alert.fd[1]);
419 #endif
420 } /* alert_destroy() */
421 
422 
kpoll_destroy(struct kpoll * kp)423 static void kpoll_destroy(struct kpoll *kp) {
424 	closefd(&kp->fd);
425 
426 	alert_destroy(kp);
427 
428 	LIST_INIT(&kp->pending);
429 	LIST_INIT(&kp->polling);
430 	LIST_INIT(&kp->dormant);
431 } /* kpoll_destroy() */
432 
433 
kpoll_init(struct kpoll * kp)434 static int kpoll_init(struct kpoll *kp) {
435 	int error;
436 
437 	kp->fd = -1;
438 	kp->alert.fd[0] = -1;
439 	kp->alert.fd[1] = -1;
440 
441 	LIST_INIT(&kp->pending);
442 	LIST_INIT(&kp->polling);
443 	LIST_INIT(&kp->dormant);
444 
445 #if HAVE_EPOLL_CREATE1
446 	if (-1 == (kp->fd = epoll_create1(O_CLOEXEC)))
447 		goto syerr;
448 #elif HAVE_EPOLL
449 	if (-1 == (kp->fd = epoll_create(0)))
450 		goto syerr;
451 #elif HAVE_PORTS
452 	if (-1 == (kp->fd = port_create())) {
453 		if (errno == EAGAIN) { /* too confusing */
454 			error = EMFILE;
455 			goto error;
456 		} else
457 			goto syerr;
458 	}
459 #else
460 	if (-1 == (kp->fd = kqueue()))
461 		goto syerr;
462 #endif
463 
464 #if !HAVE_EPOLL_CREATE1
465 	if ((error = setcloexec(kp->fd)))
466 		goto error;
467 #endif
468 
469 	if ((error = alert_init(kp)))
470 		goto error;
471 
472 	return 0;
473 syerr:
474 	error = errno;
475 error:
476 	kpoll_destroy(kp);
477 
478 	return error;
479 } /* kpoll_init() */
480 
481 
main(void)482 int main(void) {
483 	return 0;
484 }
485