xref: /illumos-gate/usr/src/cmd/bhyve/mevent.c (revision 32640292)
14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
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 
294c87aefeSPatrick Mooney /*
304c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
31251becc8SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
324c87aefeSPatrick Mooney  */
334c87aefeSPatrick Mooney 
344c87aefeSPatrick Mooney /*
356dc98349SAndy Fiddaman  * Micro event library for FreeBSD, designed for a single i/o thread
364c87aefeSPatrick Mooney  * using kqueue, and having events be persistent by default.
374c87aefeSPatrick Mooney  */
384c87aefeSPatrick Mooney 
394c87aefeSPatrick Mooney #include <sys/cdefs.h>
404c87aefeSPatrick Mooney 
414c87aefeSPatrick Mooney #include <assert.h>
424c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
434c87aefeSPatrick Mooney #include <capsicum_helpers.h>
444c87aefeSPatrick Mooney #endif
454c87aefeSPatrick Mooney #include <err.h>
464c87aefeSPatrick Mooney #include <errno.h>
47154972afSPatrick Mooney #include <stdbool.h>
484c87aefeSPatrick Mooney #include <stdlib.h>
494c87aefeSPatrick Mooney #include <stdio.h>
504c87aefeSPatrick Mooney #include <string.h>
514c87aefeSPatrick Mooney #include <sysexits.h>
524c87aefeSPatrick Mooney #include <unistd.h>
534c87aefeSPatrick Mooney 
544c87aefeSPatrick Mooney #include <sys/types.h>
554c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
564c87aefeSPatrick Mooney #include <sys/capsicum.h>
574c87aefeSPatrick Mooney #endif
584c87aefeSPatrick Mooney #ifdef __FreeBSD__
594c87aefeSPatrick Mooney #include <sys/event.h>
604c87aefeSPatrick Mooney #else
614c87aefeSPatrick Mooney #include <port.h>
624c87aefeSPatrick Mooney #include <sys/poll.h>
634c87aefeSPatrick Mooney #include <sys/siginfo.h>
644c87aefeSPatrick Mooney #include <sys/queue.h>
65154972afSPatrick Mooney #include <sys/debug.h>
66e8d71297SAndy Fiddaman #include <sys/stat.h>
674c87aefeSPatrick Mooney #endif
684c87aefeSPatrick Mooney #include <sys/time.h>
694c87aefeSPatrick Mooney 
704c87aefeSPatrick Mooney #include <pthread.h>
714c87aefeSPatrick Mooney #include <pthread_np.h>
724c87aefeSPatrick Mooney 
734c87aefeSPatrick Mooney #include "mevent.h"
744c87aefeSPatrick Mooney 
754c87aefeSPatrick Mooney #define	MEVENT_MAX	64
764c87aefeSPatrick Mooney 
77154972afSPatrick Mooney #ifndef __FreeBSD__
78154972afSPatrick Mooney #define	EV_ENABLE	0x01
79154972afSPatrick Mooney #define	EV_ADD		EV_ENABLE
80154972afSPatrick Mooney #define	EV_DISABLE	0x02
81154972afSPatrick Mooney #define	EV_DELETE	0x04
82251becc8SAndy Fiddaman 
83251becc8SAndy Fiddaman static int mevent_file_poll_interval_ms = 5000;
84154972afSPatrick Mooney #endif
854c87aefeSPatrick Mooney 
864c87aefeSPatrick Mooney static pthread_t mevent_tid;
87b0de25cbSAndy Fiddaman static pthread_once_t mevent_once = PTHREAD_ONCE_INIT;
88251becc8SAndy Fiddaman #ifdef __FreeBSD__
894c87aefeSPatrick Mooney static int mevent_timid = 43;
90251becc8SAndy Fiddaman #endif
914c87aefeSPatrick Mooney static int mevent_pipefd[2];
92b0de25cbSAndy Fiddaman static int mfd;
934c87aefeSPatrick Mooney static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
944c87aefeSPatrick Mooney 
954c87aefeSPatrick Mooney struct mevent {
964c87aefeSPatrick Mooney 	void	(*me_func)(int, enum ev_type, void *);
974c87aefeSPatrick Mooney #define me_msecs me_fd
984c87aefeSPatrick Mooney 	int	me_fd;
994c87aefeSPatrick Mooney #ifdef __FreeBSD__
1004c87aefeSPatrick Mooney 	int	me_timid;
1014c87aefeSPatrick Mooney #else
1024c87aefeSPatrick Mooney 	timer_t me_timid;
1034c87aefeSPatrick Mooney #endif
1044c87aefeSPatrick Mooney 	enum ev_type me_type;
1054c87aefeSPatrick Mooney 	void    *me_param;
1064c87aefeSPatrick Mooney 	int	me_cq;
107154972afSPatrick Mooney 	int	me_state; /* Desired kevent flags. */
1084c87aefeSPatrick Mooney 	int	me_closefd;
109b0de25cbSAndy Fiddaman 	int	me_fflags;
1104c87aefeSPatrick Mooney #ifndef __FreeBSD__
1114c87aefeSPatrick Mooney 	port_notify_t	me_notify;
1124c87aefeSPatrick Mooney 	struct sigevent	me_sigev;
1134c87aefeSPatrick Mooney 	boolean_t	me_auto_requeue;
114251becc8SAndy Fiddaman 	struct {
115251becc8SAndy Fiddaman 		int	mp_fd;
116251becc8SAndy Fiddaman 		off_t	mp_size;
117251becc8SAndy Fiddaman 		void	(*mp_func)(int, enum ev_type, void *);
118251becc8SAndy Fiddaman 		void    *mp_param;
119251becc8SAndy Fiddaman 	} me_poll;
1204c87aefeSPatrick Mooney #endif
1214c87aefeSPatrick Mooney 	LIST_ENTRY(mevent) me_list;
1224c87aefeSPatrick Mooney };
1234c87aefeSPatrick Mooney 
1244c87aefeSPatrick Mooney static LIST_HEAD(listhead, mevent) global_head, change_head;
1254c87aefeSPatrick Mooney 
1264c87aefeSPatrick Mooney static void
1274c87aefeSPatrick Mooney mevent_qlock(void)
1284c87aefeSPatrick Mooney {
1294c87aefeSPatrick Mooney 	pthread_mutex_lock(&mevent_lmutex);
1304c87aefeSPatrick Mooney }
1314c87aefeSPatrick Mooney 
1324c87aefeSPatrick Mooney static void
1334c87aefeSPatrick Mooney mevent_qunlock(void)
1344c87aefeSPatrick Mooney {
1354c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mevent_lmutex);
1364c87aefeSPatrick Mooney }
1374c87aefeSPatrick Mooney 
1384c87aefeSPatrick Mooney static void
13959d65d31SAndy Fiddaman mevent_pipe_read(int fd, enum ev_type type __unused, void *param __unused)
1404c87aefeSPatrick Mooney {
1414c87aefeSPatrick Mooney 	char buf[MEVENT_MAX];
1424c87aefeSPatrick Mooney 	int status;
1434c87aefeSPatrick Mooney 
1444c87aefeSPatrick Mooney 	/*
1454c87aefeSPatrick Mooney 	 * Drain the pipe read side. The fd is non-blocking so this is
1464c87aefeSPatrick Mooney 	 * safe to do.
1474c87aefeSPatrick Mooney 	 */
1484c87aefeSPatrick Mooney 	do {
1494c87aefeSPatrick Mooney 		status = read(fd, buf, sizeof(buf));
1504c87aefeSPatrick Mooney 	} while (status == MEVENT_MAX);
1514c87aefeSPatrick Mooney }
1524c87aefeSPatrick Mooney 
1534c87aefeSPatrick Mooney static void
1544c87aefeSPatrick Mooney mevent_notify(void)
1554c87aefeSPatrick Mooney {
15684659b24SMichael Zeller 	char c = '\0';
1576dc98349SAndy Fiddaman 
1584c87aefeSPatrick Mooney 	/*
1594c87aefeSPatrick Mooney 	 * If calling from outside the i/o thread, write a byte on the
1604c87aefeSPatrick Mooney 	 * pipe to force the i/o thread to exit the blocking kevent call.
1614c87aefeSPatrick Mooney 	 */
1624c87aefeSPatrick Mooney 	if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) {
1634c87aefeSPatrick Mooney 		write(mevent_pipefd[1], &c, 1);
1644c87aefeSPatrick Mooney 	}
1654c87aefeSPatrick Mooney }
166b0de25cbSAndy Fiddaman 
167b0de25cbSAndy Fiddaman static void
168b0de25cbSAndy Fiddaman mevent_init(void)
169b0de25cbSAndy Fiddaman {
170b0de25cbSAndy Fiddaman #ifndef WITHOUT_CAPSICUM
171b0de25cbSAndy Fiddaman 	cap_rights_t rights;
172b0de25cbSAndy Fiddaman #endif
173b0de25cbSAndy Fiddaman 
174b0de25cbSAndy Fiddaman #ifdef __FreeBSD__
175b0de25cbSAndy Fiddaman 	mfd = kqueue();
176b0de25cbSAndy Fiddaman #else
177b0de25cbSAndy Fiddaman 	mfd = port_create();
178b0de25cbSAndy Fiddaman #endif
179b0de25cbSAndy Fiddaman 	assert(mfd > 0);
180b0de25cbSAndy Fiddaman 
181b0de25cbSAndy Fiddaman #ifndef WITHOUT_CAPSICUM
182b0de25cbSAndy Fiddaman 	cap_rights_init(&rights, CAP_KQUEUE);
183b0de25cbSAndy Fiddaman 	if (caph_rights_limit(mfd, &rights) == -1)
184b0de25cbSAndy Fiddaman 		errx(EX_OSERR, "Unable to apply rights for sandbox");
185251becc8SAndy Fiddaman #endif
186b0de25cbSAndy Fiddaman 
187b0de25cbSAndy Fiddaman 	LIST_INIT(&change_head);
188b0de25cbSAndy Fiddaman 	LIST_INIT(&global_head);
189b0de25cbSAndy Fiddaman }
190b0de25cbSAndy Fiddaman 
191b0de25cbSAndy Fiddaman 
1924c87aefeSPatrick Mooney #ifdef __FreeBSD__
1934c87aefeSPatrick Mooney static int
1944c87aefeSPatrick Mooney mevent_kq_filter(struct mevent *mevp)
1954c87aefeSPatrick Mooney {
1964c87aefeSPatrick Mooney 	int retval;
1974c87aefeSPatrick Mooney 
1984c87aefeSPatrick Mooney 	retval = 0;
1994c87aefeSPatrick Mooney 
2004c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_READ)
2014c87aefeSPatrick Mooney 		retval = EVFILT_READ;
2024c87aefeSPatrick Mooney 
2034c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_WRITE)
2044c87aefeSPatrick Mooney 		retval = EVFILT_WRITE;
2054c87aefeSPatrick Mooney 
2064c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_TIMER)
2074c87aefeSPatrick Mooney 		retval = EVFILT_TIMER;
2084c87aefeSPatrick Mooney 
2094c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_SIGNAL)
2104c87aefeSPatrick Mooney 		retval = EVFILT_SIGNAL;
2114c87aefeSPatrick Mooney 
212b0de25cbSAndy Fiddaman 	if (mevp->me_type == EVF_VNODE)
213b0de25cbSAndy Fiddaman 		retval = EVFILT_VNODE;
214b0de25cbSAndy Fiddaman 
2154c87aefeSPatrick Mooney 	return (retval);
2164c87aefeSPatrick Mooney }
2174c87aefeSPatrick Mooney 
2184c87aefeSPatrick Mooney static int
2194c87aefeSPatrick Mooney mevent_kq_flags(struct mevent *mevp)
2204c87aefeSPatrick Mooney {
2216dc98349SAndy Fiddaman 	int retval;
2226dc98349SAndy Fiddaman 
2236dc98349SAndy Fiddaman 	retval = mevp->me_state;
2246dc98349SAndy Fiddaman 
2256dc98349SAndy Fiddaman 	if (mevp->me_type == EVF_VNODE)
2266dc98349SAndy Fiddaman 		retval |= EV_CLEAR;
2276dc98349SAndy Fiddaman 
2286dc98349SAndy Fiddaman 	return (retval);
2294c87aefeSPatrick Mooney }
2304c87aefeSPatrick Mooney 
2314c87aefeSPatrick Mooney static int
2324c87aefeSPatrick Mooney mevent_kq_fflags(struct mevent *mevp)
2334c87aefeSPatrick Mooney {
234b0de25cbSAndy Fiddaman 	int retval;
235b0de25cbSAndy Fiddaman 
236b0de25cbSAndy Fiddaman 	retval = 0;
237b0de25cbSAndy Fiddaman 
238b0de25cbSAndy Fiddaman 	switch (mevp->me_type) {
239b0de25cbSAndy Fiddaman 	case EVF_VNODE:
240b0de25cbSAndy Fiddaman 		if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
241b0de25cbSAndy Fiddaman 			retval |= NOTE_ATTRIB;
242b0de25cbSAndy Fiddaman 		break;
2436dc98349SAndy Fiddaman 	case EVF_READ:
2446dc98349SAndy Fiddaman 	case EVF_WRITE:
2456dc98349SAndy Fiddaman 	case EVF_TIMER:
2466dc98349SAndy Fiddaman 	case EVF_SIGNAL:
2476dc98349SAndy Fiddaman 		break;
248b0de25cbSAndy Fiddaman 	}
249b0de25cbSAndy Fiddaman 
250b0de25cbSAndy Fiddaman 	return (retval);
251b0de25cbSAndy Fiddaman }
252b0de25cbSAndy Fiddaman 
253b0de25cbSAndy Fiddaman static void
254b0de25cbSAndy Fiddaman mevent_populate(struct mevent *mevp, struct kevent *kev)
255b0de25cbSAndy Fiddaman {
256b0de25cbSAndy Fiddaman 	if (mevp->me_type == EVF_TIMER) {
257b0de25cbSAndy Fiddaman 		kev->ident = mevp->me_timid;
258b0de25cbSAndy Fiddaman 		kev->data = mevp->me_msecs;
259b0de25cbSAndy Fiddaman 	} else {
260b0de25cbSAndy Fiddaman 		kev->ident = mevp->me_fd;
261b0de25cbSAndy Fiddaman 		kev->data = 0;
262b0de25cbSAndy Fiddaman 	}
263b0de25cbSAndy Fiddaman 	kev->filter = mevent_kq_filter(mevp);
264b0de25cbSAndy Fiddaman 	kev->flags = mevent_kq_flags(mevp);
265b0de25cbSAndy Fiddaman 	kev->fflags = mevent_kq_fflags(mevp);
266b0de25cbSAndy Fiddaman 	kev->udata = mevp;
2674c87aefeSPatrick Mooney }
2684c87aefeSPatrick Mooney 
2694c87aefeSPatrick Mooney static int
270b0de25cbSAndy Fiddaman mevent_build(struct kevent *kev)
2714c87aefeSPatrick Mooney {
2724c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
2734c87aefeSPatrick Mooney 	int i;
2744c87aefeSPatrick Mooney 
2754c87aefeSPatrick Mooney 	i = 0;
2764c87aefeSPatrick Mooney 
2774c87aefeSPatrick Mooney 	mevent_qlock();
2784c87aefeSPatrick Mooney 
2794c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
2804c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
2814c87aefeSPatrick Mooney 			/*
2824c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
2834c87aefeSPatrick Mooney 			 * event
2844c87aefeSPatrick Mooney 			 */
2854c87aefeSPatrick Mooney 			close(mevp->me_fd);
2864c87aefeSPatrick Mooney 		} else {
287b0de25cbSAndy Fiddaman 			assert((mevp->me_state & EV_ADD) == 0);
288b0de25cbSAndy Fiddaman 			mevent_populate(mevp, &kev[i]);
2894c87aefeSPatrick Mooney 			i++;
2904c87aefeSPatrick Mooney 		}
2914c87aefeSPatrick Mooney 
2924c87aefeSPatrick Mooney 		mevp->me_cq = 0;
2934c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
2944c87aefeSPatrick Mooney 
295154972afSPatrick Mooney 		if (mevp->me_state & EV_DELETE) {
2964c87aefeSPatrick Mooney 			free(mevp);
2974c87aefeSPatrick Mooney 		} else {
2984c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
2994c87aefeSPatrick Mooney 		}
3004c87aefeSPatrick Mooney 
3014c87aefeSPatrick Mooney 		assert(i < MEVENT_MAX);
3024c87aefeSPatrick Mooney 	}
3034c87aefeSPatrick Mooney 
3044c87aefeSPatrick Mooney 	mevent_qunlock();
3054c87aefeSPatrick Mooney 
3064c87aefeSPatrick Mooney 	return (i);
3074c87aefeSPatrick Mooney }
3084c87aefeSPatrick Mooney 
3094c87aefeSPatrick Mooney static void
3104c87aefeSPatrick Mooney mevent_handle(struct kevent *kev, int numev)
3114c87aefeSPatrick Mooney {
3124c87aefeSPatrick Mooney 	struct mevent *mevp;
3134c87aefeSPatrick Mooney 	int i;
3144c87aefeSPatrick Mooney 
3154c87aefeSPatrick Mooney 	for (i = 0; i < numev; i++) {
3164c87aefeSPatrick Mooney 		mevp = kev[i].udata;
3174c87aefeSPatrick Mooney 
3184c87aefeSPatrick Mooney 		/* XXX check for EV_ERROR ? */
3194c87aefeSPatrick Mooney 
3204c87aefeSPatrick Mooney 		(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
3214c87aefeSPatrick Mooney 	}
3224c87aefeSPatrick Mooney }
3234c87aefeSPatrick Mooney 
3244c87aefeSPatrick Mooney #else /* __FreeBSD__ */
3254c87aefeSPatrick Mooney 
326154972afSPatrick Mooney static boolean_t
327154972afSPatrick Mooney mevent_clarify_state(struct mevent *mevp)
328154972afSPatrick Mooney {
329154972afSPatrick Mooney 	const int state = mevp->me_state;
330154972afSPatrick Mooney 
331154972afSPatrick Mooney 	if ((state & EV_DELETE) != 0) {
332154972afSPatrick Mooney 		/* All other intents are overriden by delete. */
333154972afSPatrick Mooney 		mevp->me_state = EV_DELETE;
334154972afSPatrick Mooney 		return (B_TRUE);
335154972afSPatrick Mooney 	}
336154972afSPatrick Mooney 
337154972afSPatrick Mooney 	/*
338154972afSPatrick Mooney 	 * Without a distinction between EV_ADD and EV_ENABLE in our emulation,
339154972afSPatrick Mooney 	 * handling the add-disabled case means eliding the portfs operation
340154972afSPatrick Mooney 	 * when both flags are present.
341154972afSPatrick Mooney 	 *
342154972afSPatrick Mooney 	 * This is not a concern for subsequent enable/disable operations, as
343154972afSPatrick Mooney 	 * mevent_update() toggles the flags properly so they are not left in
344154972afSPatrick Mooney 	 * conflict.
345154972afSPatrick Mooney 	 */
346154972afSPatrick Mooney 	if (state == (EV_ENABLE|EV_DISABLE)) {
347154972afSPatrick Mooney 		mevp->me_state = EV_DISABLE;
348154972afSPatrick Mooney 		return (B_FALSE);
349154972afSPatrick Mooney 	}
350154972afSPatrick Mooney 
351154972afSPatrick Mooney 	return (B_TRUE);
352154972afSPatrick Mooney }
353154972afSPatrick Mooney 
3544c87aefeSPatrick Mooney static void
355251becc8SAndy Fiddaman mevent_poll_file_attrib(int fd, enum ev_type type, void *param)
3564c87aefeSPatrick Mooney {
357251becc8SAndy Fiddaman 	struct mevent *mevp = param;
358251becc8SAndy Fiddaman 	struct stat st;
3594c87aefeSPatrick Mooney 
360251becc8SAndy Fiddaman 	if (fstat(mevp->me_poll.mp_fd, &st) != 0) {
361e8d71297SAndy Fiddaman 		(void) fprintf(stderr, "%s: fstat(%d) failed: %s\n",
362e8d71297SAndy Fiddaman 		    __func__, fd, strerror(errno));
363251becc8SAndy Fiddaman 		return;
364251becc8SAndy Fiddaman 	}
3654c87aefeSPatrick Mooney 
366e8d71297SAndy Fiddaman 	/*
367e8d71297SAndy Fiddaman 	 * The only current consumer of file attribute monitoring is
368e8d71297SAndy Fiddaman 	 * blockif, which wants to know about size changes.
369e8d71297SAndy Fiddaman 	 */
370e8d71297SAndy Fiddaman 	if (mevp->me_poll.mp_size != st.st_size) {
371251becc8SAndy Fiddaman 		mevp->me_poll.mp_size = st.st_size;
3724c87aefeSPatrick Mooney 
373251becc8SAndy Fiddaman 		(*mevp->me_poll.mp_func)(mevp->me_poll.mp_fd, EVF_VNODE,
374251becc8SAndy Fiddaman 		    mevp->me_poll.mp_param);
375251becc8SAndy Fiddaman 	}
376251becc8SAndy Fiddaman }
3774c87aefeSPatrick Mooney 
378251becc8SAndy Fiddaman static void
379251becc8SAndy Fiddaman mevent_update_one_readwrite(struct mevent *mevp)
380251becc8SAndy Fiddaman {
381251becc8SAndy Fiddaman 	int portfd = mevp->me_notify.portnfy_port;
382251becc8SAndy Fiddaman 
383251becc8SAndy Fiddaman 	mevp->me_auto_requeue = B_FALSE;
384251becc8SAndy Fiddaman 
385251becc8SAndy Fiddaman 	switch (mevp->me_state) {
386251becc8SAndy Fiddaman 	case EV_ENABLE:
387251becc8SAndy Fiddaman 	{
388251becc8SAndy Fiddaman 		const int events = (mevp->me_type == EVF_READ) ?
389251becc8SAndy Fiddaman 		    POLLIN : POLLOUT;
390251becc8SAndy Fiddaman 
391251becc8SAndy Fiddaman 		if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd,
392251becc8SAndy Fiddaman 		    events, mevp) != 0) {
393251becc8SAndy Fiddaman 			(void) fprintf(stderr,
394251becc8SAndy Fiddaman 			    "port_associate fd %d %p failed: %s\n",
395251becc8SAndy Fiddaman 			    mevp->me_fd, mevp, strerror(errno));
3964c87aefeSPatrick Mooney 		}
397251becc8SAndy Fiddaman 		return;
398251becc8SAndy Fiddaman 	}
399251becc8SAndy Fiddaman 	case EV_DISABLE:
400251becc8SAndy Fiddaman 	case EV_DELETE:
401251becc8SAndy Fiddaman 		/*
402251becc8SAndy Fiddaman 		 * A disable that comes in while an event is being
403251becc8SAndy Fiddaman 		 * handled will result in an ENOENT.
404251becc8SAndy Fiddaman 		 */
405251becc8SAndy Fiddaman 		if (port_dissociate(portfd, PORT_SOURCE_FD,
406251becc8SAndy Fiddaman 		    mevp->me_fd) != 0 && errno != ENOENT) {
407251becc8SAndy Fiddaman 			(void) fprintf(stderr, "port_dissociate "
408251becc8SAndy Fiddaman 			    "portfd %d fd %d mevp %p failed: %s\n",
409251becc8SAndy Fiddaman 			    portfd, mevp->me_fd, mevp, strerror(errno));
4104c87aefeSPatrick Mooney 		}
411251becc8SAndy Fiddaman 		return;
412251becc8SAndy Fiddaman 	default:
413251becc8SAndy Fiddaman 		(void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
414251becc8SAndy Fiddaman 		    mevp->me_state);
415251becc8SAndy Fiddaman 		abort();
416251becc8SAndy Fiddaman 	}
417251becc8SAndy Fiddaman }
4184c87aefeSPatrick Mooney 
419251becc8SAndy Fiddaman static void
420251becc8SAndy Fiddaman mevent_update_one_timer(struct mevent *mevp)
421251becc8SAndy Fiddaman {
422251becc8SAndy Fiddaman 	mevp->me_auto_requeue = B_TRUE;
4234c87aefeSPatrick Mooney 
424251becc8SAndy Fiddaman 	switch (mevp->me_state) {
425251becc8SAndy Fiddaman 	case EV_ENABLE:
426251becc8SAndy Fiddaman 	{
427251becc8SAndy Fiddaman 		struct itimerspec it = { 0 };
4284c87aefeSPatrick Mooney 
429251becc8SAndy Fiddaman 		mevp->me_sigev.sigev_notify = SIGEV_PORT;
430251becc8SAndy Fiddaman 		mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify;
4314c87aefeSPatrick Mooney 
432251becc8SAndy Fiddaman 		if (timer_create(CLOCK_REALTIME, &mevp->me_sigev,
433251becc8SAndy Fiddaman 		    &mevp->me_timid) != 0) {
434251becc8SAndy Fiddaman 			(void) fprintf(stderr, "timer_create failed: %s",
435251becc8SAndy Fiddaman 			    strerror(errno));
436251becc8SAndy Fiddaman 			return;
437251becc8SAndy Fiddaman 		}
4384c87aefeSPatrick Mooney 
439251becc8SAndy Fiddaman 		/* The first timeout */
440251becc8SAndy Fiddaman 		it.it_value.tv_sec = mevp->me_msecs / MILLISEC;
441251becc8SAndy Fiddaman 		it.it_value.tv_nsec =
442251becc8SAndy Fiddaman 			MSEC2NSEC(mevp->me_msecs % MILLISEC);
443251becc8SAndy Fiddaman 		/* Repeat at the same interval */
444251becc8SAndy Fiddaman 		it.it_interval = it.it_value;
4454c87aefeSPatrick Mooney 
446251becc8SAndy Fiddaman 		if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) {
447251becc8SAndy Fiddaman 			(void) fprintf(stderr, "timer_settime failed: %s",
448251becc8SAndy Fiddaman 			    strerror(errno));
4494c87aefeSPatrick Mooney 		}
450251becc8SAndy Fiddaman 		return;
451251becc8SAndy Fiddaman 	}
452251becc8SAndy Fiddaman 	case EV_DISABLE:
453251becc8SAndy Fiddaman 	case EV_DELETE:
454251becc8SAndy Fiddaman 		if (timer_delete(mevp->me_timid) != 0) {
455251becc8SAndy Fiddaman 			(void) fprintf(stderr, "timer_delete failed: %s",
456251becc8SAndy Fiddaman 			    strerror(errno));
4574c87aefeSPatrick Mooney 		}
458251becc8SAndy Fiddaman 		mevp->me_timid = -1;
459251becc8SAndy Fiddaman 		return;
460251becc8SAndy Fiddaman 	default:
461251becc8SAndy Fiddaman 		(void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
462251becc8SAndy Fiddaman 		    mevp->me_state);
463251becc8SAndy Fiddaman 		abort();
464251becc8SAndy Fiddaman 	}
465251becc8SAndy Fiddaman }
466b0de25cbSAndy Fiddaman 
467251becc8SAndy Fiddaman static void
468251becc8SAndy Fiddaman mevent_update_one_vnode(struct mevent *mevp)
469251becc8SAndy Fiddaman {
470251becc8SAndy Fiddaman 	switch (mevp->me_state) {
471251becc8SAndy Fiddaman 	case EV_ENABLE:
472251becc8SAndy Fiddaman 	{
473e8d71297SAndy Fiddaman 		struct stat st;
474251becc8SAndy Fiddaman 		int events = 0;
475b0de25cbSAndy Fiddaman 
476251becc8SAndy Fiddaman 		if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
477251becc8SAndy Fiddaman 			events |= FILE_ATTRIB;
478b0de25cbSAndy Fiddaman 
479251becc8SAndy Fiddaman 		assert(events != 0);
480251becc8SAndy Fiddaman 
481e8d71297SAndy Fiddaman 		/*
482e8d71297SAndy Fiddaman 		 * It is tempting to use the PORT_SOURCE_FILE type for this in
483e8d71297SAndy Fiddaman 		 * conjunction with the FILE_ATTRIB event type. Unfortunately
484e8d71297SAndy Fiddaman 		 * this event type triggers on any change to the file's
485e8d71297SAndy Fiddaman 		 * ctime, and therefore for every write as well as attribute
486e8d71297SAndy Fiddaman 		 * changes. It also does not work for ZVOLs.
487e8d71297SAndy Fiddaman 		 *
488e8d71297SAndy Fiddaman 		 * Convert this to a timer event and poll for the file
489e8d71297SAndy Fiddaman 		 * attribute changes that we care about.
490e8d71297SAndy Fiddaman 		 */
491251becc8SAndy Fiddaman 
492e8d71297SAndy Fiddaman 		if (fstat(mevp->me_fd, &st) != 0) {
493e8d71297SAndy Fiddaman 			(void) fprintf(stderr, "fstat(%d) failed: %s\n",
494e8d71297SAndy Fiddaman 			    mevp->me_fd, strerror(errno));
495e8d71297SAndy Fiddaman 			return;
496e8d71297SAndy Fiddaman 		}
497b0de25cbSAndy Fiddaman 
498e8d71297SAndy Fiddaman 		mevp->me_poll.mp_fd = mevp->me_fd;
499e8d71297SAndy Fiddaman 		mevp->me_poll.mp_size = st.st_size;
500251becc8SAndy Fiddaman 
501e8d71297SAndy Fiddaman 		mevp->me_poll.mp_func = mevp->me_func;
502e8d71297SAndy Fiddaman 		mevp->me_poll.mp_param = mevp->me_param;
503e8d71297SAndy Fiddaman 		mevp->me_func = mevent_poll_file_attrib;
504e8d71297SAndy Fiddaman 		mevp->me_param = mevp;
505251becc8SAndy Fiddaman 
506e8d71297SAndy Fiddaman 		mevp->me_type = EVF_TIMER;
507e8d71297SAndy Fiddaman 		mevp->me_timid = -1;
508e8d71297SAndy Fiddaman 		mevp->me_msecs = mevent_file_poll_interval_ms;
509e8d71297SAndy Fiddaman 		mevent_update_one_timer(mevp);
510251becc8SAndy Fiddaman 
511251becc8SAndy Fiddaman 		return;
512251becc8SAndy Fiddaman 	}
513251becc8SAndy Fiddaman 	case EV_DISABLE:
514251becc8SAndy Fiddaman 	case EV_DELETE:
515251becc8SAndy Fiddaman 		/*
516e8d71297SAndy Fiddaman 		 * These events do not really exist as they are converted to
517e8d71297SAndy Fiddaman 		 * timers; fall through to abort.
518251becc8SAndy Fiddaman 		 */
5194c87aefeSPatrick Mooney 	default:
520251becc8SAndy Fiddaman 		(void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
521251becc8SAndy Fiddaman 		    mevp->me_state);
522251becc8SAndy Fiddaman 		abort();
5234c87aefeSPatrick Mooney 	}
524251becc8SAndy Fiddaman }
5254c87aefeSPatrick Mooney 
526251becc8SAndy Fiddaman static void
527251becc8SAndy Fiddaman mevent_update_one(struct mevent *mevp)
528251becc8SAndy Fiddaman {
529251becc8SAndy Fiddaman 	switch (mevp->me_type) {
530251becc8SAndy Fiddaman 	case EVF_READ:
531251becc8SAndy Fiddaman 	case EVF_WRITE:
532251becc8SAndy Fiddaman 		mevent_update_one_readwrite(mevp);
533251becc8SAndy Fiddaman 		break;
534251becc8SAndy Fiddaman 	case EVF_TIMER:
535251becc8SAndy Fiddaman 		mevent_update_one_timer(mevp);
536251becc8SAndy Fiddaman 		break;
537251becc8SAndy Fiddaman 	case EVF_VNODE:
538251becc8SAndy Fiddaman 		mevent_update_one_vnode(mevp);
539251becc8SAndy Fiddaman 		break;
540251becc8SAndy Fiddaman 	case EVF_SIGNAL: /* EVF_SIGNAL not yet implemented. */
541251becc8SAndy Fiddaman 	default:
542251becc8SAndy Fiddaman 		(void) fprintf(stderr, "%s: unhandled event type %d\n",
543251becc8SAndy Fiddaman 		    __func__, mevp->me_type);
544251becc8SAndy Fiddaman 		abort();
545251becc8SAndy Fiddaman 	}
5464c87aefeSPatrick Mooney }
5474c87aefeSPatrick Mooney 
5484c87aefeSPatrick Mooney static void
549b0de25cbSAndy Fiddaman mevent_populate(struct mevent *mevp)
550b0de25cbSAndy Fiddaman {
551b0de25cbSAndy Fiddaman 	mevp->me_notify.portnfy_port = mfd;
552b0de25cbSAndy Fiddaman 	mevp->me_notify.portnfy_user = mevp;
553b0de25cbSAndy Fiddaman }
554b0de25cbSAndy Fiddaman 
555b0de25cbSAndy Fiddaman static void
556b0de25cbSAndy Fiddaman mevent_update_pending()
5574c87aefeSPatrick Mooney {
5584c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
5594c87aefeSPatrick Mooney 
5604c87aefeSPatrick Mooney 	mevent_qlock();
5614c87aefeSPatrick Mooney 
5624c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
563b0de25cbSAndy Fiddaman 		mevent_populate(mevp);
5644c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
5654c87aefeSPatrick Mooney 			/*
5664c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
5674c87aefeSPatrick Mooney 			 * event
5684c87aefeSPatrick Mooney 			 */
5694c87aefeSPatrick Mooney 			(void) close(mevp->me_fd);
5704c87aefeSPatrick Mooney 			mevp->me_fd = -1;
5714c87aefeSPatrick Mooney 		} else {
572154972afSPatrick Mooney 			if (mevent_clarify_state(mevp)) {
573154972afSPatrick Mooney 				mevent_update_one(mevp);
574154972afSPatrick Mooney 			}
5754c87aefeSPatrick Mooney 		}
5764c87aefeSPatrick Mooney 
5774c87aefeSPatrick Mooney 		mevp->me_cq = 0;
5784c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
5794c87aefeSPatrick Mooney 
580154972afSPatrick Mooney 		if (mevp->me_state & EV_DELETE) {
5814c87aefeSPatrick Mooney 			free(mevp);
5824c87aefeSPatrick Mooney 		} else {
5834c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
5844c87aefeSPatrick Mooney 		}
5854c87aefeSPatrick Mooney 	}
5864c87aefeSPatrick Mooney 
5874c87aefeSPatrick Mooney 	mevent_qunlock();
5884c87aefeSPatrick Mooney }
5894c87aefeSPatrick Mooney 
5904c87aefeSPatrick Mooney static void
5914c87aefeSPatrick Mooney mevent_handle_pe(port_event_t *pe)
5924c87aefeSPatrick Mooney {
5934c87aefeSPatrick Mooney 	struct mevent *mevp = pe->portev_user;
5944c87aefeSPatrick Mooney 
5954c87aefeSPatrick Mooney 	(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
5964c87aefeSPatrick Mooney 
5974c87aefeSPatrick Mooney 	mevent_qlock();
5984c87aefeSPatrick Mooney 	if (!mevp->me_cq && !mevp->me_auto_requeue) {
5994c87aefeSPatrick Mooney 		mevent_update_one(mevp);
6004c87aefeSPatrick Mooney 	}
6014c87aefeSPatrick Mooney 	mevent_qunlock();
6024c87aefeSPatrick Mooney }
6034c87aefeSPatrick Mooney #endif
6044c87aefeSPatrick Mooney 
605154972afSPatrick Mooney static struct mevent *
606154972afSPatrick Mooney mevent_add_state(int tfd, enum ev_type type,
607154972afSPatrick Mooney 	   void (*func)(int, enum ev_type, void *), void *param,
608b0de25cbSAndy Fiddaman 	   int state, int fflags)
6094c87aefeSPatrick Mooney {
610b0de25cbSAndy Fiddaman #ifdef __FreeBSD__
611b0de25cbSAndy Fiddaman 	struct kevent kev;
612b0de25cbSAndy Fiddaman #endif
6134c87aefeSPatrick Mooney 	struct mevent *lp, *mevp;
614b0de25cbSAndy Fiddaman #ifdef __FreeBSD__
615b0de25cbSAndy Fiddaman 	int ret;
616b0de25cbSAndy Fiddaman #endif
6174c87aefeSPatrick Mooney 
6184c87aefeSPatrick Mooney 	if (tfd < 0 || func == NULL) {
6194c87aefeSPatrick Mooney 		return (NULL);
6204c87aefeSPatrick Mooney 	}
6214c87aefeSPatrick Mooney 
6224c87aefeSPatrick Mooney 	mevp = NULL;
6234c87aefeSPatrick Mooney 
624b0de25cbSAndy Fiddaman 	pthread_once(&mevent_once, mevent_init);
625b0de25cbSAndy Fiddaman 
6264c87aefeSPatrick Mooney 	mevent_qlock();
6274c87aefeSPatrick Mooney 
6284c87aefeSPatrick Mooney 	/*
6294c87aefeSPatrick Mooney 	 * Verify that the fd/type tuple is not present in any list
6304c87aefeSPatrick Mooney 	 */
6314c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &global_head, me_list) {
6324c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
6334c87aefeSPatrick Mooney 		    lp->me_type == type) {
6344c87aefeSPatrick Mooney 			goto exit;
6354c87aefeSPatrick Mooney 		}
6364c87aefeSPatrick Mooney 	}
6374c87aefeSPatrick Mooney 
6384c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &change_head, me_list) {
6394c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
6404c87aefeSPatrick Mooney 		    lp->me_type == type) {
6414c87aefeSPatrick Mooney 			goto exit;
6424c87aefeSPatrick Mooney 		}
6434c87aefeSPatrick Mooney 	}
6444c87aefeSPatrick Mooney 
6454c87aefeSPatrick Mooney 	/*
646b0de25cbSAndy Fiddaman 	 * Allocate an entry and populate it.
6474c87aefeSPatrick Mooney 	 */
6484c87aefeSPatrick Mooney 	mevp = calloc(1, sizeof(struct mevent));
6494c87aefeSPatrick Mooney 	if (mevp == NULL) {
6504c87aefeSPatrick Mooney 		goto exit;
6514c87aefeSPatrick Mooney 	}
6524c87aefeSPatrick Mooney 
6534c87aefeSPatrick Mooney 	if (type == EVF_TIMER) {
6544c87aefeSPatrick Mooney 		mevp->me_msecs = tfd;
655251becc8SAndy Fiddaman #ifdef __FreeBSD__
6564c87aefeSPatrick Mooney 		mevp->me_timid = mevent_timid++;
657251becc8SAndy Fiddaman #else
658251becc8SAndy Fiddaman 		mevp->me_timid = -1;
659251becc8SAndy Fiddaman #endif
6604c87aefeSPatrick Mooney 	} else
6614c87aefeSPatrick Mooney 		mevp->me_fd = tfd;
6624c87aefeSPatrick Mooney 	mevp->me_type = type;
6634c87aefeSPatrick Mooney 	mevp->me_func = func;
6644c87aefeSPatrick Mooney 	mevp->me_param = param;
665154972afSPatrick Mooney 	mevp->me_state = state;
666b0de25cbSAndy Fiddaman 	mevp->me_fflags = fflags;
667b0de25cbSAndy Fiddaman 
668b0de25cbSAndy Fiddaman 	/*
669b0de25cbSAndy Fiddaman 	 * Try to add the event.  If this fails, report the failure to
670b0de25cbSAndy Fiddaman 	 * the caller.
671b0de25cbSAndy Fiddaman 	 */
672b0de25cbSAndy Fiddaman #ifdef __FreeBSD__
673b0de25cbSAndy Fiddaman 	mevent_populate(mevp, &kev);
674b0de25cbSAndy Fiddaman 	ret = kevent(mfd, &kev, 1, NULL, 0, NULL);
675b0de25cbSAndy Fiddaman 	if (ret == -1) {
676b0de25cbSAndy Fiddaman 		free(mevp);
677b0de25cbSAndy Fiddaman 		mevp = NULL;
678b0de25cbSAndy Fiddaman 		goto exit;
679b0de25cbSAndy Fiddaman 	}
680b0de25cbSAndy Fiddaman 	mevp->me_state &= ~EV_ADD;
681b0de25cbSAndy Fiddaman #else
682b0de25cbSAndy Fiddaman 	mevent_populate(mevp);
683b0de25cbSAndy Fiddaman 	if (mevent_clarify_state(mevp))
684b0de25cbSAndy Fiddaman 		mevent_update_one(mevp);
685b0de25cbSAndy Fiddaman #endif
686b0de25cbSAndy Fiddaman 
687b0de25cbSAndy Fiddaman 	LIST_INSERT_HEAD(&global_head, mevp, me_list);
6884c87aefeSPatrick Mooney 
6894c87aefeSPatrick Mooney exit:
6904c87aefeSPatrick Mooney 	mevent_qunlock();
6914c87aefeSPatrick Mooney 
6924c87aefeSPatrick Mooney 	return (mevp);
6934c87aefeSPatrick Mooney }
6944c87aefeSPatrick Mooney 
695154972afSPatrick Mooney struct mevent *
696154972afSPatrick Mooney mevent_add(int tfd, enum ev_type type,
697154972afSPatrick Mooney 	   void (*func)(int, enum ev_type, void *), void *param)
698154972afSPatrick Mooney {
699154972afSPatrick Mooney 
700b0de25cbSAndy Fiddaman 	return (mevent_add_state(tfd, type, func, param, EV_ADD, 0));
701b0de25cbSAndy Fiddaman }
702b0de25cbSAndy Fiddaman 
703b0de25cbSAndy Fiddaman struct mevent *
704b0de25cbSAndy Fiddaman mevent_add_flags(int tfd, enum ev_type type, int fflags,
705b0de25cbSAndy Fiddaman 		 void (*func)(int, enum ev_type, void *), void *param)
706b0de25cbSAndy Fiddaman {
707b0de25cbSAndy Fiddaman 
708b0de25cbSAndy Fiddaman 	return (mevent_add_state(tfd, type, func, param, EV_ADD, fflags));
709154972afSPatrick Mooney }
710154972afSPatrick Mooney 
711154972afSPatrick Mooney struct mevent *
712154972afSPatrick Mooney mevent_add_disabled(int tfd, enum ev_type type,
713154972afSPatrick Mooney 		    void (*func)(int, enum ev_type, void *), void *param)
714154972afSPatrick Mooney {
715154972afSPatrick Mooney 
716b0de25cbSAndy Fiddaman 	return (mevent_add_state(tfd, type, func, param, EV_ADD | EV_DISABLE, 0));
717154972afSPatrick Mooney }
718154972afSPatrick Mooney 
7194c87aefeSPatrick Mooney static int
720154972afSPatrick Mooney mevent_update(struct mevent *evp, bool enable)
7214c87aefeSPatrick Mooney {
722154972afSPatrick Mooney 	int newstate;
723154972afSPatrick Mooney 
724154972afSPatrick Mooney 	mevent_qlock();
725154972afSPatrick Mooney 
7264c87aefeSPatrick Mooney 	/*
7274c87aefeSPatrick Mooney 	 * It's not possible to enable/disable a deleted event
7284c87aefeSPatrick Mooney 	 */
729154972afSPatrick Mooney 	assert((evp->me_state & EV_DELETE) == 0);
730154972afSPatrick Mooney 
731154972afSPatrick Mooney 	newstate = evp->me_state;
732154972afSPatrick Mooney 	if (enable) {
733154972afSPatrick Mooney 		newstate |= EV_ENABLE;
734154972afSPatrick Mooney 		newstate &= ~EV_DISABLE;
735154972afSPatrick Mooney 	} else {
736154972afSPatrick Mooney 		newstate |= EV_DISABLE;
737154972afSPatrick Mooney 		newstate &= ~EV_ENABLE;
738154972afSPatrick Mooney 	}
7394c87aefeSPatrick Mooney 
7404c87aefeSPatrick Mooney 	/*
7414c87aefeSPatrick Mooney 	 * No update needed if state isn't changing
7424c87aefeSPatrick Mooney 	 */
743154972afSPatrick Mooney 	if (evp->me_state != newstate) {
744154972afSPatrick Mooney 		evp->me_state = newstate;
745154972afSPatrick Mooney 
746154972afSPatrick Mooney 		/*
747154972afSPatrick Mooney 		 * Place the entry onto the changed list if not
748154972afSPatrick Mooney 		 * already there.
749154972afSPatrick Mooney 		 */
750154972afSPatrick Mooney 		if (evp->me_cq == 0) {
751154972afSPatrick Mooney 			evp->me_cq = 1;
752154972afSPatrick Mooney 			LIST_REMOVE(evp, me_list);
753154972afSPatrick Mooney 			LIST_INSERT_HEAD(&change_head, evp, me_list);
754154972afSPatrick Mooney 			mevent_notify();
755154972afSPatrick Mooney 		}
7564c87aefeSPatrick Mooney 	}
7574c87aefeSPatrick Mooney 
7584c87aefeSPatrick Mooney 	mevent_qunlock();
7594c87aefeSPatrick Mooney 
7604c87aefeSPatrick Mooney 	return (0);
7614c87aefeSPatrick Mooney }
7624c87aefeSPatrick Mooney 
7634c87aefeSPatrick Mooney int
7644c87aefeSPatrick Mooney mevent_enable(struct mevent *evp)
7654c87aefeSPatrick Mooney {
7664c87aefeSPatrick Mooney 
767154972afSPatrick Mooney 	return (mevent_update(evp, true));
7684c87aefeSPatrick Mooney }
7694c87aefeSPatrick Mooney 
7704c87aefeSPatrick Mooney int
7714c87aefeSPatrick Mooney mevent_disable(struct mevent *evp)
7724c87aefeSPatrick Mooney {
7734c87aefeSPatrick Mooney 
774154972afSPatrick Mooney 	return (mevent_update(evp, false));
7754c87aefeSPatrick Mooney }
7764c87aefeSPatrick Mooney 
7774c87aefeSPatrick Mooney static int
7784c87aefeSPatrick Mooney mevent_delete_event(struct mevent *evp, int closefd)
7794c87aefeSPatrick Mooney {
7804c87aefeSPatrick Mooney 	mevent_qlock();
7814c87aefeSPatrick Mooney 
7824c87aefeSPatrick Mooney 	/*
7834c87aefeSPatrick Mooney          * Place the entry onto the changed list if not already there, and
7844c87aefeSPatrick Mooney 	 * mark as to be deleted.
7854c87aefeSPatrick Mooney          */
7864c87aefeSPatrick Mooney         if (evp->me_cq == 0) {
7874c87aefeSPatrick Mooney 		evp->me_cq = 1;
7884c87aefeSPatrick Mooney 		LIST_REMOVE(evp, me_list);
7894c87aefeSPatrick Mooney 		LIST_INSERT_HEAD(&change_head, evp, me_list);
7904c87aefeSPatrick Mooney 		mevent_notify();
7914c87aefeSPatrick Mooney         }
792154972afSPatrick Mooney 	evp->me_state = EV_DELETE;
7934c87aefeSPatrick Mooney 
7944c87aefeSPatrick Mooney 	if (closefd)
7954c87aefeSPatrick Mooney 		evp->me_closefd = 1;
7964c87aefeSPatrick Mooney 
7974c87aefeSPatrick Mooney 	mevent_qunlock();
7984c87aefeSPatrick Mooney 
7994c87aefeSPatrick Mooney 	return (0);
8004c87aefeSPatrick Mooney }
8014c87aefeSPatrick Mooney 
8024c87aefeSPatrick Mooney int
8034c87aefeSPatrick Mooney mevent_delete(struct mevent *evp)
8044c87aefeSPatrick Mooney {
8054c87aefeSPatrick Mooney 
8064c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 0));
8074c87aefeSPatrick Mooney }
8084c87aefeSPatrick Mooney 
8094c87aefeSPatrick Mooney int
8104c87aefeSPatrick Mooney mevent_delete_close(struct mevent *evp)
8114c87aefeSPatrick Mooney {
8124c87aefeSPatrick Mooney 
8134c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 1));
8144c87aefeSPatrick Mooney }
8154c87aefeSPatrick Mooney 
8164c87aefeSPatrick Mooney static void
8174c87aefeSPatrick Mooney mevent_set_name(void)
8184c87aefeSPatrick Mooney {
8194c87aefeSPatrick Mooney 
8204c87aefeSPatrick Mooney 	pthread_set_name_np(mevent_tid, "mevent");
8214c87aefeSPatrick Mooney }
8224c87aefeSPatrick Mooney 
8234c87aefeSPatrick Mooney void
8244c87aefeSPatrick Mooney mevent_dispatch(void)
8254c87aefeSPatrick Mooney {
8264c87aefeSPatrick Mooney #ifdef __FreeBSD__
8274c87aefeSPatrick Mooney 	struct kevent changelist[MEVENT_MAX];
8284c87aefeSPatrick Mooney 	struct kevent eventlist[MEVENT_MAX];
8294c87aefeSPatrick Mooney 	struct mevent *pipev;
8304c87aefeSPatrick Mooney 	int numev;
8314c87aefeSPatrick Mooney #else
8324c87aefeSPatrick Mooney 	struct mevent *pipev;
8334c87aefeSPatrick Mooney #endif
8344c87aefeSPatrick Mooney 	int ret;
8354c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
8364c87aefeSPatrick Mooney 	cap_rights_t rights;
8374c87aefeSPatrick Mooney #endif
8384c87aefeSPatrick Mooney 
8394c87aefeSPatrick Mooney 	mevent_tid = pthread_self();
8404c87aefeSPatrick Mooney 	mevent_set_name();
8414c87aefeSPatrick Mooney 
842b0de25cbSAndy Fiddaman 	pthread_once(&mevent_once, mevent_init);
8434c87aefeSPatrick Mooney 
8444c87aefeSPatrick Mooney 	/*
8454c87aefeSPatrick Mooney 	 * Open the pipe that will be used for other threads to force
8464c87aefeSPatrick Mooney 	 * the blocking kqueue call to exit by writing to it. Set the
8474c87aefeSPatrick Mooney 	 * descriptor to non-blocking.
8484c87aefeSPatrick Mooney 	 */
8494c87aefeSPatrick Mooney 	ret = pipe(mevent_pipefd);
8504c87aefeSPatrick Mooney 	if (ret < 0) {
8514c87aefeSPatrick Mooney 		perror("pipe");
8524c87aefeSPatrick Mooney 		exit(0);
8534c87aefeSPatrick Mooney 	}
8544c87aefeSPatrick Mooney 
8554c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
8564c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
8574c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[0], &rights) == -1)
8584c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
8594c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[1], &rights) == -1)
8604c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
8614c87aefeSPatrick Mooney #endif
8624c87aefeSPatrick Mooney 
8634c87aefeSPatrick Mooney 	/*
8644c87aefeSPatrick Mooney 	 * Add internal event handler for the pipe write fd
8654c87aefeSPatrick Mooney 	 */
8664c87aefeSPatrick Mooney 	pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL);
8674c87aefeSPatrick Mooney 	assert(pipev != NULL);
8684c87aefeSPatrick Mooney 
8694c87aefeSPatrick Mooney 	for (;;) {
8704c87aefeSPatrick Mooney #ifdef __FreeBSD__
8714c87aefeSPatrick Mooney 		/*
8724c87aefeSPatrick Mooney 		 * Build changelist if required.
8734c87aefeSPatrick Mooney 		 * XXX the changelist can be put into the blocking call
8744c87aefeSPatrick Mooney 		 * to eliminate the extra syscall. Currently better for
8754c87aefeSPatrick Mooney 		 * debug.
8764c87aefeSPatrick Mooney 		 */
877b0de25cbSAndy Fiddaman 		numev = mevent_build(changelist);
8784c87aefeSPatrick Mooney 		if (numev) {
8794c87aefeSPatrick Mooney 			ret = kevent(mfd, changelist, numev, NULL, 0, NULL);
8804c87aefeSPatrick Mooney 			if (ret == -1) {
8814c87aefeSPatrick Mooney 				perror("Error return from kevent change");
8824c87aefeSPatrick Mooney 			}
8834c87aefeSPatrick Mooney 		}
8844c87aefeSPatrick Mooney 
8854c87aefeSPatrick Mooney 		/*
8864c87aefeSPatrick Mooney 		 * Block awaiting events
8874c87aefeSPatrick Mooney 		 */
8884c87aefeSPatrick Mooney 		ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);
8894c87aefeSPatrick Mooney 		if (ret == -1 && errno != EINTR) {
8904c87aefeSPatrick Mooney 			perror("Error return from kevent monitor");
8914c87aefeSPatrick Mooney 		}
8926dc98349SAndy Fiddaman 
8934c87aefeSPatrick Mooney 		/*
8944c87aefeSPatrick Mooney 		 * Handle reported events
8954c87aefeSPatrick Mooney 		 */
8964c87aefeSPatrick Mooney 		mevent_handle(eventlist, ret);
8974c87aefeSPatrick Mooney 
8984c87aefeSPatrick Mooney #else /* __FreeBSD__ */
8994c87aefeSPatrick Mooney 		port_event_t pev;
9004c87aefeSPatrick Mooney 
9014c87aefeSPatrick Mooney 		/* Handle any pending updates */
902b0de25cbSAndy Fiddaman 		mevent_update_pending();
9034c87aefeSPatrick Mooney 
9044c87aefeSPatrick Mooney 		/* Block awaiting events */
905b0de25cbSAndy Fiddaman 		ret = port_get(mfd, &pev, NULL);
906cf7690ebSMike Zeller 		if (ret != 0) {
907cf7690ebSMike Zeller 			if (errno != EINTR)
908cf7690ebSMike Zeller 				perror("Error return from port_get");
9094c87aefeSPatrick Mooney 			continue;
9104c87aefeSPatrick Mooney 		}
9114c87aefeSPatrick Mooney 
9124c87aefeSPatrick Mooney 		/* Handle reported event */
9134c87aefeSPatrick Mooney 		mevent_handle_pe(&pev);
9144c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
9156dc98349SAndy Fiddaman 	}
9164c87aefeSPatrick Mooney }
917