xref: /illumos-gate/usr/src/cmd/bhyve/mevent.c (revision 4c87aefe)
1*4c87aefeSPatrick Mooney /*-
2*4c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*4c87aefeSPatrick Mooney  *
4*4c87aefeSPatrick Mooney  * Copyright (c) 2011 NetApp, Inc.
5*4c87aefeSPatrick Mooney  * All rights reserved.
6*4c87aefeSPatrick Mooney  *
7*4c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
8*4c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
9*4c87aefeSPatrick Mooney  * are met:
10*4c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
11*4c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
12*4c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
13*4c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
14*4c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
15*4c87aefeSPatrick Mooney  *
16*4c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17*4c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20*4c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*4c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*4c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*4c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*4c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*4c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*4c87aefeSPatrick Mooney  * SUCH DAMAGE.
27*4c87aefeSPatrick Mooney  *
28*4c87aefeSPatrick Mooney  * $FreeBSD$
29*4c87aefeSPatrick Mooney  */
30*4c87aefeSPatrick Mooney 
31*4c87aefeSPatrick Mooney /*
32*4c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
33*4c87aefeSPatrick Mooney  */
34*4c87aefeSPatrick Mooney 
35*4c87aefeSPatrick Mooney /*
36*4c87aefeSPatrick Mooney  * Micro event library for FreeBSD, designed for a single i/o thread
37*4c87aefeSPatrick Mooney  * using kqueue, and having events be persistent by default.
38*4c87aefeSPatrick Mooney  */
39*4c87aefeSPatrick Mooney 
40*4c87aefeSPatrick Mooney #include <sys/cdefs.h>
41*4c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
42*4c87aefeSPatrick Mooney 
43*4c87aefeSPatrick Mooney #include <assert.h>
44*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
45*4c87aefeSPatrick Mooney #include <capsicum_helpers.h>
46*4c87aefeSPatrick Mooney #endif
47*4c87aefeSPatrick Mooney #include <err.h>
48*4c87aefeSPatrick Mooney #include <errno.h>
49*4c87aefeSPatrick Mooney #include <stdlib.h>
50*4c87aefeSPatrick Mooney #include <stdio.h>
51*4c87aefeSPatrick Mooney #include <string.h>
52*4c87aefeSPatrick Mooney #include <sysexits.h>
53*4c87aefeSPatrick Mooney #include <unistd.h>
54*4c87aefeSPatrick Mooney 
55*4c87aefeSPatrick Mooney #include <sys/types.h>
56*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
57*4c87aefeSPatrick Mooney #include <sys/capsicum.h>
58*4c87aefeSPatrick Mooney #endif
59*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
60*4c87aefeSPatrick Mooney #include <sys/event.h>
61*4c87aefeSPatrick Mooney #else
62*4c87aefeSPatrick Mooney #include <port.h>
63*4c87aefeSPatrick Mooney #include <sys/poll.h>
64*4c87aefeSPatrick Mooney #include <sys/siginfo.h>
65*4c87aefeSPatrick Mooney #include <sys/queue.h>
66*4c87aefeSPatrick Mooney #endif
67*4c87aefeSPatrick Mooney #include <sys/time.h>
68*4c87aefeSPatrick Mooney 
69*4c87aefeSPatrick Mooney #include <pthread.h>
70*4c87aefeSPatrick Mooney #include <pthread_np.h>
71*4c87aefeSPatrick Mooney 
72*4c87aefeSPatrick Mooney #include "mevent.h"
73*4c87aefeSPatrick Mooney 
74*4c87aefeSPatrick Mooney #define	MEVENT_MAX	64
75*4c87aefeSPatrick Mooney 
76*4c87aefeSPatrick Mooney #define	MEV_ADD		1
77*4c87aefeSPatrick Mooney #define	MEV_ENABLE	2
78*4c87aefeSPatrick Mooney #define	MEV_DISABLE	3
79*4c87aefeSPatrick Mooney #define	MEV_DEL_PENDING	4
80*4c87aefeSPatrick Mooney 
81*4c87aefeSPatrick Mooney extern char *vmname;
82*4c87aefeSPatrick Mooney 
83*4c87aefeSPatrick Mooney static pthread_t mevent_tid;
84*4c87aefeSPatrick Mooney static int mevent_timid = 43;
85*4c87aefeSPatrick Mooney static int mevent_pipefd[2];
86*4c87aefeSPatrick Mooney static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
87*4c87aefeSPatrick Mooney 
88*4c87aefeSPatrick Mooney struct mevent {
89*4c87aefeSPatrick Mooney 	void	(*me_func)(int, enum ev_type, void *);
90*4c87aefeSPatrick Mooney #define me_msecs me_fd
91*4c87aefeSPatrick Mooney 	int	me_fd;
92*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
93*4c87aefeSPatrick Mooney 	int	me_timid;
94*4c87aefeSPatrick Mooney #else
95*4c87aefeSPatrick Mooney 	timer_t me_timid;
96*4c87aefeSPatrick Mooney #endif
97*4c87aefeSPatrick Mooney 	enum ev_type me_type;
98*4c87aefeSPatrick Mooney 	void    *me_param;
99*4c87aefeSPatrick Mooney 	int	me_cq;
100*4c87aefeSPatrick Mooney 	int	me_state;
101*4c87aefeSPatrick Mooney 	int	me_closefd;
102*4c87aefeSPatrick Mooney #ifndef __FreeBSD__
103*4c87aefeSPatrick Mooney 	port_notify_t	me_notify;
104*4c87aefeSPatrick Mooney 	struct sigevent	me_sigev;
105*4c87aefeSPatrick Mooney 	boolean_t	me_auto_requeue;
106*4c87aefeSPatrick Mooney #endif
107*4c87aefeSPatrick Mooney 	LIST_ENTRY(mevent) me_list;
108*4c87aefeSPatrick Mooney };
109*4c87aefeSPatrick Mooney 
110*4c87aefeSPatrick Mooney static LIST_HEAD(listhead, mevent) global_head, change_head;
111*4c87aefeSPatrick Mooney 
112*4c87aefeSPatrick Mooney static void
113*4c87aefeSPatrick Mooney mevent_qlock(void)
114*4c87aefeSPatrick Mooney {
115*4c87aefeSPatrick Mooney 	pthread_mutex_lock(&mevent_lmutex);
116*4c87aefeSPatrick Mooney }
117*4c87aefeSPatrick Mooney 
118*4c87aefeSPatrick Mooney static void
119*4c87aefeSPatrick Mooney mevent_qunlock(void)
120*4c87aefeSPatrick Mooney {
121*4c87aefeSPatrick Mooney 	pthread_mutex_unlock(&mevent_lmutex);
122*4c87aefeSPatrick Mooney }
123*4c87aefeSPatrick Mooney 
124*4c87aefeSPatrick Mooney static void
125*4c87aefeSPatrick Mooney mevent_pipe_read(int fd, enum ev_type type, void *param)
126*4c87aefeSPatrick Mooney {
127*4c87aefeSPatrick Mooney 	char buf[MEVENT_MAX];
128*4c87aefeSPatrick Mooney 	int status;
129*4c87aefeSPatrick Mooney 
130*4c87aefeSPatrick Mooney 	/*
131*4c87aefeSPatrick Mooney 	 * Drain the pipe read side. The fd is non-blocking so this is
132*4c87aefeSPatrick Mooney 	 * safe to do.
133*4c87aefeSPatrick Mooney 	 */
134*4c87aefeSPatrick Mooney 	do {
135*4c87aefeSPatrick Mooney 		status = read(fd, buf, sizeof(buf));
136*4c87aefeSPatrick Mooney 	} while (status == MEVENT_MAX);
137*4c87aefeSPatrick Mooney }
138*4c87aefeSPatrick Mooney 
139*4c87aefeSPatrick Mooney static void
140*4c87aefeSPatrick Mooney mevent_notify(void)
141*4c87aefeSPatrick Mooney {
142*4c87aefeSPatrick Mooney 	char c;
143*4c87aefeSPatrick Mooney 
144*4c87aefeSPatrick Mooney 	/*
145*4c87aefeSPatrick Mooney 	 * If calling from outside the i/o thread, write a byte on the
146*4c87aefeSPatrick Mooney 	 * pipe to force the i/o thread to exit the blocking kevent call.
147*4c87aefeSPatrick Mooney 	 */
148*4c87aefeSPatrick Mooney 	if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) {
149*4c87aefeSPatrick Mooney 		write(mevent_pipefd[1], &c, 1);
150*4c87aefeSPatrick Mooney 	}
151*4c87aefeSPatrick Mooney }
152*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
153*4c87aefeSPatrick Mooney static int
154*4c87aefeSPatrick Mooney mevent_kq_filter(struct mevent *mevp)
155*4c87aefeSPatrick Mooney {
156*4c87aefeSPatrick Mooney 	int retval;
157*4c87aefeSPatrick Mooney 
158*4c87aefeSPatrick Mooney 	retval = 0;
159*4c87aefeSPatrick Mooney 
160*4c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_READ)
161*4c87aefeSPatrick Mooney 		retval = EVFILT_READ;
162*4c87aefeSPatrick Mooney 
163*4c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_WRITE)
164*4c87aefeSPatrick Mooney 		retval = EVFILT_WRITE;
165*4c87aefeSPatrick Mooney 
166*4c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_TIMER)
167*4c87aefeSPatrick Mooney 		retval = EVFILT_TIMER;
168*4c87aefeSPatrick Mooney 
169*4c87aefeSPatrick Mooney 	if (mevp->me_type == EVF_SIGNAL)
170*4c87aefeSPatrick Mooney 		retval = EVFILT_SIGNAL;
171*4c87aefeSPatrick Mooney 
172*4c87aefeSPatrick Mooney 	return (retval);
173*4c87aefeSPatrick Mooney }
174*4c87aefeSPatrick Mooney 
175*4c87aefeSPatrick Mooney static int
176*4c87aefeSPatrick Mooney mevent_kq_flags(struct mevent *mevp)
177*4c87aefeSPatrick Mooney {
178*4c87aefeSPatrick Mooney 	int ret;
179*4c87aefeSPatrick Mooney 
180*4c87aefeSPatrick Mooney 	switch (mevp->me_state) {
181*4c87aefeSPatrick Mooney 	case MEV_ADD:
182*4c87aefeSPatrick Mooney 		ret = EV_ADD;		/* implicitly enabled */
183*4c87aefeSPatrick Mooney 		break;
184*4c87aefeSPatrick Mooney 	case MEV_ENABLE:
185*4c87aefeSPatrick Mooney 		ret = EV_ENABLE;
186*4c87aefeSPatrick Mooney 		break;
187*4c87aefeSPatrick Mooney 	case MEV_DISABLE:
188*4c87aefeSPatrick Mooney 		ret = EV_DISABLE;
189*4c87aefeSPatrick Mooney 		break;
190*4c87aefeSPatrick Mooney 	case MEV_DEL_PENDING:
191*4c87aefeSPatrick Mooney 		ret = EV_DELETE;
192*4c87aefeSPatrick Mooney 		break;
193*4c87aefeSPatrick Mooney 	default:
194*4c87aefeSPatrick Mooney 		assert(0);
195*4c87aefeSPatrick Mooney 		break;
196*4c87aefeSPatrick Mooney 	}
197*4c87aefeSPatrick Mooney 
198*4c87aefeSPatrick Mooney 	return (ret);
199*4c87aefeSPatrick Mooney }
200*4c87aefeSPatrick Mooney 
201*4c87aefeSPatrick Mooney static int
202*4c87aefeSPatrick Mooney mevent_kq_fflags(struct mevent *mevp)
203*4c87aefeSPatrick Mooney {
204*4c87aefeSPatrick Mooney 	/* XXX nothing yet, perhaps EV_EOF for reads ? */
205*4c87aefeSPatrick Mooney 	return (0);
206*4c87aefeSPatrick Mooney }
207*4c87aefeSPatrick Mooney 
208*4c87aefeSPatrick Mooney static int
209*4c87aefeSPatrick Mooney mevent_build(int mfd, struct kevent *kev)
210*4c87aefeSPatrick Mooney {
211*4c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
212*4c87aefeSPatrick Mooney 	int i;
213*4c87aefeSPatrick Mooney 
214*4c87aefeSPatrick Mooney 	i = 0;
215*4c87aefeSPatrick Mooney 
216*4c87aefeSPatrick Mooney 	mevent_qlock();
217*4c87aefeSPatrick Mooney 
218*4c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
219*4c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
220*4c87aefeSPatrick Mooney 			/*
221*4c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
222*4c87aefeSPatrick Mooney 			 * event
223*4c87aefeSPatrick Mooney 			 */
224*4c87aefeSPatrick Mooney 			close(mevp->me_fd);
225*4c87aefeSPatrick Mooney 		} else {
226*4c87aefeSPatrick Mooney 			if (mevp->me_type == EVF_TIMER) {
227*4c87aefeSPatrick Mooney 				kev[i].ident = mevp->me_timid;
228*4c87aefeSPatrick Mooney 				kev[i].data = mevp->me_msecs;
229*4c87aefeSPatrick Mooney 			} else {
230*4c87aefeSPatrick Mooney 				kev[i].ident = mevp->me_fd;
231*4c87aefeSPatrick Mooney 				kev[i].data = 0;
232*4c87aefeSPatrick Mooney 			}
233*4c87aefeSPatrick Mooney 			kev[i].filter = mevent_kq_filter(mevp);
234*4c87aefeSPatrick Mooney 			kev[i].flags = mevent_kq_flags(mevp);
235*4c87aefeSPatrick Mooney 			kev[i].fflags = mevent_kq_fflags(mevp);
236*4c87aefeSPatrick Mooney 			kev[i].udata = mevp;
237*4c87aefeSPatrick Mooney 			i++;
238*4c87aefeSPatrick Mooney 		}
239*4c87aefeSPatrick Mooney 
240*4c87aefeSPatrick Mooney 		mevp->me_cq = 0;
241*4c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
242*4c87aefeSPatrick Mooney 
243*4c87aefeSPatrick Mooney 		if (mevp->me_state == MEV_DEL_PENDING) {
244*4c87aefeSPatrick Mooney 			free(mevp);
245*4c87aefeSPatrick Mooney 		} else {
246*4c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
247*4c87aefeSPatrick Mooney 		}
248*4c87aefeSPatrick Mooney 
249*4c87aefeSPatrick Mooney 		assert(i < MEVENT_MAX);
250*4c87aefeSPatrick Mooney 	}
251*4c87aefeSPatrick Mooney 
252*4c87aefeSPatrick Mooney 	mevent_qunlock();
253*4c87aefeSPatrick Mooney 
254*4c87aefeSPatrick Mooney 	return (i);
255*4c87aefeSPatrick Mooney }
256*4c87aefeSPatrick Mooney 
257*4c87aefeSPatrick Mooney static void
258*4c87aefeSPatrick Mooney mevent_handle(struct kevent *kev, int numev)
259*4c87aefeSPatrick Mooney {
260*4c87aefeSPatrick Mooney 	struct mevent *mevp;
261*4c87aefeSPatrick Mooney 	int i;
262*4c87aefeSPatrick Mooney 
263*4c87aefeSPatrick Mooney 	for (i = 0; i < numev; i++) {
264*4c87aefeSPatrick Mooney 		mevp = kev[i].udata;
265*4c87aefeSPatrick Mooney 
266*4c87aefeSPatrick Mooney 		/* XXX check for EV_ERROR ? */
267*4c87aefeSPatrick Mooney 
268*4c87aefeSPatrick Mooney 		(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
269*4c87aefeSPatrick Mooney 	}
270*4c87aefeSPatrick Mooney }
271*4c87aefeSPatrick Mooney 
272*4c87aefeSPatrick Mooney #else /* __FreeBSD__ */
273*4c87aefeSPatrick Mooney 
274*4c87aefeSPatrick Mooney static void
275*4c87aefeSPatrick Mooney mevent_update_one(struct mevent *mevp)
276*4c87aefeSPatrick Mooney {
277*4c87aefeSPatrick Mooney 	int portfd = mevp->me_notify.portnfy_port;
278*4c87aefeSPatrick Mooney 
279*4c87aefeSPatrick Mooney 	switch (mevp->me_type) {
280*4c87aefeSPatrick Mooney 	case EVF_READ:
281*4c87aefeSPatrick Mooney 	case EVF_WRITE:
282*4c87aefeSPatrick Mooney 		mevp->me_auto_requeue = B_FALSE;
283*4c87aefeSPatrick Mooney 
284*4c87aefeSPatrick Mooney 		switch (mevp->me_state) {
285*4c87aefeSPatrick Mooney 		case MEV_ADD:
286*4c87aefeSPatrick Mooney 		case MEV_ENABLE:
287*4c87aefeSPatrick Mooney 		{
288*4c87aefeSPatrick Mooney 			int events;
289*4c87aefeSPatrick Mooney 
290*4c87aefeSPatrick Mooney 			events = (mevp->me_type == EVF_READ) ? POLLIN : POLLOUT;
291*4c87aefeSPatrick Mooney 
292*4c87aefeSPatrick Mooney 			if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd,
293*4c87aefeSPatrick Mooney 			    events, mevp) != 0) {
294*4c87aefeSPatrick Mooney 				(void) fprintf(stderr,
295*4c87aefeSPatrick Mooney 				    "port_associate fd %d %p failed: %s\n",
296*4c87aefeSPatrick Mooney 				    mevp->me_fd, mevp, strerror(errno));
297*4c87aefeSPatrick Mooney 			}
298*4c87aefeSPatrick Mooney 			return;
299*4c87aefeSPatrick Mooney 		}
300*4c87aefeSPatrick Mooney 		case MEV_DISABLE:
301*4c87aefeSPatrick Mooney 		case MEV_DEL_PENDING:
302*4c87aefeSPatrick Mooney 			/*
303*4c87aefeSPatrick Mooney 			 * A disable that comes in while an event is being
304*4c87aefeSPatrick Mooney 			 * handled will result in an ENOENT.
305*4c87aefeSPatrick Mooney 			 */
306*4c87aefeSPatrick Mooney 			if (port_dissociate(portfd, PORT_SOURCE_FD,
307*4c87aefeSPatrick Mooney 			    mevp->me_fd) != 0 && errno != ENOENT) {
308*4c87aefeSPatrick Mooney 				(void) fprintf(stderr, "port_dissociate "
309*4c87aefeSPatrick Mooney 				    "portfd %d fd %d mevp %p failed: %s\n",
310*4c87aefeSPatrick Mooney 				    portfd, mevp->me_fd, mevp, strerror(errno));
311*4c87aefeSPatrick Mooney 			}
312*4c87aefeSPatrick Mooney 			return;
313*4c87aefeSPatrick Mooney 		default:
314*4c87aefeSPatrick Mooney 			goto abort;
315*4c87aefeSPatrick Mooney 		}
316*4c87aefeSPatrick Mooney 
317*4c87aefeSPatrick Mooney 	case EVF_TIMER:
318*4c87aefeSPatrick Mooney 		mevp->me_auto_requeue = B_TRUE;
319*4c87aefeSPatrick Mooney 
320*4c87aefeSPatrick Mooney 		switch (mevp->me_state) {
321*4c87aefeSPatrick Mooney 		case MEV_ADD:
322*4c87aefeSPatrick Mooney 		case MEV_ENABLE:
323*4c87aefeSPatrick Mooney 		{
324*4c87aefeSPatrick Mooney 			struct itimerspec it = { 0 };
325*4c87aefeSPatrick Mooney 
326*4c87aefeSPatrick Mooney 			mevp->me_sigev.sigev_notify = SIGEV_PORT;
327*4c87aefeSPatrick Mooney 			mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify;
328*4c87aefeSPatrick Mooney 
329*4c87aefeSPatrick Mooney 			if (timer_create(CLOCK_REALTIME, &mevp->me_sigev,
330*4c87aefeSPatrick Mooney 			    &mevp->me_timid) != 0) {
331*4c87aefeSPatrick Mooney 				(void) fprintf(stderr,
332*4c87aefeSPatrick Mooney 				    "timer_create failed: %s", strerror(errno));
333*4c87aefeSPatrick Mooney 				return;
334*4c87aefeSPatrick Mooney 			}
335*4c87aefeSPatrick Mooney 
336*4c87aefeSPatrick Mooney 			/* The first timeout */
337*4c87aefeSPatrick Mooney 			it.it_value.tv_sec = mevp->me_msecs / MILLISEC;
338*4c87aefeSPatrick Mooney 			it.it_value.tv_nsec =
339*4c87aefeSPatrick Mooney 				MSEC2NSEC(mevp->me_msecs % MILLISEC);
340*4c87aefeSPatrick Mooney 			/* Repeat at the same interval */
341*4c87aefeSPatrick Mooney 			it.it_interval = it.it_value;
342*4c87aefeSPatrick Mooney 
343*4c87aefeSPatrick Mooney 			if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) {
344*4c87aefeSPatrick Mooney 				(void) fprintf(stderr, "timer_settime failed: "
345*4c87aefeSPatrick Mooney 				    "%s", strerror(errno));
346*4c87aefeSPatrick Mooney 			}
347*4c87aefeSPatrick Mooney 			return;
348*4c87aefeSPatrick Mooney 		}
349*4c87aefeSPatrick Mooney 		case MEV_DISABLE:
350*4c87aefeSPatrick Mooney 		case MEV_DEL_PENDING:
351*4c87aefeSPatrick Mooney 			if (timer_delete(mevp->me_timid) != 0) {
352*4c87aefeSPatrick Mooney 				(void) fprintf(stderr, "timer_delete failed: "
353*4c87aefeSPatrick Mooney 				    "%s", strerror(errno));
354*4c87aefeSPatrick Mooney 			}
355*4c87aefeSPatrick Mooney 			return;
356*4c87aefeSPatrick Mooney 		default:
357*4c87aefeSPatrick Mooney 			goto abort;
358*4c87aefeSPatrick Mooney 		}
359*4c87aefeSPatrick Mooney 	default:
360*4c87aefeSPatrick Mooney 		/* EVF_SIGNAL not yet implemented. */
361*4c87aefeSPatrick Mooney 		goto abort;
362*4c87aefeSPatrick Mooney 	}
363*4c87aefeSPatrick Mooney 
364*4c87aefeSPatrick Mooney abort:
365*4c87aefeSPatrick Mooney 	(void) fprintf(stderr, "%s: unhandled type %d state %d\n", __func__,
366*4c87aefeSPatrick Mooney 	    mevp->me_type, mevp->me_state);
367*4c87aefeSPatrick Mooney 	abort();
368*4c87aefeSPatrick Mooney }
369*4c87aefeSPatrick Mooney 
370*4c87aefeSPatrick Mooney static void
371*4c87aefeSPatrick Mooney mevent_update_pending(int portfd)
372*4c87aefeSPatrick Mooney {
373*4c87aefeSPatrick Mooney 	struct mevent *mevp, *tmpp;
374*4c87aefeSPatrick Mooney 
375*4c87aefeSPatrick Mooney 	mevent_qlock();
376*4c87aefeSPatrick Mooney 
377*4c87aefeSPatrick Mooney 	LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {
378*4c87aefeSPatrick Mooney 		mevp->me_notify.portnfy_port = portfd;
379*4c87aefeSPatrick Mooney 		mevp->me_notify.portnfy_user = mevp;
380*4c87aefeSPatrick Mooney 		if (mevp->me_closefd) {
381*4c87aefeSPatrick Mooney 			/*
382*4c87aefeSPatrick Mooney 			 * A close of the file descriptor will remove the
383*4c87aefeSPatrick Mooney 			 * event
384*4c87aefeSPatrick Mooney 			 */
385*4c87aefeSPatrick Mooney 			(void) close(mevp->me_fd);
386*4c87aefeSPatrick Mooney 			mevp->me_fd = -1;
387*4c87aefeSPatrick Mooney 		} else {
388*4c87aefeSPatrick Mooney 			mevent_update_one(mevp);
389*4c87aefeSPatrick Mooney 		}
390*4c87aefeSPatrick Mooney 
391*4c87aefeSPatrick Mooney 		mevp->me_cq = 0;
392*4c87aefeSPatrick Mooney 		LIST_REMOVE(mevp, me_list);
393*4c87aefeSPatrick Mooney 
394*4c87aefeSPatrick Mooney 		if (mevp->me_state == MEV_DEL_PENDING) {
395*4c87aefeSPatrick Mooney 			free(mevp);
396*4c87aefeSPatrick Mooney 		} else {
397*4c87aefeSPatrick Mooney 			LIST_INSERT_HEAD(&global_head, mevp, me_list);
398*4c87aefeSPatrick Mooney 		}
399*4c87aefeSPatrick Mooney 	}
400*4c87aefeSPatrick Mooney 
401*4c87aefeSPatrick Mooney 	mevent_qunlock();
402*4c87aefeSPatrick Mooney }
403*4c87aefeSPatrick Mooney 
404*4c87aefeSPatrick Mooney static void
405*4c87aefeSPatrick Mooney mevent_handle_pe(port_event_t *pe)
406*4c87aefeSPatrick Mooney {
407*4c87aefeSPatrick Mooney 	struct mevent *mevp = pe->portev_user;
408*4c87aefeSPatrick Mooney 
409*4c87aefeSPatrick Mooney 	mevent_qunlock();
410*4c87aefeSPatrick Mooney 
411*4c87aefeSPatrick Mooney 	(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);
412*4c87aefeSPatrick Mooney 
413*4c87aefeSPatrick Mooney 	mevent_qlock();
414*4c87aefeSPatrick Mooney 	if (!mevp->me_cq && !mevp->me_auto_requeue) {
415*4c87aefeSPatrick Mooney 		mevent_update_one(mevp);
416*4c87aefeSPatrick Mooney 	}
417*4c87aefeSPatrick Mooney 	mevent_qunlock();
418*4c87aefeSPatrick Mooney }
419*4c87aefeSPatrick Mooney #endif
420*4c87aefeSPatrick Mooney 
421*4c87aefeSPatrick Mooney struct mevent *
422*4c87aefeSPatrick Mooney mevent_add(int tfd, enum ev_type type,
423*4c87aefeSPatrick Mooney 	   void (*func)(int, enum ev_type, void *), void *param)
424*4c87aefeSPatrick Mooney {
425*4c87aefeSPatrick Mooney 	struct mevent *lp, *mevp;
426*4c87aefeSPatrick Mooney 
427*4c87aefeSPatrick Mooney 	if (tfd < 0 || func == NULL) {
428*4c87aefeSPatrick Mooney 		return (NULL);
429*4c87aefeSPatrick Mooney 	}
430*4c87aefeSPatrick Mooney 
431*4c87aefeSPatrick Mooney 	mevp = NULL;
432*4c87aefeSPatrick Mooney 
433*4c87aefeSPatrick Mooney 	mevent_qlock();
434*4c87aefeSPatrick Mooney 
435*4c87aefeSPatrick Mooney 	/*
436*4c87aefeSPatrick Mooney 	 * Verify that the fd/type tuple is not present in any list
437*4c87aefeSPatrick Mooney 	 */
438*4c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &global_head, me_list) {
439*4c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
440*4c87aefeSPatrick Mooney 		    lp->me_type == type) {
441*4c87aefeSPatrick Mooney 			goto exit;
442*4c87aefeSPatrick Mooney 		}
443*4c87aefeSPatrick Mooney 	}
444*4c87aefeSPatrick Mooney 
445*4c87aefeSPatrick Mooney 	LIST_FOREACH(lp, &change_head, me_list) {
446*4c87aefeSPatrick Mooney 		if (type != EVF_TIMER && lp->me_fd == tfd &&
447*4c87aefeSPatrick Mooney 		    lp->me_type == type) {
448*4c87aefeSPatrick Mooney 			goto exit;
449*4c87aefeSPatrick Mooney 		}
450*4c87aefeSPatrick Mooney 	}
451*4c87aefeSPatrick Mooney 
452*4c87aefeSPatrick Mooney 	/*
453*4c87aefeSPatrick Mooney 	 * Allocate an entry, populate it, and add it to the change list.
454*4c87aefeSPatrick Mooney 	 */
455*4c87aefeSPatrick Mooney 	mevp = calloc(1, sizeof(struct mevent));
456*4c87aefeSPatrick Mooney 	if (mevp == NULL) {
457*4c87aefeSPatrick Mooney 		goto exit;
458*4c87aefeSPatrick Mooney 	}
459*4c87aefeSPatrick Mooney 
460*4c87aefeSPatrick Mooney 	if (type == EVF_TIMER) {
461*4c87aefeSPatrick Mooney 		mevp->me_msecs = tfd;
462*4c87aefeSPatrick Mooney 		mevp->me_timid = mevent_timid++;
463*4c87aefeSPatrick Mooney 	} else
464*4c87aefeSPatrick Mooney 		mevp->me_fd = tfd;
465*4c87aefeSPatrick Mooney 	mevp->me_type = type;
466*4c87aefeSPatrick Mooney 	mevp->me_func = func;
467*4c87aefeSPatrick Mooney 	mevp->me_param = param;
468*4c87aefeSPatrick Mooney 
469*4c87aefeSPatrick Mooney 	LIST_INSERT_HEAD(&change_head, mevp, me_list);
470*4c87aefeSPatrick Mooney 	mevp->me_cq = 1;
471*4c87aefeSPatrick Mooney 	mevp->me_state = MEV_ADD;
472*4c87aefeSPatrick Mooney 	mevent_notify();
473*4c87aefeSPatrick Mooney 
474*4c87aefeSPatrick Mooney exit:
475*4c87aefeSPatrick Mooney 	mevent_qunlock();
476*4c87aefeSPatrick Mooney 
477*4c87aefeSPatrick Mooney 	return (mevp);
478*4c87aefeSPatrick Mooney }
479*4c87aefeSPatrick Mooney 
480*4c87aefeSPatrick Mooney static int
481*4c87aefeSPatrick Mooney mevent_update(struct mevent *evp, int newstate)
482*4c87aefeSPatrick Mooney {
483*4c87aefeSPatrick Mooney 	/*
484*4c87aefeSPatrick Mooney 	 * It's not possible to enable/disable a deleted event
485*4c87aefeSPatrick Mooney 	 */
486*4c87aefeSPatrick Mooney 	if (evp->me_state == MEV_DEL_PENDING)
487*4c87aefeSPatrick Mooney 		return (EINVAL);
488*4c87aefeSPatrick Mooney 
489*4c87aefeSPatrick Mooney 	/*
490*4c87aefeSPatrick Mooney 	 * No update needed if state isn't changing
491*4c87aefeSPatrick Mooney 	 */
492*4c87aefeSPatrick Mooney 	if (evp->me_state == newstate)
493*4c87aefeSPatrick Mooney 		return (0);
494*4c87aefeSPatrick Mooney 
495*4c87aefeSPatrick Mooney 	mevent_qlock();
496*4c87aefeSPatrick Mooney 
497*4c87aefeSPatrick Mooney 	evp->me_state = newstate;
498*4c87aefeSPatrick Mooney 
499*4c87aefeSPatrick Mooney 	/*
500*4c87aefeSPatrick Mooney 	 * Place the entry onto the changed list if not already there.
501*4c87aefeSPatrick Mooney 	 */
502*4c87aefeSPatrick Mooney 	if (evp->me_cq == 0) {
503*4c87aefeSPatrick Mooney 		evp->me_cq = 1;
504*4c87aefeSPatrick Mooney 		LIST_REMOVE(evp, me_list);
505*4c87aefeSPatrick Mooney 		LIST_INSERT_HEAD(&change_head, evp, me_list);
506*4c87aefeSPatrick Mooney 		mevent_notify();
507*4c87aefeSPatrick Mooney 	}
508*4c87aefeSPatrick Mooney 
509*4c87aefeSPatrick Mooney 	mevent_qunlock();
510*4c87aefeSPatrick Mooney 
511*4c87aefeSPatrick Mooney 	return (0);
512*4c87aefeSPatrick Mooney }
513*4c87aefeSPatrick Mooney 
514*4c87aefeSPatrick Mooney int
515*4c87aefeSPatrick Mooney mevent_enable(struct mevent *evp)
516*4c87aefeSPatrick Mooney {
517*4c87aefeSPatrick Mooney 
518*4c87aefeSPatrick Mooney 	return (mevent_update(evp, MEV_ENABLE));
519*4c87aefeSPatrick Mooney }
520*4c87aefeSPatrick Mooney 
521*4c87aefeSPatrick Mooney int
522*4c87aefeSPatrick Mooney mevent_disable(struct mevent *evp)
523*4c87aefeSPatrick Mooney {
524*4c87aefeSPatrick Mooney 
525*4c87aefeSPatrick Mooney 	return (mevent_update(evp, MEV_DISABLE));
526*4c87aefeSPatrick Mooney }
527*4c87aefeSPatrick Mooney 
528*4c87aefeSPatrick Mooney static int
529*4c87aefeSPatrick Mooney mevent_delete_event(struct mevent *evp, int closefd)
530*4c87aefeSPatrick Mooney {
531*4c87aefeSPatrick Mooney 	mevent_qlock();
532*4c87aefeSPatrick Mooney 
533*4c87aefeSPatrick Mooney 	/*
534*4c87aefeSPatrick Mooney          * Place the entry onto the changed list if not already there, and
535*4c87aefeSPatrick Mooney 	 * mark as to be deleted.
536*4c87aefeSPatrick Mooney          */
537*4c87aefeSPatrick Mooney         if (evp->me_cq == 0) {
538*4c87aefeSPatrick Mooney 		evp->me_cq = 1;
539*4c87aefeSPatrick Mooney 		LIST_REMOVE(evp, me_list);
540*4c87aefeSPatrick Mooney 		LIST_INSERT_HEAD(&change_head, evp, me_list);
541*4c87aefeSPatrick Mooney 		mevent_notify();
542*4c87aefeSPatrick Mooney         }
543*4c87aefeSPatrick Mooney 	evp->me_state = MEV_DEL_PENDING;
544*4c87aefeSPatrick Mooney 
545*4c87aefeSPatrick Mooney 	if (closefd)
546*4c87aefeSPatrick Mooney 		evp->me_closefd = 1;
547*4c87aefeSPatrick Mooney 
548*4c87aefeSPatrick Mooney 	mevent_qunlock();
549*4c87aefeSPatrick Mooney 
550*4c87aefeSPatrick Mooney 	return (0);
551*4c87aefeSPatrick Mooney }
552*4c87aefeSPatrick Mooney 
553*4c87aefeSPatrick Mooney int
554*4c87aefeSPatrick Mooney mevent_delete(struct mevent *evp)
555*4c87aefeSPatrick Mooney {
556*4c87aefeSPatrick Mooney 
557*4c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 0));
558*4c87aefeSPatrick Mooney }
559*4c87aefeSPatrick Mooney 
560*4c87aefeSPatrick Mooney int
561*4c87aefeSPatrick Mooney mevent_delete_close(struct mevent *evp)
562*4c87aefeSPatrick Mooney {
563*4c87aefeSPatrick Mooney 
564*4c87aefeSPatrick Mooney 	return (mevent_delete_event(evp, 1));
565*4c87aefeSPatrick Mooney }
566*4c87aefeSPatrick Mooney 
567*4c87aefeSPatrick Mooney static void
568*4c87aefeSPatrick Mooney mevent_set_name(void)
569*4c87aefeSPatrick Mooney {
570*4c87aefeSPatrick Mooney 
571*4c87aefeSPatrick Mooney 	pthread_set_name_np(mevent_tid, "mevent");
572*4c87aefeSPatrick Mooney }
573*4c87aefeSPatrick Mooney 
574*4c87aefeSPatrick Mooney void
575*4c87aefeSPatrick Mooney mevent_dispatch(void)
576*4c87aefeSPatrick Mooney {
577*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
578*4c87aefeSPatrick Mooney 	struct kevent changelist[MEVENT_MAX];
579*4c87aefeSPatrick Mooney 	struct kevent eventlist[MEVENT_MAX];
580*4c87aefeSPatrick Mooney 	struct mevent *pipev;
581*4c87aefeSPatrick Mooney 	int mfd;
582*4c87aefeSPatrick Mooney 	int numev;
583*4c87aefeSPatrick Mooney #else
584*4c87aefeSPatrick Mooney 	struct mevent *pipev;
585*4c87aefeSPatrick Mooney 	int portfd;
586*4c87aefeSPatrick Mooney #endif
587*4c87aefeSPatrick Mooney 	int ret;
588*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
589*4c87aefeSPatrick Mooney 	cap_rights_t rights;
590*4c87aefeSPatrick Mooney #endif
591*4c87aefeSPatrick Mooney 
592*4c87aefeSPatrick Mooney 	mevent_tid = pthread_self();
593*4c87aefeSPatrick Mooney 	mevent_set_name();
594*4c87aefeSPatrick Mooney 
595*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
596*4c87aefeSPatrick Mooney 	mfd = kqueue();
597*4c87aefeSPatrick Mooney 	assert(mfd > 0);
598*4c87aefeSPatrick Mooney #else
599*4c87aefeSPatrick Mooney 	portfd = port_create();
600*4c87aefeSPatrick Mooney 	assert(portfd >= 0);
601*4c87aefeSPatrick Mooney #endif
602*4c87aefeSPatrick Mooney 
603*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
604*4c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_KQUEUE);
605*4c87aefeSPatrick Mooney 	if (caph_rights_limit(mfd, &rights) == -1)
606*4c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
607*4c87aefeSPatrick Mooney #endif
608*4c87aefeSPatrick Mooney 
609*4c87aefeSPatrick Mooney 	/*
610*4c87aefeSPatrick Mooney 	 * Open the pipe that will be used for other threads to force
611*4c87aefeSPatrick Mooney 	 * the blocking kqueue call to exit by writing to it. Set the
612*4c87aefeSPatrick Mooney 	 * descriptor to non-blocking.
613*4c87aefeSPatrick Mooney 	 */
614*4c87aefeSPatrick Mooney 	ret = pipe(mevent_pipefd);
615*4c87aefeSPatrick Mooney 	if (ret < 0) {
616*4c87aefeSPatrick Mooney 		perror("pipe");
617*4c87aefeSPatrick Mooney 		exit(0);
618*4c87aefeSPatrick Mooney 	}
619*4c87aefeSPatrick Mooney 
620*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
621*4c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
622*4c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[0], &rights) == -1)
623*4c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
624*4c87aefeSPatrick Mooney 	if (caph_rights_limit(mevent_pipefd[1], &rights) == -1)
625*4c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
626*4c87aefeSPatrick Mooney #endif
627*4c87aefeSPatrick Mooney 
628*4c87aefeSPatrick Mooney 	/*
629*4c87aefeSPatrick Mooney 	 * Add internal event handler for the pipe write fd
630*4c87aefeSPatrick Mooney 	 */
631*4c87aefeSPatrick Mooney 	pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL);
632*4c87aefeSPatrick Mooney 	assert(pipev != NULL);
633*4c87aefeSPatrick Mooney 
634*4c87aefeSPatrick Mooney 	for (;;) {
635*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
636*4c87aefeSPatrick Mooney 		/*
637*4c87aefeSPatrick Mooney 		 * Build changelist if required.
638*4c87aefeSPatrick Mooney 		 * XXX the changelist can be put into the blocking call
639*4c87aefeSPatrick Mooney 		 * to eliminate the extra syscall. Currently better for
640*4c87aefeSPatrick Mooney 		 * debug.
641*4c87aefeSPatrick Mooney 		 */
642*4c87aefeSPatrick Mooney 		numev = mevent_build(mfd, changelist);
643*4c87aefeSPatrick Mooney 		if (numev) {
644*4c87aefeSPatrick Mooney 			ret = kevent(mfd, changelist, numev, NULL, 0, NULL);
645*4c87aefeSPatrick Mooney 			if (ret == -1) {
646*4c87aefeSPatrick Mooney 				perror("Error return from kevent change");
647*4c87aefeSPatrick Mooney 			}
648*4c87aefeSPatrick Mooney 		}
649*4c87aefeSPatrick Mooney 
650*4c87aefeSPatrick Mooney 		/*
651*4c87aefeSPatrick Mooney 		 * Block awaiting events
652*4c87aefeSPatrick Mooney 		 */
653*4c87aefeSPatrick Mooney 		ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);
654*4c87aefeSPatrick Mooney 		if (ret == -1 && errno != EINTR) {
655*4c87aefeSPatrick Mooney 			perror("Error return from kevent monitor");
656*4c87aefeSPatrick Mooney 		}
657*4c87aefeSPatrick Mooney 
658*4c87aefeSPatrick Mooney 		/*
659*4c87aefeSPatrick Mooney 		 * Handle reported events
660*4c87aefeSPatrick Mooney 		 */
661*4c87aefeSPatrick Mooney 		mevent_handle(eventlist, ret);
662*4c87aefeSPatrick Mooney 
663*4c87aefeSPatrick Mooney #else /* __FreeBSD__ */
664*4c87aefeSPatrick Mooney 		port_event_t pev;
665*4c87aefeSPatrick Mooney 
666*4c87aefeSPatrick Mooney 		/* Handle any pending updates */
667*4c87aefeSPatrick Mooney 		mevent_update_pending(portfd);
668*4c87aefeSPatrick Mooney 
669*4c87aefeSPatrick Mooney 		/* Block awaiting events */
670*4c87aefeSPatrick Mooney 		ret = port_get(portfd, &pev, NULL);
671*4c87aefeSPatrick Mooney 		if (ret != 0 && errno != EINTR) {
672*4c87aefeSPatrick Mooney 			perror("Error return from port_get");
673*4c87aefeSPatrick Mooney 			continue;
674*4c87aefeSPatrick Mooney 		}
675*4c87aefeSPatrick Mooney 
676*4c87aefeSPatrick Mooney 		/* Handle reported event */
677*4c87aefeSPatrick Mooney 		mevent_handle_pe(&pev);
678*4c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
679*4c87aefeSPatrick Mooney 	}
680*4c87aefeSPatrick Mooney }
681