xref: /illumos-gate/usr/src/cmd/bhyve/mevent.c (revision 154972af)
14c87aefeSPatrick Mooney /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2011 NetApp, Inc.
54c87aefeSPatrick Mooney  * All rights reserved.
64c87aefeSPatrick Mooney  *
74c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
84c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
94c87aefeSPatrick Mooney  * are met:
104c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
114c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
124c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
144c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
154c87aefeSPatrick Mooney  *
164c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
174c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
204c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264c87aefeSPatrick Mooney  * SUCH DAMAGE.
274c87aefeSPatrick Mooney  *
284c87aefeSPatrick Mooney  * $FreeBSD$
294c87aefeSPatrick Mooney  */
304c87aefeSPatrick Mooney 
314c87aefeSPatrick Mooney /*
324c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
334c87aefeSPatrick Mooney  */
344c87aefeSPatrick Mooney 
354c87aefeSPatrick Mooney /*
364c87aefeSPatrick Mooney  * Micro event library for FreeBSD, designed for a single i/o thread
374c87aefeSPatrick Mooney  * using kqueue, and having events be persistent by default.
384c87aefeSPatrick Mooney  */
394c87aefeSPatrick Mooney 
404c87aefeSPatrick Mooney #include <sys/cdefs.h>
414c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
424c87aefeSPatrick Mooney 
434c87aefeSPatrick Mooney #include <assert.h>
444c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
454c87aefeSPatrick Mooney #include <capsicum_helpers.h>
464c87aefeSPatrick Mooney #endif
474c87aefeSPatrick Mooney #include <err.h>
484c87aefeSPatrick Mooney #include <errno.h>
49*154972afSPatrick Mooney #include <stdbool.h>
504c87aefeSPatrick Mooney #include <stdlib.h>
514c87aefeSPatrick Mooney #include <stdio.h>
524c87aefeSPatrick Mooney #include <string.h>
534c87aefeSPatrick Mooney #include <sysexits.h>
544c87aefeSPatrick Mooney #include <unistd.h>
554c87aefeSPatrick Mooney 
564c87aefeSPatrick Mooney #include <sys/types.h>
574c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
584c87aefeSPatrick Mooney #include <sys/capsicum.h>
594c87aefeSPatrick Mooney #endif
604c87aefeSPatrick Mooney #ifdef __FreeBSD__
614c87aefeSPatrick Mooney #include <sys/event.h>
624c87aefeSPatrick Mooney #else
634c87aefeSPatrick Mooney #include <port.h>
644c87aefeSPatrick Mooney #include <sys/poll.h>
654c87aefeSPatrick Mooney #include <sys/siginfo.h>
664c87aefeSPatrick Mooney #include <sys/queue.h>
67*154972afSPatrick Mooney #include <sys/debug.h>
684c87aefeSPatrick Mooney #endif
694c87aefeSPatrick Mooney #include <sys/time.h>
704c87aefeSPatrick Mooney 
714c87aefeSPatrick Mooney #include <pthread.h>
724c87aefeSPatrick Mooney #include <pthread_np.h>
734c87aefeSPatrick Mooney 
744c87aefeSPatrick Mooney #include "mevent.h"
754c87aefeSPatrick Mooney 
764c87aefeSPatrick Mooney #define	MEVENT_MAX	64
774c87aefeSPatrick Mooney 
78*154972afSPatrick Mooney #ifndef __FreeBSD__
79*154972afSPatrick Mooney #define	EV_ENABLE	0x01
80*154972afSPatrick Mooney #define	EV_ADD		EV_ENABLE
81*154972afSPatrick Mooney #define	EV_DISABLE	0x02
82*154972afSPatrick Mooney #define	EV_DELETE	0x04
83*154972afSPatrick Mooney #endif
844c87aefeSPatrick Mooney 
854c87aefeSPatrick Mooney extern char *vmname;
864c87aefeSPatrick Mooney 
874c87aefeSPatrick Mooney static pthread_t mevent_tid;
884c87aefeSPatrick Mooney static int mevent_timid = 43;
894c87aefeSPatrick Mooney static int mevent_pipefd[2];
904c87aefeSPatrick Mooney static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
914c87aefeSPatrick Mooney 
924c87aefeSPatrick Mooney struct mevent {
934c87aefeSPatrick Mooney 	void	(*me_func)(int, enum ev_type, void *);
944c87aefeSPatrick Mooney #define me_msecs me_fd
954c87aefeSPatrick Mooney 	int	me_fd;
964c87aefeSPatrick Mooney #ifdef __FreeBSD__
974c87aefeSPatrick Mooney 	int	me_timid;
984c87aefeSPatrick Mooney #else
994c87aefeSPatrick Mooney 	timer_t me_timid;
1004c87aefeSPatrick Mooney #endif
1014c87aefeSPatrick Mooney 	enum ev_type me_type;
1024c87aefeSPatrick Mooney 	void    *me_param;
1034c87aefeSPatrick Mooney 	int	me_cq;
104*154972afSPatrick Mooney 	int	me_state; /* Desired kevent flags. */
1054c87aefeSPatrick Mooney 	int	me_closefd;
1064c87aefeSPatrick Mooney #ifndef __FreeBSD__
1074c87aefeSPatrick Mooney 	port_notify_t	me_notify;
1084c87aefeSPatrick Mooney 	struct sigevent	me_sigev;
1094c87aefeSPatrick Mooney 	boolean_t	me_auto_requeue;
1104c87aefeSPatrick Mooney #endif
1114c87aefeSPatrick Mooney 	LIST_ENTRY(mevent) me_list;
1124c87aefeSPatrick Mooney };
1134c87aefeSPatrick Mooney 
1144c87aefeSPatrick Mooney static LIST_HEAD(listhead, mevent) global_head, change_head;
1154c87aefeSPatrick Mooney 
1164c87aefeSPatrick Mooney static void
1174c87aefeSPatrick Mooney mevent_qlock(void)
1184c87aefeSPatrick Mooney {
1194c87aefeSPatrick Mooney 	pthread_mutex_lock(&mevent_lmutex);
1204c87aefeSPatrick Mooney }
1214c87aefeSPatrick Mooney 
1224c87aefeSPatrick Mooney static void
1234c87aefeSPatrick Mooney mevent_qunlock(void)
1244c87aefeSPatrick Mooney {
1254c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mevent_lmutex);
1264c87aefeSPatrick Mooney }
1274c87aefeSPatrick Mooney 
1284c87aefeSPatrick Mooney static void
1294c87aefeSPatrick Mooney mevent_pipe_read(int fd, enum ev_type type, void *param)
1304c87aefeSPatrick Mooney {
1314c87aefeSPatrick Mooney 	char buf[MEVENT_MAX];
1324c87aefeSPatrick Mooney 	int status;
1334c87aefeSPatrick Mooney 
1344c87aefeSPatrick Mooney 	/*
1354c87aefeSPatrick Mooney 	 * Drain the pipe read side. The fd is non-blocking so this is
1364c87aefeSPatrick Mooney 	 * safe to do.
1374c87aefeSPatrick Mooney 	 */
1384c87aefeSPatrick Mooney 	do {
1394c87aefeSPatrick Mooney 		status = read(fd, buf, sizeof(buf));
1404c87aefeSPatrick Mooney 	} while (status == MEVENT_MAX);
1414c87aefeSPatrick Mooney }
1424c87aefeSPatrick Mooney 
1434c87aefeSPatrick Mooney static void
1444c87aefeSPatrick Mooney mevent_notify(void)
1454c87aefeSPatrick Mooney {
14684659b24SMichael Zeller 	char c = '\0';
1474c87aefeSPatrick Mooney 
1484c87aefeSPatrick Mooney 	/*
1494c87aefeSPatrick Mooney 	 * If calling from outside the i/o thread, write a byte on the
1504c87aefeSPatrick Mooney 	 * pipe to force the i/o thread to exit the blocking kevent call.
1514c87aefeSPatrick Mooney 	 */
1524c87aefeSPatrick Mooney 	if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) {
1534c87aefeSPatrick Mooney 		write(mevent_pipefd[1], &c, 1);
1544c87aefeSPatrick Mooney 	}
1554c87aefeSPatrick Mooney }
1564c87aefeSPatrick Mooney #ifdef __FreeBSD__
1574c87aefeSPatrick Mooney static int
1584c87aefeSPatrick Mooney mevent_kq_filter(struct mevent *mevp)
1594c87aefeSPatrick Mooney {
1604c87aefeSPatrick Mooney 	int retval;
1614c87aefeSPatrick Mooney 
1624c87aefeSPatrick Mooney 	retval = 0;
1634c87aefeSPatrick Mooney 
1644c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_READ)
1654c87aefeSPatrick Mooney 		retval = EVFILT_READ;
1664c87aefeSPatrick Mooney 
1674c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_WRITE)
1684c87aefeSPatrick Mooney 		retval = EVFILT_WRITE;
1694c87aefeSPatrick Mooney 
1704c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_TIMER)
1714c87aefeSPatrick Mooney 		retval = EVFILT_TIMER;
1724c87aefeSPatrick Mooney 
1734c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_SIGNAL)
1744c87aefeSPatrick Mooney 		retval = EVFILT_SIGNAL;
1754c87aefeSPatrick Mooney 
1764c87aefeSPatrick Mooney 	return (retval);
1774c87aefeSPatrick Mooney }
1784c87aefeSPatrick Mooney 
1794c87aefeSPatrick Mooney static int
1804c87aefeSPatrick Mooney mevent_kq_flags(struct mevent *mevp)
1814c87aefeSPatrick Mooney {
182*154972afSPatrick Mooney 	return (mevp->me_state);
1834c87aefeSPatrick Mooney }
1844c87aefeSPatrick Mooney 
1854c87aefeSPatrick Mooney static int
1864c87aefeSPatrick Mooney mevent_kq_fflags(struct mevent *mevp)
1874c87aefeSPatrick Mooney {
1884c87aefeSPatrick Mooney 	/* XXX nothing yet, perhaps EV_EOF for reads ? */
1894c87aefeSPatrick Mooney 	return (0);
1904c87aefeSPatrick Mooney }
1914c87aefeSPatrick Mooney 
1924c87aefeSPatrick Mooney static int
1934c87aefeSPatrick Mooney mevent_build(int mfd, struct kevent *kev)
1944c87aefeSPatrick Mooney {
1954c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
1964c87aefeSPatrick Mooney 	int i;
1974c87aefeSPatrick Mooney 
1984c87aefeSPatrick Mooney 	i = 0;
1994c87aefeSPatrick Mooney 
2004c87aefeSPatrick Mooney 	mevent_qlock();
2014c87aefeSPatrick Mooney 
2024c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
2034c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
2044c87aefeSPatrick Mooney 			/*
2054c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
2064c87aefeSPatrick Mooney 			 * event
2074c87aefeSPatrick Mooney 			 */
2084c87aefeSPatrick Mooney 			close(mevp->me_fd);
2094c87aefeSPatrick Mooney 		} else {
2104c87aefeSPatrick Mooney 			if (mevp->me_type == EVF_TIMER) {
2114c87aefeSPatrick Mooney 				kev[i].ident = mevp->me_timid;
2124c87aefeSPatrick Mooney 				kev[i].data = mevp->me_msecs;
2134c87aefeSPatrick Mooney 			} else {
2144c87aefeSPatrick Mooney 				kev[i].ident = mevp->me_fd;
2154c87aefeSPatrick Mooney 				kev[i].data = 0;
2164c87aefeSPatrick Mooney 			}
2174c87aefeSPatrick Mooney 			kev[i].filter = mevent_kq_filter(mevp);
2184c87aefeSPatrick Mooney 			kev[i].flags = mevent_kq_flags(mevp);
2194c87aefeSPatrick Mooney 			kev[i].fflags = mevent_kq_fflags(mevp);
2204c87aefeSPatrick Mooney 			kev[i].udata = mevp;
2214c87aefeSPatrick Mooney 			i++;
2224c87aefeSPatrick Mooney 		}
2234c87aefeSPatrick Mooney 
2244c87aefeSPatrick Mooney 		mevp->me_cq = 0;
2254c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
2264c87aefeSPatrick Mooney 
227*154972afSPatrick Mooney 		if (mevp->me_state & EV_DELETE) {
2284c87aefeSPatrick Mooney 			free(mevp);
2294c87aefeSPatrick Mooney 		} else {
230*154972afSPatrick Mooney 			/*
231*154972afSPatrick Mooney 			 * We need to add the event only once, so we can
232*154972afSPatrick Mooney 			 * reset the EV_ADD bit after it has been propagated
233*154972afSPatrick Mooney 			 * to the kevent() arguments the first time.
234*154972afSPatrick Mooney 			 */
235*154972afSPatrick Mooney 			mevp->me_state &= ~EV_ADD;
2364c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
2374c87aefeSPatrick Mooney 		}
2384c87aefeSPatrick Mooney 
2394c87aefeSPatrick Mooney 		assert(i < MEVENT_MAX);
2404c87aefeSPatrick Mooney 	}
2414c87aefeSPatrick Mooney 
2424c87aefeSPatrick Mooney 	mevent_qunlock();
2434c87aefeSPatrick Mooney 
2444c87aefeSPatrick Mooney 	return (i);
2454c87aefeSPatrick Mooney }
2464c87aefeSPatrick Mooney 
2474c87aefeSPatrick Mooney static void
2484c87aefeSPatrick Mooney mevent_handle(struct kevent *kev, int numev)
2494c87aefeSPatrick Mooney {
2504c87aefeSPatrick Mooney 	struct mevent *mevp;
2514c87aefeSPatrick Mooney 	int i;
2524c87aefeSPatrick Mooney 
2534c87aefeSPatrick Mooney 	for (i = 0; i < numev; i++) {
2544c87aefeSPatrick Mooney 		mevp = kev[i].udata;
2554c87aefeSPatrick Mooney 
2564c87aefeSPatrick Mooney 		/* XXX check for EV_ERROR ? */
2574c87aefeSPatrick Mooney 
2584c87aefeSPatrick Mooney 		(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
2594c87aefeSPatrick Mooney 	}
2604c87aefeSPatrick Mooney }
2614c87aefeSPatrick Mooney 
2624c87aefeSPatrick Mooney #else /* __FreeBSD__ */
2634c87aefeSPatrick Mooney 
264*154972afSPatrick Mooney static boolean_t
265*154972afSPatrick Mooney mevent_clarify_state(struct mevent *mevp)
266*154972afSPatrick Mooney {
267*154972afSPatrick Mooney 	const int state = mevp->me_state;
268*154972afSPatrick Mooney 
269*154972afSPatrick Mooney 	if ((state & EV_DELETE) != 0) {
270*154972afSPatrick Mooney 		/* All other intents are overriden by delete. */
271*154972afSPatrick Mooney 		mevp->me_state = EV_DELETE;
272*154972afSPatrick Mooney 		return (B_TRUE);
273*154972afSPatrick Mooney 	}
274*154972afSPatrick Mooney 
275*154972afSPatrick Mooney 	/*
276*154972afSPatrick Mooney 	 * Without a distinction between EV_ADD and EV_ENABLE in our emulation,
277*154972afSPatrick Mooney 	 * handling the add-disabled case means eliding the portfs operation
278*154972afSPatrick Mooney 	 * when both flags are present.
279*154972afSPatrick Mooney 	 *
280*154972afSPatrick Mooney 	 * This is not a concern for subsequent enable/disable operations, as
281*154972afSPatrick Mooney 	 * mevent_update() toggles the flags properly so they are not left in
282*154972afSPatrick Mooney 	 * conflict.
283*154972afSPatrick Mooney 	 */
284*154972afSPatrick Mooney 	if (state == (EV_ENABLE|EV_DISABLE)) {
285*154972afSPatrick Mooney 		mevp->me_state = EV_DISABLE;
286*154972afSPatrick Mooney 		return (B_FALSE);
287*154972afSPatrick Mooney 	}
288*154972afSPatrick Mooney 
289*154972afSPatrick Mooney 	return (B_TRUE);
290*154972afSPatrick Mooney }
291*154972afSPatrick Mooney 
2924c87aefeSPatrick Mooney static void
2934c87aefeSPatrick Mooney mevent_update_one(struct mevent *mevp)
2944c87aefeSPatrick Mooney {
2954c87aefeSPatrick Mooney 	int portfd = mevp->me_notify.portnfy_port;
2964c87aefeSPatrick Mooney 
2974c87aefeSPatrick Mooney 	switch (mevp->me_type) {
2984c87aefeSPatrick Mooney 	case EVF_READ:
2994c87aefeSPatrick Mooney 	case EVF_WRITE:
3004c87aefeSPatrick Mooney 		mevp->me_auto_requeue = B_FALSE;
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney 		switch (mevp->me_state) {
303*154972afSPatrick Mooney 		case EV_ENABLE:
3044c87aefeSPatrick Mooney 		{
3054c87aefeSPatrick Mooney 			int events;
3064c87aefeSPatrick Mooney 
3074c87aefeSPatrick Mooney 			events = (mevp->me_type == EVF_READ) ? POLLIN : POLLOUT;
3084c87aefeSPatrick Mooney 
3094c87aefeSPatrick Mooney 			if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd,
3104c87aefeSPatrick Mooney 			    events, mevp) != 0) {
3114c87aefeSPatrick Mooney 				(void) fprintf(stderr,
3124c87aefeSPatrick Mooney 				    "port_associate fd %d %p failed: %s\n",
3134c87aefeSPatrick Mooney 				    mevp->me_fd, mevp, strerror(errno));
3144c87aefeSPatrick Mooney 			}
3154c87aefeSPatrick Mooney 			return;
3164c87aefeSPatrick Mooney 		}
317*154972afSPatrick Mooney 		case EV_DISABLE:
318*154972afSPatrick Mooney 		case EV_DELETE:
3194c87aefeSPatrick Mooney 			/*
3204c87aefeSPatrick Mooney 			 * A disable that comes in while an event is being
3214c87aefeSPatrick Mooney 			 * handled will result in an ENOENT.
3224c87aefeSPatrick Mooney 			 */
3234c87aefeSPatrick Mooney 			if (port_dissociate(portfd, PORT_SOURCE_FD,
3244c87aefeSPatrick Mooney 			    mevp->me_fd) != 0 && errno != ENOENT) {
3254c87aefeSPatrick Mooney 				(void) fprintf(stderr, "port_dissociate "
3264c87aefeSPatrick Mooney 				    "portfd %d fd %d mevp %p failed: %s\n",
3274c87aefeSPatrick Mooney 				    portfd, mevp->me_fd, mevp, strerror(errno));
3284c87aefeSPatrick Mooney 			}
3294c87aefeSPatrick Mooney 			return;
3304c87aefeSPatrick Mooney 		default:
3314c87aefeSPatrick Mooney 			goto abort;
3324c87aefeSPatrick Mooney 		}
3334c87aefeSPatrick Mooney 
3344c87aefeSPatrick Mooney 	case EVF_TIMER:
3354c87aefeSPatrick Mooney 		mevp->me_auto_requeue = B_TRUE;
3364c87aefeSPatrick Mooney 
3374c87aefeSPatrick Mooney 		switch (mevp->me_state) {
338*154972afSPatrick Mooney 		case EV_ENABLE:
3394c87aefeSPatrick Mooney 		{
3404c87aefeSPatrick Mooney 			struct itimerspec it = { 0 };
3414c87aefeSPatrick Mooney 
3424c87aefeSPatrick Mooney 			mevp->me_sigev.sigev_notify = SIGEV_PORT;
3434c87aefeSPatrick Mooney 			mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify;
3444c87aefeSPatrick Mooney 
3454c87aefeSPatrick Mooney 			if (timer_create(CLOCK_REALTIME, &mevp->me_sigev,
3464c87aefeSPatrick Mooney 			    &mevp->me_timid) != 0) {
3474c87aefeSPatrick Mooney 				(void) fprintf(stderr,
3484c87aefeSPatrick Mooney 				    "timer_create failed: %s", strerror(errno));
3494c87aefeSPatrick Mooney 				return;
3504c87aefeSPatrick Mooney 			}
3514c87aefeSPatrick Mooney 
3524c87aefeSPatrick Mooney 			/* The first timeout */
3534c87aefeSPatrick Mooney 			it.it_value.tv_sec = mevp->me_msecs / MILLISEC;
3544c87aefeSPatrick Mooney 			it.it_value.tv_nsec =
3554c87aefeSPatrick Mooney 				MSEC2NSEC(mevp->me_msecs % MILLISEC);
3564c87aefeSPatrick Mooney 			/* Repeat at the same interval */
3574c87aefeSPatrick Mooney 			it.it_interval = it.it_value;
3584c87aefeSPatrick Mooney 
3594c87aefeSPatrick Mooney 			if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) {
3604c87aefeSPatrick Mooney 				(void) fprintf(stderr, "timer_settime failed: "
3614c87aefeSPatrick Mooney 				    "%s", strerror(errno));
3624c87aefeSPatrick Mooney 			}
3634c87aefeSPatrick Mooney 			return;
3644c87aefeSPatrick Mooney 		}
365*154972afSPatrick Mooney 		case EV_DISABLE:
366*154972afSPatrick Mooney 		case EV_DELETE:
3674c87aefeSPatrick Mooney 			if (timer_delete(mevp->me_timid) != 0) {
3684c87aefeSPatrick Mooney 				(void) fprintf(stderr, "timer_delete failed: "
3694c87aefeSPatrick Mooney 				    "%s", strerror(errno));
3704c87aefeSPatrick Mooney 			}
3714c87aefeSPatrick Mooney 			return;
3724c87aefeSPatrick Mooney 		default:
3734c87aefeSPatrick Mooney 			goto abort;
3744c87aefeSPatrick Mooney 		}
3754c87aefeSPatrick Mooney 	default:
3764c87aefeSPatrick Mooney 		/* EVF_SIGNAL not yet implemented. */
3774c87aefeSPatrick Mooney 		goto abort;
3784c87aefeSPatrick Mooney 	}
3794c87aefeSPatrick Mooney 
3804c87aefeSPatrick Mooney abort:
3814c87aefeSPatrick Mooney 	(void) fprintf(stderr, "%s: unhandled type %d state %d\n", __func__,
3824c87aefeSPatrick Mooney 	    mevp->me_type, mevp->me_state);
3834c87aefeSPatrick Mooney 	abort();
3844c87aefeSPatrick Mooney }
3854c87aefeSPatrick Mooney 
3864c87aefeSPatrick Mooney static void
3874c87aefeSPatrick Mooney mevent_update_pending(int portfd)
3884c87aefeSPatrick Mooney {
3894c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
3904c87aefeSPatrick Mooney 
3914c87aefeSPatrick Mooney 	mevent_qlock();
3924c87aefeSPatrick Mooney 
3934c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
3944c87aefeSPatrick Mooney 		mevp->me_notify.portnfy_port = portfd;
3954c87aefeSPatrick Mooney 		mevp->me_notify.portnfy_user = mevp;
3964c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
3974c87aefeSPatrick Mooney 			/*
3984c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
3994c87aefeSPatrick Mooney 			 * event
4004c87aefeSPatrick Mooney 			 */
4014c87aefeSPatrick Mooney 			(void) close(mevp->me_fd);
4024c87aefeSPatrick Mooney 			mevp->me_fd = -1;
4034c87aefeSPatrick Mooney 		} else {
404*154972afSPatrick Mooney 			if (mevent_clarify_state(mevp)) {
405*154972afSPatrick Mooney 				mevent_update_one(mevp);
406*154972afSPatrick Mooney 			}
4074c87aefeSPatrick Mooney 		}
4084c87aefeSPatrick Mooney 
4094c87aefeSPatrick Mooney 		mevp->me_cq = 0;
4104c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
4114c87aefeSPatrick Mooney 
412*154972afSPatrick Mooney 		if (mevp->me_state & EV_DELETE) {
4134c87aefeSPatrick Mooney 			free(mevp);
4144c87aefeSPatrick Mooney 		} else {
4154c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
4164c87aefeSPatrick Mooney 		}
4174c87aefeSPatrick Mooney 	}
4184c87aefeSPatrick Mooney 
4194c87aefeSPatrick Mooney 	mevent_qunlock();
4204c87aefeSPatrick Mooney }
4214c87aefeSPatrick Mooney 
4224c87aefeSPatrick Mooney static void
4234c87aefeSPatrick Mooney mevent_handle_pe(port_event_t *pe)
4244c87aefeSPatrick Mooney {
4254c87aefeSPatrick Mooney 	struct mevent *mevp = pe->portev_user;
4264c87aefeSPatrick Mooney 
4274c87aefeSPatrick Mooney 	mevent_qunlock();
4284c87aefeSPatrick Mooney 
4294c87aefeSPatrick Mooney 	(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
4304c87aefeSPatrick Mooney 
4314c87aefeSPatrick Mooney 	mevent_qlock();
4324c87aefeSPatrick Mooney 	if (!mevp->me_cq && !mevp->me_auto_requeue) {
4334c87aefeSPatrick Mooney 		mevent_update_one(mevp);
4344c87aefeSPatrick Mooney 	}
4354c87aefeSPatrick Mooney 	mevent_qunlock();
4364c87aefeSPatrick Mooney }
4374c87aefeSPatrick Mooney #endif
4384c87aefeSPatrick Mooney 
439*154972afSPatrick Mooney static struct mevent *
440*154972afSPatrick Mooney mevent_add_state(int tfd, enum ev_type type,
441*154972afSPatrick Mooney 	   void (*func)(int, enum ev_type, void *), void *param,
442*154972afSPatrick Mooney 	   int state)
4434c87aefeSPatrick Mooney {
4444c87aefeSPatrick Mooney 	struct mevent *lp, *mevp;
4454c87aefeSPatrick Mooney 
4464c87aefeSPatrick Mooney 	if (tfd < 0 || func == NULL) {
4474c87aefeSPatrick Mooney 		return (NULL);
4484c87aefeSPatrick Mooney 	}
4494c87aefeSPatrick Mooney 
4504c87aefeSPatrick Mooney 	mevp = NULL;
4514c87aefeSPatrick Mooney 
4524c87aefeSPatrick Mooney 	mevent_qlock();
4534c87aefeSPatrick Mooney 
4544c87aefeSPatrick Mooney 	/*
4554c87aefeSPatrick Mooney 	 * Verify that the fd/type tuple is not present in any list
4564c87aefeSPatrick Mooney 	 */
4574c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &global_head, me_list) {
4584c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
4594c87aefeSPatrick Mooney 		    lp->me_type == type) {
4604c87aefeSPatrick Mooney 			goto exit;
4614c87aefeSPatrick Mooney 		}
4624c87aefeSPatrick Mooney 	}
4634c87aefeSPatrick Mooney 
4644c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &change_head, me_list) {
4654c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
4664c87aefeSPatrick Mooney 		    lp->me_type == type) {
4674c87aefeSPatrick Mooney 			goto exit;
4684c87aefeSPatrick Mooney 		}
4694c87aefeSPatrick Mooney 	}
4704c87aefeSPatrick Mooney 
4714c87aefeSPatrick Mooney 	/*
4724c87aefeSPatrick Mooney 	 * Allocate an entry, populate it, and add it to the change list.
4734c87aefeSPatrick Mooney 	 */
4744c87aefeSPatrick Mooney 	mevp = calloc(1, sizeof(struct mevent));
4754c87aefeSPatrick Mooney 	if (mevp == NULL) {
4764c87aefeSPatrick Mooney 		goto exit;
4774c87aefeSPatrick Mooney 	}
4784c87aefeSPatrick Mooney 
4794c87aefeSPatrick Mooney 	if (type == EVF_TIMER) {
4804c87aefeSPatrick Mooney 		mevp->me_msecs = tfd;
4814c87aefeSPatrick Mooney 		mevp->me_timid = mevent_timid++;
4824c87aefeSPatrick Mooney 	} else
4834c87aefeSPatrick Mooney 		mevp->me_fd = tfd;
4844c87aefeSPatrick Mooney 	mevp->me_type = type;
4854c87aefeSPatrick Mooney 	mevp->me_func = func;
4864c87aefeSPatrick Mooney 	mevp->me_param = param;
4874c87aefeSPatrick Mooney 
4884c87aefeSPatrick Mooney 	LIST_INSERT_HEAD(&change_head, mevp, me_list);
4894c87aefeSPatrick Mooney 	mevp->me_cq = 1;
490*154972afSPatrick Mooney 	mevp->me_state = state;
4914c87aefeSPatrick Mooney 	mevent_notify();
4924c87aefeSPatrick Mooney 
4934c87aefeSPatrick Mooney exit:
4944c87aefeSPatrick Mooney 	mevent_qunlock();
4954c87aefeSPatrick Mooney 
4964c87aefeSPatrick Mooney 	return (mevp);
4974c87aefeSPatrick Mooney }
4984c87aefeSPatrick Mooney 
499*154972afSPatrick Mooney struct mevent *
500*154972afSPatrick Mooney mevent_add(int tfd, enum ev_type type,
501*154972afSPatrick Mooney 	   void (*func)(int, enum ev_type, void *), void *param)
502*154972afSPatrick Mooney {
503*154972afSPatrick Mooney 
504*154972afSPatrick Mooney 	return (mevent_add_state(tfd, type, func, param, EV_ADD));
505*154972afSPatrick Mooney }
506*154972afSPatrick Mooney 
507*154972afSPatrick Mooney struct mevent *
508*154972afSPatrick Mooney mevent_add_disabled(int tfd, enum ev_type type,
509*154972afSPatrick Mooney 		    void (*func)(int, enum ev_type, void *), void *param)
510*154972afSPatrick Mooney {
511*154972afSPatrick Mooney 
512*154972afSPatrick Mooney 	return (mevent_add_state(tfd, type, func, param, EV_ADD | EV_DISABLE));
513*154972afSPatrick Mooney }
514*154972afSPatrick Mooney 
5154c87aefeSPatrick Mooney static int
516*154972afSPatrick Mooney mevent_update(struct mevent *evp, bool enable)
5174c87aefeSPatrick Mooney {
518*154972afSPatrick Mooney 	int newstate;
519*154972afSPatrick Mooney 
520*154972afSPatrick Mooney 	mevent_qlock();
521*154972afSPatrick Mooney 
5224c87aefeSPatrick Mooney 	/*
5234c87aefeSPatrick Mooney 	 * It's not possible to enable/disable a deleted event
5244c87aefeSPatrick Mooney 	 */
525*154972afSPatrick Mooney 	assert((evp->me_state & EV_DELETE) == 0);
526*154972afSPatrick Mooney 
527*154972afSPatrick Mooney 	newstate = evp->me_state;
528*154972afSPatrick Mooney 	if (enable) {
529*154972afSPatrick Mooney 		newstate |= EV_ENABLE;
530*154972afSPatrick Mooney 		newstate &= ~EV_DISABLE;
531*154972afSPatrick Mooney 	} else {
532*154972afSPatrick Mooney 		newstate |= EV_DISABLE;
533*154972afSPatrick Mooney 		newstate &= ~EV_ENABLE;
534*154972afSPatrick Mooney 	}
5354c87aefeSPatrick Mooney 
5364c87aefeSPatrick Mooney 	/*
5374c87aefeSPatrick Mooney 	 * No update needed if state isn't changing
5384c87aefeSPatrick Mooney 	 */
539*154972afSPatrick Mooney 	if (evp->me_state != newstate) {
540*154972afSPatrick Mooney 		evp->me_state = newstate;
541*154972afSPatrick Mooney 
542*154972afSPatrick Mooney 		/*
543*154972afSPatrick Mooney 		 * Place the entry onto the changed list if not
544*154972afSPatrick Mooney 		 * already there.
545*154972afSPatrick Mooney 		 */
546*154972afSPatrick Mooney 		if (evp->me_cq == 0) {
547*154972afSPatrick Mooney 			evp->me_cq = 1;
548*154972afSPatrick Mooney 			LIST_REMOVE(evp, me_list);
549*154972afSPatrick Mooney 			LIST_INSERT_HEAD(&change_head, evp, me_list);
550*154972afSPatrick Mooney 			mevent_notify();
551*154972afSPatrick Mooney 		}
5524c87aefeSPatrick Mooney 	}
5534c87aefeSPatrick Mooney 
5544c87aefeSPatrick Mooney 	mevent_qunlock();
5554c87aefeSPatrick Mooney 
5564c87aefeSPatrick Mooney 	return (0);
5574c87aefeSPatrick Mooney }
5584c87aefeSPatrick Mooney 
5594c87aefeSPatrick Mooney int
5604c87aefeSPatrick Mooney mevent_enable(struct mevent *evp)
5614c87aefeSPatrick Mooney {
5624c87aefeSPatrick Mooney 
563*154972afSPatrick Mooney 	return (mevent_update(evp, true));
5644c87aefeSPatrick Mooney }
5654c87aefeSPatrick Mooney 
5664c87aefeSPatrick Mooney int
5674c87aefeSPatrick Mooney mevent_disable(struct mevent *evp)
5684c87aefeSPatrick Mooney {
5694c87aefeSPatrick Mooney 
570*154972afSPatrick Mooney 	return (mevent_update(evp, false));
5714c87aefeSPatrick Mooney }
5724c87aefeSPatrick Mooney 
5734c87aefeSPatrick Mooney static int
5744c87aefeSPatrick Mooney mevent_delete_event(struct mevent *evp, int closefd)
5754c87aefeSPatrick Mooney {
5764c87aefeSPatrick Mooney 	mevent_qlock();
5774c87aefeSPatrick Mooney 
5784c87aefeSPatrick Mooney 	/*
5794c87aefeSPatrick Mooney          * Place the entry onto the changed list if not already there, and
5804c87aefeSPatrick Mooney 	 * mark as to be deleted.
5814c87aefeSPatrick Mooney          */
5824c87aefeSPatrick Mooney         if (evp->me_cq == 0) {
5834c87aefeSPatrick Mooney 		evp->me_cq = 1;
5844c87aefeSPatrick Mooney 		LIST_REMOVE(evp, me_list);
5854c87aefeSPatrick Mooney 		LIST_INSERT_HEAD(&change_head, evp, me_list);
5864c87aefeSPatrick Mooney 		mevent_notify();
5874c87aefeSPatrick Mooney         }
588*154972afSPatrick Mooney 	evp->me_state = EV_DELETE;
5894c87aefeSPatrick Mooney 
5904c87aefeSPatrick Mooney 	if (closefd)
5914c87aefeSPatrick Mooney 		evp->me_closefd = 1;
5924c87aefeSPatrick Mooney 
5934c87aefeSPatrick Mooney 	mevent_qunlock();
5944c87aefeSPatrick Mooney 
5954c87aefeSPatrick Mooney 	return (0);
5964c87aefeSPatrick Mooney }
5974c87aefeSPatrick Mooney 
5984c87aefeSPatrick Mooney int
5994c87aefeSPatrick Mooney mevent_delete(struct mevent *evp)
6004c87aefeSPatrick Mooney {
6014c87aefeSPatrick Mooney 
6024c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 0));
6034c87aefeSPatrick Mooney }
6044c87aefeSPatrick Mooney 
6054c87aefeSPatrick Mooney int
6064c87aefeSPatrick Mooney mevent_delete_close(struct mevent *evp)
6074c87aefeSPatrick Mooney {
6084c87aefeSPatrick Mooney 
6094c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 1));
6104c87aefeSPatrick Mooney }
6114c87aefeSPatrick Mooney 
6124c87aefeSPatrick Mooney static void
6134c87aefeSPatrick Mooney mevent_set_name(void)
6144c87aefeSPatrick Mooney {
6154c87aefeSPatrick Mooney 
6164c87aefeSPatrick Mooney 	pthread_set_name_np(mevent_tid, "mevent");
6174c87aefeSPatrick Mooney }
6184c87aefeSPatrick Mooney 
6194c87aefeSPatrick Mooney void
6204c87aefeSPatrick Mooney mevent_dispatch(void)
6214c87aefeSPatrick Mooney {
6224c87aefeSPatrick Mooney #ifdef __FreeBSD__
6234c87aefeSPatrick Mooney 	struct kevent changelist[MEVENT_MAX];
6244c87aefeSPatrick Mooney 	struct kevent eventlist[MEVENT_MAX];
6254c87aefeSPatrick Mooney 	struct mevent *pipev;
6264c87aefeSPatrick Mooney 	int mfd;
6274c87aefeSPatrick Mooney 	int numev;
6284c87aefeSPatrick Mooney #else
6294c87aefeSPatrick Mooney 	struct mevent *pipev;
6304c87aefeSPatrick Mooney 	int portfd;
6314c87aefeSPatrick Mooney #endif
6324c87aefeSPatrick Mooney 	int ret;
6334c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
6344c87aefeSPatrick Mooney 	cap_rights_t rights;
6354c87aefeSPatrick Mooney #endif
6364c87aefeSPatrick Mooney 
6374c87aefeSPatrick Mooney 	mevent_tid = pthread_self();
6384c87aefeSPatrick Mooney 	mevent_set_name();
6394c87aefeSPatrick Mooney 
6404c87aefeSPatrick Mooney #ifdef __FreeBSD__
6414c87aefeSPatrick Mooney 	mfd = kqueue();
6424c87aefeSPatrick Mooney 	assert(mfd > 0);
6434c87aefeSPatrick Mooney #else
6444c87aefeSPatrick Mooney 	portfd = port_create();
6454c87aefeSPatrick Mooney 	assert(portfd >= 0);
6464c87aefeSPatrick Mooney #endif
6474c87aefeSPatrick Mooney 
6484c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
6494c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_KQUEUE);
6504c87aefeSPatrick Mooney 	if (caph_rights_limit(mfd, &rights) == -1)
6514c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
6524c87aefeSPatrick Mooney #endif
6534c87aefeSPatrick Mooney 
6544c87aefeSPatrick Mooney 	/*
6554c87aefeSPatrick Mooney 	 * Open the pipe that will be used for other threads to force
6564c87aefeSPatrick Mooney 	 * the blocking kqueue call to exit by writing to it. Set the
6574c87aefeSPatrick Mooney 	 * descriptor to non-blocking.
6584c87aefeSPatrick Mooney 	 */
6594c87aefeSPatrick Mooney 	ret = pipe(mevent_pipefd);
6604c87aefeSPatrick Mooney 	if (ret < 0) {
6614c87aefeSPatrick Mooney 		perror("pipe");
6624c87aefeSPatrick Mooney 		exit(0);
6634c87aefeSPatrick Mooney 	}
6644c87aefeSPatrick Mooney 
6654c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
6664c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
6674c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[0], &rights) == -1)
6684c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
6694c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[1], &rights) == -1)
6704c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
6714c87aefeSPatrick Mooney #endif
6724c87aefeSPatrick Mooney 
6734c87aefeSPatrick Mooney 	/*
6744c87aefeSPatrick Mooney 	 * Add internal event handler for the pipe write fd
6754c87aefeSPatrick Mooney 	 */
6764c87aefeSPatrick Mooney 	pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL);
6774c87aefeSPatrick Mooney 	assert(pipev != NULL);
6784c87aefeSPatrick Mooney 
6794c87aefeSPatrick Mooney 	for (;;) {
6804c87aefeSPatrick Mooney #ifdef __FreeBSD__
6814c87aefeSPatrick Mooney 		/*
6824c87aefeSPatrick Mooney 		 * Build changelist if required.
6834c87aefeSPatrick Mooney 		 * XXX the changelist can be put into the blocking call
6844c87aefeSPatrick Mooney 		 * to eliminate the extra syscall. Currently better for
6854c87aefeSPatrick Mooney 		 * debug.
6864c87aefeSPatrick Mooney 		 */
6874c87aefeSPatrick Mooney 		numev = mevent_build(mfd, changelist);
6884c87aefeSPatrick Mooney 		if (numev) {
6894c87aefeSPatrick Mooney 			ret = kevent(mfd, changelist, numev, NULL, 0, NULL);
6904c87aefeSPatrick Mooney 			if (ret == -1) {
6914c87aefeSPatrick Mooney 				perror("Error return from kevent change");
6924c87aefeSPatrick Mooney 			}
6934c87aefeSPatrick Mooney 		}
6944c87aefeSPatrick Mooney 
6954c87aefeSPatrick Mooney 		/*
6964c87aefeSPatrick Mooney 		 * Block awaiting events
6974c87aefeSPatrick Mooney 		 */
6984c87aefeSPatrick Mooney 		ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);
6994c87aefeSPatrick Mooney 		if (ret == -1 && errno != EINTR) {
7004c87aefeSPatrick Mooney 			perror("Error return from kevent monitor");
7014c87aefeSPatrick Mooney 		}
7024c87aefeSPatrick Mooney 
7034c87aefeSPatrick Mooney 		/*
7044c87aefeSPatrick Mooney 		 * Handle reported events
7054c87aefeSPatrick Mooney 		 */
7064c87aefeSPatrick Mooney 		mevent_handle(eventlist, ret);
7074c87aefeSPatrick Mooney 
7084c87aefeSPatrick Mooney #else /* __FreeBSD__ */
7094c87aefeSPatrick Mooney 		port_event_t pev;
7104c87aefeSPatrick Mooney 
7114c87aefeSPatrick Mooney 		/* Handle any pending updates */
7124c87aefeSPatrick Mooney 		mevent_update_pending(portfd);
7134c87aefeSPatrick Mooney 
7144c87aefeSPatrick Mooney 		/* Block awaiting events */
7154c87aefeSPatrick Mooney 		ret = port_get(portfd, &pev, NULL);
7164c87aefeSPatrick Mooney 		if (ret != 0 && errno != EINTR) {
7174c87aefeSPatrick Mooney 			perror("Error return from port_get");
7184c87aefeSPatrick Mooney 			continue;
7194c87aefeSPatrick Mooney 		}
7204c87aefeSPatrick Mooney 
7214c87aefeSPatrick Mooney 		/* Handle reported event */
7224c87aefeSPatrick Mooney 		mevent_handle_pe(&pev);
7234c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
7244c87aefeSPatrick Mooney 	}
7254c87aefeSPatrick Mooney }
726