xref: /freebsd/usr.sbin/bhyve/mevent.c (revision 4dfa329f48618d30e0c32529f874c1d0cc7beb00)
1366f6083SPeter Grehan /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
5366f6083SPeter Grehan  * All rights reserved.
6366f6083SPeter Grehan  *
7366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
8366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
9366f6083SPeter Grehan  * are met:
10366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
15366f6083SPeter Grehan  *
16366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26366f6083SPeter Grehan  * SUCH DAMAGE.
27366f6083SPeter Grehan  */
28366f6083SPeter Grehan 
29366f6083SPeter Grehan /*
30366f6083SPeter Grehan  * Micro event library for FreeBSD, designed for a single i/o thread
31366f6083SPeter Grehan  * using kqueue, and having events be persistent by default.
32366f6083SPeter Grehan  */
33366f6083SPeter Grehan 
34366f6083SPeter Grehan #include <sys/cdefs.h>
35366f6083SPeter Grehan #include <assert.h>
36abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
37abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
38abfa3c39SMarcelo Araujo #endif
3900ef17beSBartek Rutkowski #include <err.h>
40366f6083SPeter Grehan #include <errno.h>
4107b35f77SVincenzo Maffione #include <stdbool.h>
42366f6083SPeter Grehan #include <stdlib.h>
43366f6083SPeter Grehan #include <stdio.h>
44366f6083SPeter Grehan #include <string.h>
4500ef17beSBartek Rutkowski #include <sysexits.h>
46366f6083SPeter Grehan #include <unistd.h>
47366f6083SPeter Grehan 
48366f6083SPeter Grehan #include <sys/types.h>
4900ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
5000ef17beSBartek Rutkowski #include <sys/capsicum.h>
5100ef17beSBartek Rutkowski #endif
52366f6083SPeter Grehan #include <sys/event.h>
53366f6083SPeter Grehan #include <sys/time.h>
54366f6083SPeter Grehan 
55366f6083SPeter Grehan #include <pthread.h>
564e8c7465SPeter Grehan #include <pthread_np.h>
57366f6083SPeter Grehan 
58366f6083SPeter Grehan #include "mevent.h"
59366f6083SPeter Grehan 
60366f6083SPeter Grehan #define	MEVENT_MAX	64
61366f6083SPeter Grehan 
62366f6083SPeter Grehan static pthread_t mevent_tid;
63e8424e29SJohn Baldwin static pthread_once_t mevent_once = PTHREAD_ONCE_INIT;
64151dba4aSPeter Grehan static int mevent_timid = 43;
65366f6083SPeter Grehan static int mevent_pipefd[2];
66e8424e29SJohn Baldwin static int mfd;
67366f6083SPeter Grehan static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
68366f6083SPeter Grehan 
69366f6083SPeter Grehan struct mevent {
70366f6083SPeter Grehan 	void	(*me_func)(int, enum ev_type, void *);
71151dba4aSPeter Grehan #define me_msecs me_fd
72366f6083SPeter Grehan 	int	me_fd;
73151dba4aSPeter Grehan 	int	me_timid;
74366f6083SPeter Grehan 	enum ev_type me_type;
75366f6083SPeter Grehan 	void    *me_param;
76366f6083SPeter Grehan 	int	me_cq;
7707b35f77SVincenzo Maffione 	int	me_state; /* Desired kevent flags. */
78366f6083SPeter Grehan 	int	me_closefd;
7967d60dccSJohn Baldwin 	int	me_fflags;
80366f6083SPeter Grehan 	LIST_ENTRY(mevent) me_list;
81366f6083SPeter Grehan };
82366f6083SPeter Grehan 
83*4dfa329fSJessica Clarke enum mevent_update_type {
84*4dfa329fSJessica Clarke 	UPDATE_ENABLE,
85*4dfa329fSJessica Clarke 	UPDATE_DISABLE,
86*4dfa329fSJessica Clarke 	UPDATE_TIMER,
87*4dfa329fSJessica Clarke };
88*4dfa329fSJessica Clarke 
89366f6083SPeter Grehan static LIST_HEAD(listhead, mevent) global_head, change_head;
90366f6083SPeter Grehan 
91366f6083SPeter Grehan static void
92366f6083SPeter Grehan mevent_qlock(void)
93366f6083SPeter Grehan {
94366f6083SPeter Grehan 	pthread_mutex_lock(&mevent_lmutex);
95366f6083SPeter Grehan }
96366f6083SPeter Grehan 
97366f6083SPeter Grehan static void
98366f6083SPeter Grehan mevent_qunlock(void)
99366f6083SPeter Grehan {
100366f6083SPeter Grehan 	pthread_mutex_unlock(&mevent_lmutex);
101366f6083SPeter Grehan }
102366f6083SPeter Grehan 
103366f6083SPeter Grehan static void
10498d920d9SMark Johnston mevent_pipe_read(int fd, enum ev_type type __unused, void *param __unused)
105366f6083SPeter Grehan {
106366f6083SPeter Grehan 	char buf[MEVENT_MAX];
107366f6083SPeter Grehan 	int status;
108366f6083SPeter Grehan 
109366f6083SPeter Grehan 	/*
110366f6083SPeter Grehan 	 * Drain the pipe read side. The fd is non-blocking so this is
111366f6083SPeter Grehan 	 * safe to do.
112366f6083SPeter Grehan 	 */
113366f6083SPeter Grehan 	do {
114366f6083SPeter Grehan 		status = read(fd, buf, sizeof(buf));
115366f6083SPeter Grehan 	} while (status == MEVENT_MAX);
116366f6083SPeter Grehan }
117366f6083SPeter Grehan 
118366f6083SPeter Grehan static void
119366f6083SPeter Grehan mevent_notify(void)
120366f6083SPeter Grehan {
121fe1329e4SSean Chittenden 	char c = '\0';
122366f6083SPeter Grehan 
123366f6083SPeter Grehan 	/*
124366f6083SPeter Grehan 	 * If calling from outside the i/o thread, write a byte on the
125366f6083SPeter Grehan 	 * pipe to force the i/o thread to exit the blocking kevent call.
126366f6083SPeter Grehan 	 */
127366f6083SPeter Grehan 	if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) {
128366f6083SPeter Grehan 		write(mevent_pipefd[1], &c, 1);
129366f6083SPeter Grehan 	}
130366f6083SPeter Grehan }
131366f6083SPeter Grehan 
132e8424e29SJohn Baldwin static void
133e8424e29SJohn Baldwin mevent_init(void)
134e8424e29SJohn Baldwin {
135e8424e29SJohn Baldwin #ifndef WITHOUT_CAPSICUM
136e8424e29SJohn Baldwin 	cap_rights_t rights;
137e8424e29SJohn Baldwin #endif
138e8424e29SJohn Baldwin 
139e8424e29SJohn Baldwin 	mfd = kqueue();
140e8424e29SJohn Baldwin 	assert(mfd > 0);
141e8424e29SJohn Baldwin 
142e8424e29SJohn Baldwin #ifndef WITHOUT_CAPSICUM
143e8424e29SJohn Baldwin 	cap_rights_init(&rights, CAP_KQUEUE);
144e8424e29SJohn Baldwin 	if (caph_rights_limit(mfd, &rights) == -1)
145e8424e29SJohn Baldwin 		errx(EX_OSERR, "Unable to apply rights for sandbox");
146e8424e29SJohn Baldwin #endif
147e8424e29SJohn Baldwin 
148e8424e29SJohn Baldwin 	LIST_INIT(&change_head);
149e8424e29SJohn Baldwin 	LIST_INIT(&global_head);
150e8424e29SJohn Baldwin }
151e8424e29SJohn Baldwin 
152366f6083SPeter Grehan static int
153366f6083SPeter Grehan mevent_kq_filter(struct mevent *mevp)
154366f6083SPeter Grehan {
155366f6083SPeter Grehan 	int retval;
156366f6083SPeter Grehan 
157366f6083SPeter Grehan 	retval = 0;
158366f6083SPeter Grehan 
159366f6083SPeter Grehan 	if (mevp->me_type == EVF_READ)
160366f6083SPeter Grehan 		retval = EVFILT_READ;
161366f6083SPeter Grehan 
162366f6083SPeter Grehan 	if (mevp->me_type == EVF_WRITE)
163366f6083SPeter Grehan 		retval = EVFILT_WRITE;
164366f6083SPeter Grehan 
165151dba4aSPeter Grehan 	if (mevp->me_type == EVF_TIMER)
166151dba4aSPeter Grehan 		retval = EVFILT_TIMER;
167151dba4aSPeter Grehan 
168058e24d3SJohn Baldwin 	if (mevp->me_type == EVF_SIGNAL)
169058e24d3SJohn Baldwin 		retval = EVFILT_SIGNAL;
170058e24d3SJohn Baldwin 
17167d60dccSJohn Baldwin 	if (mevp->me_type == EVF_VNODE)
17267d60dccSJohn Baldwin 		retval = EVFILT_VNODE;
17367d60dccSJohn Baldwin 
174366f6083SPeter Grehan 	return (retval);
175366f6083SPeter Grehan }
176366f6083SPeter Grehan 
177366f6083SPeter Grehan static int
178366f6083SPeter Grehan mevent_kq_flags(struct mevent *mevp)
179366f6083SPeter Grehan {
1800b29683bSRobert Wing 	int retval;
1810b29683bSRobert Wing 
1820b29683bSRobert Wing 	retval = mevp->me_state;
1830b29683bSRobert Wing 
1840b29683bSRobert Wing 	if (mevp->me_type == EVF_VNODE)
1850b29683bSRobert Wing 		retval |= EV_CLEAR;
1860b29683bSRobert Wing 
1870b29683bSRobert Wing 	return (retval);
188366f6083SPeter Grehan }
189366f6083SPeter Grehan 
190366f6083SPeter Grehan static int
191366f6083SPeter Grehan mevent_kq_fflags(struct mevent *mevp)
192366f6083SPeter Grehan {
19367d60dccSJohn Baldwin 	int retval;
19467d60dccSJohn Baldwin 
19567d60dccSJohn Baldwin 	retval = 0;
19667d60dccSJohn Baldwin 
19767d60dccSJohn Baldwin 	switch (mevp->me_type) {
19867d60dccSJohn Baldwin 	case EVF_VNODE:
19967d60dccSJohn Baldwin 		if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
20067d60dccSJohn Baldwin 			retval |= NOTE_ATTRIB;
20167d60dccSJohn Baldwin 		break;
2027ecdfc82SJohn Baldwin 	case EVF_READ:
2037ecdfc82SJohn Baldwin 	case EVF_WRITE:
2047ecdfc82SJohn Baldwin 	case EVF_TIMER:
2057ecdfc82SJohn Baldwin 	case EVF_SIGNAL:
2067ecdfc82SJohn Baldwin 		break;
20767d60dccSJohn Baldwin 	}
20867d60dccSJohn Baldwin 
20967d60dccSJohn Baldwin 	return (retval);
210366f6083SPeter Grehan }
211366f6083SPeter Grehan 
212e8424e29SJohn Baldwin static void
213e8424e29SJohn Baldwin mevent_populate(struct mevent *mevp, struct kevent *kev)
214e8424e29SJohn Baldwin {
215e8424e29SJohn Baldwin 	if (mevp->me_type == EVF_TIMER) {
216e8424e29SJohn Baldwin 		kev->ident = mevp->me_timid;
217e8424e29SJohn Baldwin 		kev->data = mevp->me_msecs;
218e8424e29SJohn Baldwin 	} else {
219e8424e29SJohn Baldwin 		kev->ident = mevp->me_fd;
220e8424e29SJohn Baldwin 		kev->data = 0;
221e8424e29SJohn Baldwin 	}
222e8424e29SJohn Baldwin 	kev->filter = mevent_kq_filter(mevp);
223e8424e29SJohn Baldwin 	kev->flags = mevent_kq_flags(mevp);
224e8424e29SJohn Baldwin 	kev->fflags = mevent_kq_fflags(mevp);
225e8424e29SJohn Baldwin 	kev->udata = mevp;
226e8424e29SJohn Baldwin }
227e8424e29SJohn Baldwin 
228366f6083SPeter Grehan static int
229e8424e29SJohn Baldwin mevent_build(struct kevent *kev)
230366f6083SPeter Grehan {
231366f6083SPeter Grehan 	struct mevent *mevp, *tmpp;
232366f6083SPeter Grehan 	int i;
233366f6083SPeter Grehan 
234366f6083SPeter Grehan 	i = 0;
235366f6083SPeter Grehan 
236366f6083SPeter Grehan 	mevent_qlock();
237366f6083SPeter Grehan 
238366f6083SPeter Grehan 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
239366f6083SPeter Grehan 		if (mevp->me_closefd) {
240366f6083SPeter Grehan 			/*
241366f6083SPeter Grehan 			 * A close of the file descriptor will remove the
242366f6083SPeter Grehan 			 * event
243366f6083SPeter Grehan 			 */
244366f6083SPeter Grehan 			close(mevp->me_fd);
245366f6083SPeter Grehan 		} else {
246e8424e29SJohn Baldwin 			mevent_populate(mevp, &kev[i]);
247366f6083SPeter Grehan 			i++;
248366f6083SPeter Grehan 		}
249366f6083SPeter Grehan 
250366f6083SPeter Grehan 		mevp->me_cq = 0;
251366f6083SPeter Grehan 		LIST_REMOVE(mevp, me_list);
252366f6083SPeter Grehan 
25307b35f77SVincenzo Maffione 		if (mevp->me_state & EV_DELETE) {
254366f6083SPeter Grehan 			free(mevp);
255366f6083SPeter Grehan 		} else {
256366f6083SPeter Grehan 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
257366f6083SPeter Grehan 		}
258366f6083SPeter Grehan 
259366f6083SPeter Grehan 		assert(i < MEVENT_MAX);
260366f6083SPeter Grehan 	}
261366f6083SPeter Grehan 
262366f6083SPeter Grehan 	mevent_qunlock();
263366f6083SPeter Grehan 
264366f6083SPeter Grehan 	return (i);
265366f6083SPeter Grehan }
266366f6083SPeter Grehan 
267366f6083SPeter Grehan static void
268366f6083SPeter Grehan mevent_handle(struct kevent *kev, int numev)
269366f6083SPeter Grehan {
270366f6083SPeter Grehan 	struct mevent *mevp;
271366f6083SPeter Grehan 	int i;
272366f6083SPeter Grehan 
273366f6083SPeter Grehan 	for (i = 0; i < numev; i++) {
274366f6083SPeter Grehan 		mevp = kev[i].udata;
275366f6083SPeter Grehan 
276366f6083SPeter Grehan 		/* XXX check for EV_ERROR ? */
277366f6083SPeter Grehan 
278366f6083SPeter Grehan 		(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
279366f6083SPeter Grehan 	}
280366f6083SPeter Grehan }
281366f6083SPeter Grehan 
282d12c5ef6SVincenzo Maffione static struct mevent *
283d12c5ef6SVincenzo Maffione mevent_add_state(int tfd, enum ev_type type,
284d12c5ef6SVincenzo Maffione 	   void (*func)(int, enum ev_type, void *), void *param,
28567d60dccSJohn Baldwin 	   int state, int fflags)
286366f6083SPeter Grehan {
287e8424e29SJohn Baldwin 	struct kevent kev;
288366f6083SPeter Grehan 	struct mevent *lp, *mevp;
289e8424e29SJohn Baldwin 	int ret;
290366f6083SPeter Grehan 
291151dba4aSPeter Grehan 	if (tfd < 0 || func == NULL) {
292366f6083SPeter Grehan 		return (NULL);
293366f6083SPeter Grehan 	}
294366f6083SPeter Grehan 
295366f6083SPeter Grehan 	mevp = NULL;
296366f6083SPeter Grehan 
297e8424e29SJohn Baldwin 	pthread_once(&mevent_once, mevent_init);
298e8424e29SJohn Baldwin 
299366f6083SPeter Grehan 	mevent_qlock();
300366f6083SPeter Grehan 
301366f6083SPeter Grehan 	/*
302366f6083SPeter Grehan 	 * Verify that the fd/type tuple is not present in any list
303366f6083SPeter Grehan 	 */
304366f6083SPeter Grehan 	LIST_FOREACH(lp, &global_head, me_list) {
305151dba4aSPeter Grehan 		if (type != EVF_TIMER && lp->me_fd == tfd &&
306151dba4aSPeter Grehan 		    lp->me_type == type) {
307366f6083SPeter Grehan 			goto exit;
308366f6083SPeter Grehan 		}
309366f6083SPeter Grehan 	}
310366f6083SPeter Grehan 
311366f6083SPeter Grehan 	LIST_FOREACH(lp, &change_head, me_list) {
312151dba4aSPeter Grehan 		if (type != EVF_TIMER && lp->me_fd == tfd &&
313151dba4aSPeter Grehan 		    lp->me_type == type) {
314366f6083SPeter Grehan 			goto exit;
315366f6083SPeter Grehan 		}
316366f6083SPeter Grehan 	}
317366f6083SPeter Grehan 
318366f6083SPeter Grehan 	/*
319e8424e29SJohn Baldwin 	 * Allocate an entry and populate it.
320366f6083SPeter Grehan 	 */
321994f858aSXin LI 	mevp = calloc(1, sizeof(struct mevent));
322366f6083SPeter Grehan 	if (mevp == NULL) {
323366f6083SPeter Grehan 		goto exit;
324366f6083SPeter Grehan 	}
325366f6083SPeter Grehan 
326151dba4aSPeter Grehan 	if (type == EVF_TIMER) {
327151dba4aSPeter Grehan 		mevp->me_msecs = tfd;
328151dba4aSPeter Grehan 		mevp->me_timid = mevent_timid++;
329151dba4aSPeter Grehan 	} else
330151dba4aSPeter Grehan 		mevp->me_fd = tfd;
331366f6083SPeter Grehan 	mevp->me_type = type;
332366f6083SPeter Grehan 	mevp->me_func = func;
333366f6083SPeter Grehan 	mevp->me_param = param;
334d12c5ef6SVincenzo Maffione 	mevp->me_state = state;
33567d60dccSJohn Baldwin 	mevp->me_fflags = fflags;
336e8424e29SJohn Baldwin 
337e8424e29SJohn Baldwin 	/*
338e8424e29SJohn Baldwin 	 * Try to add the event.  If this fails, report the failure to
339e8424e29SJohn Baldwin 	 * the caller.
340e8424e29SJohn Baldwin 	 */
341e8424e29SJohn Baldwin 	mevent_populate(mevp, &kev);
342e8424e29SJohn Baldwin 	ret = kevent(mfd, &kev, 1, NULL, 0, NULL);
343e8424e29SJohn Baldwin 	if (ret == -1) {
344e8424e29SJohn Baldwin 		free(mevp);
345e8424e29SJohn Baldwin 		mevp = NULL;
346e8424e29SJohn Baldwin 		goto exit;
347e8424e29SJohn Baldwin 	}
348e8424e29SJohn Baldwin 
349e8424e29SJohn Baldwin 	mevp->me_state &= ~EV_ADD;
350e8424e29SJohn Baldwin 	LIST_INSERT_HEAD(&global_head, mevp, me_list);
351366f6083SPeter Grehan 
352366f6083SPeter Grehan exit:
353366f6083SPeter Grehan 	mevent_qunlock();
354366f6083SPeter Grehan 
355366f6083SPeter Grehan 	return (mevp);
356366f6083SPeter Grehan }
357366f6083SPeter Grehan 
358d12c5ef6SVincenzo Maffione struct mevent *
359d12c5ef6SVincenzo Maffione mevent_add(int tfd, enum ev_type type,
360d12c5ef6SVincenzo Maffione 	   void (*func)(int, enum ev_type, void *), void *param)
361d12c5ef6SVincenzo Maffione {
362d12c5ef6SVincenzo Maffione 
36367d60dccSJohn Baldwin 	return (mevent_add_state(tfd, type, func, param, EV_ADD, 0));
36467d60dccSJohn Baldwin }
36567d60dccSJohn Baldwin 
36667d60dccSJohn Baldwin struct mevent *
36767d60dccSJohn Baldwin mevent_add_flags(int tfd, enum ev_type type, int fflags,
36867d60dccSJohn Baldwin 		 void (*func)(int, enum ev_type, void *), void *param)
36967d60dccSJohn Baldwin {
37067d60dccSJohn Baldwin 
37167d60dccSJohn Baldwin 	return (mevent_add_state(tfd, type, func, param, EV_ADD, fflags));
372d12c5ef6SVincenzo Maffione }
373d12c5ef6SVincenzo Maffione 
3743e11768eSVincenzo Maffione struct mevent *
3753e11768eSVincenzo Maffione mevent_add_disabled(int tfd, enum ev_type type,
3763e11768eSVincenzo Maffione 		    void (*func)(int, enum ev_type, void *), void *param)
3773e11768eSVincenzo Maffione {
3783e11768eSVincenzo Maffione 
37967d60dccSJohn Baldwin 	return (mevent_add_state(tfd, type, func, param, EV_ADD | EV_DISABLE, 0));
3803e11768eSVincenzo Maffione }
3813e11768eSVincenzo Maffione 
382366f6083SPeter Grehan static int
383*4dfa329fSJessica Clarke mevent_update(struct mevent *evp, enum mevent_update_type type, int msecs)
384366f6083SPeter Grehan {
38507b35f77SVincenzo Maffione 	int newstate;
38607b35f77SVincenzo Maffione 
38707b35f77SVincenzo Maffione 	mevent_qlock();
38807b35f77SVincenzo Maffione 
389366f6083SPeter Grehan 	/*
390*4dfa329fSJessica Clarke 	 * It's not possible to update a deleted event
391366f6083SPeter Grehan 	 */
39207b35f77SVincenzo Maffione 	assert((evp->me_state & EV_DELETE) == 0);
39307b35f77SVincenzo Maffione 
39407b35f77SVincenzo Maffione 	newstate = evp->me_state;
395*4dfa329fSJessica Clarke 	if (type == UPDATE_ENABLE) {
39607b35f77SVincenzo Maffione 		newstate |= EV_ENABLE;
39707b35f77SVincenzo Maffione 		newstate &= ~EV_DISABLE;
398*4dfa329fSJessica Clarke 	} else if (type == UPDATE_DISABLE) {
39907b35f77SVincenzo Maffione 		newstate |= EV_DISABLE;
40007b35f77SVincenzo Maffione 		newstate &= ~EV_ENABLE;
401*4dfa329fSJessica Clarke 	} else {
402*4dfa329fSJessica Clarke 		assert(type == UPDATE_TIMER);
403*4dfa329fSJessica Clarke 		assert(evp->me_type == EVF_TIMER);
404*4dfa329fSJessica Clarke 		newstate |= EV_ADD;
405*4dfa329fSJessica Clarke 		evp->me_msecs = msecs;
40607b35f77SVincenzo Maffione 	}
407366f6083SPeter Grehan 
408366f6083SPeter Grehan 	/*
409*4dfa329fSJessica Clarke 	 * No update needed if enable/disable had no effect
410366f6083SPeter Grehan 	 */
411*4dfa329fSJessica Clarke 	if (evp->me_state != newstate || type == UPDATE_TIMER) {
412366f6083SPeter Grehan 		evp->me_state = newstate;
413366f6083SPeter Grehan 
414366f6083SPeter Grehan 		/*
41507b35f77SVincenzo Maffione 		 * Place the entry onto the changed list if not
41607b35f77SVincenzo Maffione 		 * already there.
417366f6083SPeter Grehan 		 */
418366f6083SPeter Grehan 		if (evp->me_cq == 0) {
419366f6083SPeter Grehan 			evp->me_cq = 1;
420366f6083SPeter Grehan 			LIST_REMOVE(evp, me_list);
421366f6083SPeter Grehan 			LIST_INSERT_HEAD(&change_head, evp, me_list);
422366f6083SPeter Grehan 			mevent_notify();
423366f6083SPeter Grehan 		}
42407b35f77SVincenzo Maffione 	}
425366f6083SPeter Grehan 
426366f6083SPeter Grehan 	mevent_qunlock();
427366f6083SPeter Grehan 
428366f6083SPeter Grehan 	return (0);
429366f6083SPeter Grehan }
430366f6083SPeter Grehan 
431366f6083SPeter Grehan int
432366f6083SPeter Grehan mevent_enable(struct mevent *evp)
433366f6083SPeter Grehan {
434*4dfa329fSJessica Clarke 	return (mevent_update(evp, UPDATE_ENABLE, -1));
435366f6083SPeter Grehan }
436366f6083SPeter Grehan 
437366f6083SPeter Grehan int
438366f6083SPeter Grehan mevent_disable(struct mevent *evp)
439366f6083SPeter Grehan {
440*4dfa329fSJessica Clarke 	return (mevent_update(evp, UPDATE_DISABLE, -1));
441*4dfa329fSJessica Clarke }
442366f6083SPeter Grehan 
443*4dfa329fSJessica Clarke int
444*4dfa329fSJessica Clarke mevent_timer_update(struct mevent *evp, int msecs)
445*4dfa329fSJessica Clarke {
446*4dfa329fSJessica Clarke 	return (mevent_update(evp, UPDATE_TIMER, msecs));
447366f6083SPeter Grehan }
448366f6083SPeter Grehan 
449366f6083SPeter Grehan static int
450366f6083SPeter Grehan mevent_delete_event(struct mevent *evp, int closefd)
451366f6083SPeter Grehan {
452366f6083SPeter Grehan 	mevent_qlock();
453366f6083SPeter Grehan 
454366f6083SPeter Grehan 	/*
455366f6083SPeter Grehan          * Place the entry onto the changed list if not already there, and
456366f6083SPeter Grehan 	 * mark as to be deleted.
457366f6083SPeter Grehan          */
458366f6083SPeter Grehan         if (evp->me_cq == 0) {
459366f6083SPeter Grehan 		evp->me_cq = 1;
460366f6083SPeter Grehan 		LIST_REMOVE(evp, me_list);
461366f6083SPeter Grehan 		LIST_INSERT_HEAD(&change_head, evp, me_list);
462366f6083SPeter Grehan 		mevent_notify();
463366f6083SPeter Grehan         }
46407b35f77SVincenzo Maffione 	evp->me_state = EV_DELETE;
465366f6083SPeter Grehan 
466366f6083SPeter Grehan 	if (closefd)
467366f6083SPeter Grehan 		evp->me_closefd = 1;
468366f6083SPeter Grehan 
469366f6083SPeter Grehan 	mevent_qunlock();
470366f6083SPeter Grehan 
471366f6083SPeter Grehan 	return (0);
472366f6083SPeter Grehan }
473366f6083SPeter Grehan 
474366f6083SPeter Grehan int
475366f6083SPeter Grehan mevent_delete(struct mevent *evp)
476366f6083SPeter Grehan {
477366f6083SPeter Grehan 
478366f6083SPeter Grehan 	return (mevent_delete_event(evp, 0));
479366f6083SPeter Grehan }
480366f6083SPeter Grehan 
481366f6083SPeter Grehan int
482366f6083SPeter Grehan mevent_delete_close(struct mevent *evp)
483366f6083SPeter Grehan {
484366f6083SPeter Grehan 
485366f6083SPeter Grehan 	return (mevent_delete_event(evp, 1));
486366f6083SPeter Grehan }
487366f6083SPeter Grehan 
4884e8c7465SPeter Grehan static void
4894e8c7465SPeter Grehan mevent_set_name(void)
4904e8c7465SPeter Grehan {
4914e8c7465SPeter Grehan 
4927f5487acSPeter Grehan 	pthread_set_name_np(mevent_tid, "mevent");
4934e8c7465SPeter Grehan }
4944e8c7465SPeter Grehan 
495366f6083SPeter Grehan void
496366f6083SPeter Grehan mevent_dispatch(void)
497366f6083SPeter Grehan {
498366f6083SPeter Grehan 	struct kevent changelist[MEVENT_MAX];
499366f6083SPeter Grehan 	struct kevent eventlist[MEVENT_MAX];
500366f6083SPeter Grehan 	struct mevent *pipev;
501366f6083SPeter Grehan 	int numev;
502366f6083SPeter Grehan 	int ret;
50300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
50400ef17beSBartek Rutkowski 	cap_rights_t rights;
50500ef17beSBartek Rutkowski #endif
506366f6083SPeter Grehan 
507366f6083SPeter Grehan 	mevent_tid = pthread_self();
5084e8c7465SPeter Grehan 	mevent_set_name();
509366f6083SPeter Grehan 
510e8424e29SJohn Baldwin 	pthread_once(&mevent_once, mevent_init);
51100ef17beSBartek Rutkowski 
512366f6083SPeter Grehan 	/*
513366f6083SPeter Grehan 	 * Open the pipe that will be used for other threads to force
514366f6083SPeter Grehan 	 * the blocking kqueue call to exit by writing to it. Set the
515366f6083SPeter Grehan 	 * descriptor to non-blocking.
516366f6083SPeter Grehan 	 */
517366f6083SPeter Grehan 	ret = pipe(mevent_pipefd);
518366f6083SPeter Grehan 	if (ret < 0) {
519366f6083SPeter Grehan 		perror("pipe");
520366f6083SPeter Grehan 		exit(0);
521366f6083SPeter Grehan 	}
522366f6083SPeter Grehan 
52300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
52400ef17beSBartek Rutkowski 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
525abfa3c39SMarcelo Araujo 	if (caph_rights_limit(mevent_pipefd[0], &rights) == -1)
52600ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
527abfa3c39SMarcelo Araujo 	if (caph_rights_limit(mevent_pipefd[1], &rights) == -1)
52800ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
52900ef17beSBartek Rutkowski #endif
53000ef17beSBartek Rutkowski 
531366f6083SPeter Grehan 	/*
532366f6083SPeter Grehan 	 * Add internal event handler for the pipe write fd
533366f6083SPeter Grehan 	 */
534366f6083SPeter Grehan 	pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL);
535366f6083SPeter Grehan 	assert(pipev != NULL);
536366f6083SPeter Grehan 
537366f6083SPeter Grehan 	for (;;) {
538366f6083SPeter Grehan 		/*
539366f6083SPeter Grehan 		 * Build changelist if required.
540366f6083SPeter Grehan 		 * XXX the changelist can be put into the blocking call
541366f6083SPeter Grehan 		 * to eliminate the extra syscall. Currently better for
542366f6083SPeter Grehan 		 * debug.
543366f6083SPeter Grehan 		 */
544e8424e29SJohn Baldwin 		numev = mevent_build(changelist);
545366f6083SPeter Grehan 		if (numev) {
546366f6083SPeter Grehan 			ret = kevent(mfd, changelist, numev, NULL, 0, NULL);
547366f6083SPeter Grehan 			if (ret == -1) {
548366f6083SPeter Grehan 				perror("Error return from kevent change");
549366f6083SPeter Grehan 			}
550366f6083SPeter Grehan 		}
551366f6083SPeter Grehan 
552366f6083SPeter Grehan 		/*
553366f6083SPeter Grehan 		 * Block awaiting events
554366f6083SPeter Grehan 		 */
555366f6083SPeter Grehan 		ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);
556058e24d3SJohn Baldwin 		if (ret == -1 && errno != EINTR) {
557366f6083SPeter Grehan 			perror("Error return from kevent monitor");
558366f6083SPeter Grehan 		}
559366f6083SPeter Grehan 
560366f6083SPeter Grehan 		/*
561366f6083SPeter Grehan 		 * Handle reported events
562366f6083SPeter Grehan 		 */
563366f6083SPeter Grehan 		mevent_handle(eventlist, ret);
564366f6083SPeter Grehan 	}
565366f6083SPeter Grehan }
566