14c87aefeSPatrick Mooney /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 44c87aefeSPatrick Mooney * Copyright (c) 2011 NetApp, Inc. 54c87aefeSPatrick Mooney * All rights reserved. 64c87aefeSPatrick Mooney * 74c87aefeSPatrick Mooney * Redistribution and use in source and binary forms, with or without 84c87aefeSPatrick Mooney * modification, are permitted provided that the following conditions 94c87aefeSPatrick Mooney * are met: 104c87aefeSPatrick Mooney * 1. Redistributions of source code must retain the above copyright 114c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer. 124c87aefeSPatrick Mooney * 2. Redistributions in binary form must reproduce the above copyright 134c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer in the 144c87aefeSPatrick Mooney * documentation and/or other materials provided with the distribution. 154c87aefeSPatrick Mooney * 164c87aefeSPatrick Mooney * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 174c87aefeSPatrick Mooney * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184c87aefeSPatrick Mooney * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194c87aefeSPatrick Mooney * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 204c87aefeSPatrick Mooney * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214c87aefeSPatrick Mooney * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224c87aefeSPatrick Mooney * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234c87aefeSPatrick Mooney * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244c87aefeSPatrick Mooney * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254c87aefeSPatrick Mooney * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264c87aefeSPatrick Mooney * SUCH DAMAGE. 274c87aefeSPatrick Mooney * 284c87aefeSPatrick Mooney * $FreeBSD$ 294c87aefeSPatrick Mooney */ 304c87aefeSPatrick Mooney 314c87aefeSPatrick Mooney /* 324c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 334c87aefeSPatrick Mooney */ 344c87aefeSPatrick Mooney 354c87aefeSPatrick Mooney /* 364c87aefeSPatrick Mooney * Micro event library for FreeBSD, designed for a single i/o thread 374c87aefeSPatrick Mooney * using kqueue, and having events be persistent by default. 384c87aefeSPatrick Mooney */ 394c87aefeSPatrick Mooney 404c87aefeSPatrick Mooney #include <sys/cdefs.h> 414c87aefeSPatrick Mooney __FBSDID("$FreeBSD$"); 424c87aefeSPatrick Mooney 434c87aefeSPatrick Mooney #include <assert.h> 444c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 454c87aefeSPatrick Mooney #include <capsicum_helpers.h> 464c87aefeSPatrick Mooney #endif 474c87aefeSPatrick Mooney #include <err.h> 484c87aefeSPatrick Mooney #include <errno.h> 494c87aefeSPatrick Mooney #include <stdlib.h> 504c87aefeSPatrick Mooney #include <stdio.h> 514c87aefeSPatrick Mooney #include <string.h> 524c87aefeSPatrick Mooney #include <sysexits.h> 534c87aefeSPatrick Mooney #include <unistd.h> 544c87aefeSPatrick Mooney 554c87aefeSPatrick Mooney #include <sys/types.h> 564c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 574c87aefeSPatrick Mooney #include <sys/capsicum.h> 584c87aefeSPatrick Mooney #endif 594c87aefeSPatrick Mooney #ifdef __FreeBSD__ 604c87aefeSPatrick Mooney #include <sys/event.h> 614c87aefeSPatrick Mooney #else 624c87aefeSPatrick Mooney #include <port.h> 634c87aefeSPatrick Mooney #include <sys/poll.h> 644c87aefeSPatrick Mooney #include <sys/siginfo.h> 654c87aefeSPatrick Mooney #include <sys/queue.h> 664c87aefeSPatrick Mooney #endif 674c87aefeSPatrick Mooney #include <sys/time.h> 684c87aefeSPatrick Mooney 694c87aefeSPatrick Mooney #include <pthread.h> 704c87aefeSPatrick Mooney #include <pthread_np.h> 714c87aefeSPatrick Mooney 724c87aefeSPatrick Mooney #include "mevent.h" 734c87aefeSPatrick Mooney 744c87aefeSPatrick Mooney #define MEVENT_MAX 64 754c87aefeSPatrick Mooney 764c87aefeSPatrick Mooney #define MEV_ADD 1 774c87aefeSPatrick Mooney #define MEV_ENABLE 2 784c87aefeSPatrick Mooney #define MEV_DISABLE 3 794c87aefeSPatrick Mooney #define MEV_DEL_PENDING 4 804c87aefeSPatrick Mooney 814c87aefeSPatrick Mooney extern char *vmname; 824c87aefeSPatrick Mooney 834c87aefeSPatrick Mooney static pthread_t mevent_tid; 844c87aefeSPatrick Mooney static int mevent_timid = 43; 854c87aefeSPatrick Mooney static int mevent_pipefd[2]; 864c87aefeSPatrick Mooney static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER; 874c87aefeSPatrick Mooney 884c87aefeSPatrick Mooney struct mevent { 894c87aefeSPatrick Mooney void (*me_func)(int, enum ev_type, void *); 904c87aefeSPatrick Mooney #define me_msecs me_fd 914c87aefeSPatrick Mooney int me_fd; 924c87aefeSPatrick Mooney #ifdef __FreeBSD__ 934c87aefeSPatrick Mooney int me_timid; 944c87aefeSPatrick Mooney #else 954c87aefeSPatrick Mooney timer_t me_timid; 964c87aefeSPatrick Mooney #endif 974c87aefeSPatrick Mooney enum ev_type me_type; 984c87aefeSPatrick Mooney void *me_param; 994c87aefeSPatrick Mooney int me_cq; 1004c87aefeSPatrick Mooney int me_state; 1014c87aefeSPatrick Mooney int me_closefd; 1024c87aefeSPatrick Mooney #ifndef __FreeBSD__ 1034c87aefeSPatrick Mooney port_notify_t me_notify; 1044c87aefeSPatrick Mooney struct sigevent me_sigev; 1054c87aefeSPatrick Mooney boolean_t me_auto_requeue; 1064c87aefeSPatrick Mooney #endif 1074c87aefeSPatrick Mooney LIST_ENTRY(mevent) me_list; 1084c87aefeSPatrick Mooney }; 1094c87aefeSPatrick Mooney 1104c87aefeSPatrick Mooney static LIST_HEAD(listhead, mevent) global_head, change_head; 1114c87aefeSPatrick Mooney 1124c87aefeSPatrick Mooney static void 1134c87aefeSPatrick Mooney mevent_qlock(void) 1144c87aefeSPatrick Mooney { 1154c87aefeSPatrick Mooney pthread_mutex_lock(&mevent_lmutex); 1164c87aefeSPatrick Mooney } 1174c87aefeSPatrick Mooney 1184c87aefeSPatrick Mooney static void 1194c87aefeSPatrick Mooney mevent_qunlock(void) 1204c87aefeSPatrick Mooney { 1214c87aefeSPatrick Mooney pthread_mutex_unlock(&mevent_lmutex); 1224c87aefeSPatrick Mooney } 1234c87aefeSPatrick Mooney 1244c87aefeSPatrick Mooney static void 1254c87aefeSPatrick Mooney mevent_pipe_read(int fd, enum ev_type type, void *param) 1264c87aefeSPatrick Mooney { 1274c87aefeSPatrick Mooney char buf[MEVENT_MAX]; 1284c87aefeSPatrick Mooney int status; 1294c87aefeSPatrick Mooney 1304c87aefeSPatrick Mooney /* 1314c87aefeSPatrick Mooney * Drain the pipe read side. The fd is non-blocking so this is 1324c87aefeSPatrick Mooney * safe to do. 1334c87aefeSPatrick Mooney */ 1344c87aefeSPatrick Mooney do { 1354c87aefeSPatrick Mooney status = read(fd, buf, sizeof(buf)); 1364c87aefeSPatrick Mooney } while (status == MEVENT_MAX); 1374c87aefeSPatrick Mooney } 1384c87aefeSPatrick Mooney 1394c87aefeSPatrick Mooney static void 1404c87aefeSPatrick Mooney mevent_notify(void) 1414c87aefeSPatrick Mooney { 142*84659b24SMichael Zeller char c = '\0'; 1434c87aefeSPatrick Mooney 1444c87aefeSPatrick Mooney /* 1454c87aefeSPatrick Mooney * If calling from outside the i/o thread, write a byte on the 1464c87aefeSPatrick Mooney * pipe to force the i/o thread to exit the blocking kevent call. 1474c87aefeSPatrick Mooney */ 1484c87aefeSPatrick Mooney if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) { 1494c87aefeSPatrick Mooney write(mevent_pipefd[1], &c, 1); 1504c87aefeSPatrick Mooney } 1514c87aefeSPatrick Mooney } 1524c87aefeSPatrick Mooney #ifdef __FreeBSD__ 1534c87aefeSPatrick Mooney static int 1544c87aefeSPatrick Mooney mevent_kq_filter(struct mevent *mevp) 1554c87aefeSPatrick Mooney { 1564c87aefeSPatrick Mooney int retval; 1574c87aefeSPatrick Mooney 1584c87aefeSPatrick Mooney retval = 0; 1594c87aefeSPatrick Mooney 1604c87aefeSPatrick Mooney if (mevp->me_type == EVF_READ) 1614c87aefeSPatrick Mooney retval = EVFILT_READ; 1624c87aefeSPatrick Mooney 1634c87aefeSPatrick Mooney if (mevp->me_type == EVF_WRITE) 1644c87aefeSPatrick Mooney retval = EVFILT_WRITE; 1654c87aefeSPatrick Mooney 1664c87aefeSPatrick Mooney if (mevp->me_type == EVF_TIMER) 1674c87aefeSPatrick Mooney retval = EVFILT_TIMER; 1684c87aefeSPatrick Mooney 1694c87aefeSPatrick Mooney if (mevp->me_type == EVF_SIGNAL) 1704c87aefeSPatrick Mooney retval = EVFILT_SIGNAL; 1714c87aefeSPatrick Mooney 1724c87aefeSPatrick Mooney return (retval); 1734c87aefeSPatrick Mooney } 1744c87aefeSPatrick Mooney 1754c87aefeSPatrick Mooney static int 1764c87aefeSPatrick Mooney mevent_kq_flags(struct mevent *mevp) 1774c87aefeSPatrick Mooney { 1784c87aefeSPatrick Mooney int ret; 1794c87aefeSPatrick Mooney 1804c87aefeSPatrick Mooney switch (mevp->me_state) { 1814c87aefeSPatrick Mooney case MEV_ADD: 1824c87aefeSPatrick Mooney ret = EV_ADD; /* implicitly enabled */ 1834c87aefeSPatrick Mooney break; 1844c87aefeSPatrick Mooney case MEV_ENABLE: 1854c87aefeSPatrick Mooney ret = EV_ENABLE; 1864c87aefeSPatrick Mooney break; 1874c87aefeSPatrick Mooney case MEV_DISABLE: 1884c87aefeSPatrick Mooney ret = EV_DISABLE; 1894c87aefeSPatrick Mooney break; 1904c87aefeSPatrick Mooney case MEV_DEL_PENDING: 1914c87aefeSPatrick Mooney ret = EV_DELETE; 1924c87aefeSPatrick Mooney break; 1934c87aefeSPatrick Mooney default: 1944c87aefeSPatrick Mooney assert(0); 1954c87aefeSPatrick Mooney break; 1964c87aefeSPatrick Mooney } 1974c87aefeSPatrick Mooney 1984c87aefeSPatrick Mooney return (ret); 1994c87aefeSPatrick Mooney } 2004c87aefeSPatrick Mooney 2014c87aefeSPatrick Mooney static int 2024c87aefeSPatrick Mooney mevent_kq_fflags(struct mevent *mevp) 2034c87aefeSPatrick Mooney { 2044c87aefeSPatrick Mooney /* XXX nothing yet, perhaps EV_EOF for reads ? */ 2054c87aefeSPatrick Mooney return (0); 2064c87aefeSPatrick Mooney } 2074c87aefeSPatrick Mooney 2084c87aefeSPatrick Mooney static int 2094c87aefeSPatrick Mooney mevent_build(int mfd, struct kevent *kev) 2104c87aefeSPatrick Mooney { 2114c87aefeSPatrick Mooney struct mevent *mevp, *tmpp; 2124c87aefeSPatrick Mooney int i; 2134c87aefeSPatrick Mooney 2144c87aefeSPatrick Mooney i = 0; 2154c87aefeSPatrick Mooney 2164c87aefeSPatrick Mooney mevent_qlock(); 2174c87aefeSPatrick Mooney 2184c87aefeSPatrick Mooney LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) { 2194c87aefeSPatrick Mooney if (mevp->me_closefd) { 2204c87aefeSPatrick Mooney /* 2214c87aefeSPatrick Mooney * A close of the file descriptor will remove the 2224c87aefeSPatrick Mooney * event 2234c87aefeSPatrick Mooney */ 2244c87aefeSPatrick Mooney close(mevp->me_fd); 2254c87aefeSPatrick Mooney } else { 2264c87aefeSPatrick Mooney if (mevp->me_type == EVF_TIMER) { 2274c87aefeSPatrick Mooney kev[i].ident = mevp->me_timid; 2284c87aefeSPatrick Mooney kev[i].data = mevp->me_msecs; 2294c87aefeSPatrick Mooney } else { 2304c87aefeSPatrick Mooney kev[i].ident = mevp->me_fd; 2314c87aefeSPatrick Mooney kev[i].data = 0; 2324c87aefeSPatrick Mooney } 2334c87aefeSPatrick Mooney kev[i].filter = mevent_kq_filter(mevp); 2344c87aefeSPatrick Mooney kev[i].flags = mevent_kq_flags(mevp); 2354c87aefeSPatrick Mooney kev[i].fflags = mevent_kq_fflags(mevp); 2364c87aefeSPatrick Mooney kev[i].udata = mevp; 2374c87aefeSPatrick Mooney i++; 2384c87aefeSPatrick Mooney } 2394c87aefeSPatrick Mooney 2404c87aefeSPatrick Mooney mevp->me_cq = 0; 2414c87aefeSPatrick Mooney LIST_REMOVE(mevp, me_list); 2424c87aefeSPatrick Mooney 2434c87aefeSPatrick Mooney if (mevp->me_state == MEV_DEL_PENDING) { 2444c87aefeSPatrick Mooney free(mevp); 2454c87aefeSPatrick Mooney } else { 2464c87aefeSPatrick Mooney LIST_INSERT_HEAD(&global_head, mevp, me_list); 2474c87aefeSPatrick Mooney } 2484c87aefeSPatrick Mooney 2494c87aefeSPatrick Mooney assert(i < MEVENT_MAX); 2504c87aefeSPatrick Mooney } 2514c87aefeSPatrick Mooney 2524c87aefeSPatrick Mooney mevent_qunlock(); 2534c87aefeSPatrick Mooney 2544c87aefeSPatrick Mooney return (i); 2554c87aefeSPatrick Mooney } 2564c87aefeSPatrick Mooney 2574c87aefeSPatrick Mooney static void 2584c87aefeSPatrick Mooney mevent_handle(struct kevent *kev, int numev) 2594c87aefeSPatrick Mooney { 2604c87aefeSPatrick Mooney struct mevent *mevp; 2614c87aefeSPatrick Mooney int i; 2624c87aefeSPatrick Mooney 2634c87aefeSPatrick Mooney for (i = 0; i < numev; i++) { 2644c87aefeSPatrick Mooney mevp = kev[i].udata; 2654c87aefeSPatrick Mooney 2664c87aefeSPatrick Mooney /* XXX check for EV_ERROR ? */ 2674c87aefeSPatrick Mooney 2684c87aefeSPatrick Mooney (*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param); 2694c87aefeSPatrick Mooney } 2704c87aefeSPatrick Mooney } 2714c87aefeSPatrick Mooney 2724c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 2734c87aefeSPatrick Mooney 2744c87aefeSPatrick Mooney static void 2754c87aefeSPatrick Mooney mevent_update_one(struct mevent *mevp) 2764c87aefeSPatrick Mooney { 2774c87aefeSPatrick Mooney int portfd = mevp->me_notify.portnfy_port; 2784c87aefeSPatrick Mooney 2794c87aefeSPatrick Mooney switch (mevp->me_type) { 2804c87aefeSPatrick Mooney case EVF_READ: 2814c87aefeSPatrick Mooney case EVF_WRITE: 2824c87aefeSPatrick Mooney mevp->me_auto_requeue = B_FALSE; 2834c87aefeSPatrick Mooney 2844c87aefeSPatrick Mooney switch (mevp->me_state) { 2854c87aefeSPatrick Mooney case MEV_ADD: 2864c87aefeSPatrick Mooney case MEV_ENABLE: 2874c87aefeSPatrick Mooney { 2884c87aefeSPatrick Mooney int events; 2894c87aefeSPatrick Mooney 2904c87aefeSPatrick Mooney events = (mevp->me_type == EVF_READ) ? POLLIN : POLLOUT; 2914c87aefeSPatrick Mooney 2924c87aefeSPatrick Mooney if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd, 2934c87aefeSPatrick Mooney events, mevp) != 0) { 2944c87aefeSPatrick Mooney (void) fprintf(stderr, 2954c87aefeSPatrick Mooney "port_associate fd %d %p failed: %s\n", 2964c87aefeSPatrick Mooney mevp->me_fd, mevp, strerror(errno)); 2974c87aefeSPatrick Mooney } 2984c87aefeSPatrick Mooney return; 2994c87aefeSPatrick Mooney } 3004c87aefeSPatrick Mooney case MEV_DISABLE: 3014c87aefeSPatrick Mooney case MEV_DEL_PENDING: 3024c87aefeSPatrick Mooney /* 3034c87aefeSPatrick Mooney * A disable that comes in while an event is being 3044c87aefeSPatrick Mooney * handled will result in an ENOENT. 3054c87aefeSPatrick Mooney */ 3064c87aefeSPatrick Mooney if (port_dissociate(portfd, PORT_SOURCE_FD, 3074c87aefeSPatrick Mooney mevp->me_fd) != 0 && errno != ENOENT) { 3084c87aefeSPatrick Mooney (void) fprintf(stderr, "port_dissociate " 3094c87aefeSPatrick Mooney "portfd %d fd %d mevp %p failed: %s\n", 3104c87aefeSPatrick Mooney portfd, mevp->me_fd, mevp, strerror(errno)); 3114c87aefeSPatrick Mooney } 3124c87aefeSPatrick Mooney return; 3134c87aefeSPatrick Mooney default: 3144c87aefeSPatrick Mooney goto abort; 3154c87aefeSPatrick Mooney } 3164c87aefeSPatrick Mooney 3174c87aefeSPatrick Mooney case EVF_TIMER: 3184c87aefeSPatrick Mooney mevp->me_auto_requeue = B_TRUE; 3194c87aefeSPatrick Mooney 3204c87aefeSPatrick Mooney switch (mevp->me_state) { 3214c87aefeSPatrick Mooney case MEV_ADD: 3224c87aefeSPatrick Mooney case MEV_ENABLE: 3234c87aefeSPatrick Mooney { 3244c87aefeSPatrick Mooney struct itimerspec it = { 0 }; 3254c87aefeSPatrick Mooney 3264c87aefeSPatrick Mooney mevp->me_sigev.sigev_notify = SIGEV_PORT; 3274c87aefeSPatrick Mooney mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify; 3284c87aefeSPatrick Mooney 3294c87aefeSPatrick Mooney if (timer_create(CLOCK_REALTIME, &mevp->me_sigev, 3304c87aefeSPatrick Mooney &mevp->me_timid) != 0) { 3314c87aefeSPatrick Mooney (void) fprintf(stderr, 3324c87aefeSPatrick Mooney "timer_create failed: %s", strerror(errno)); 3334c87aefeSPatrick Mooney return; 3344c87aefeSPatrick Mooney } 3354c87aefeSPatrick Mooney 3364c87aefeSPatrick Mooney /* The first timeout */ 3374c87aefeSPatrick Mooney it.it_value.tv_sec = mevp->me_msecs / MILLISEC; 3384c87aefeSPatrick Mooney it.it_value.tv_nsec = 3394c87aefeSPatrick Mooney MSEC2NSEC(mevp->me_msecs % MILLISEC); 3404c87aefeSPatrick Mooney /* Repeat at the same interval */ 3414c87aefeSPatrick Mooney it.it_interval = it.it_value; 3424c87aefeSPatrick Mooney 3434c87aefeSPatrick Mooney if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) { 3444c87aefeSPatrick Mooney (void) fprintf(stderr, "timer_settime failed: " 3454c87aefeSPatrick Mooney "%s", strerror(errno)); 3464c87aefeSPatrick Mooney } 3474c87aefeSPatrick Mooney return; 3484c87aefeSPatrick Mooney } 3494c87aefeSPatrick Mooney case MEV_DISABLE: 3504c87aefeSPatrick Mooney case MEV_DEL_PENDING: 3514c87aefeSPatrick Mooney if (timer_delete(mevp->me_timid) != 0) { 3524c87aefeSPatrick Mooney (void) fprintf(stderr, "timer_delete failed: " 3534c87aefeSPatrick Mooney "%s", strerror(errno)); 3544c87aefeSPatrick Mooney } 3554c87aefeSPatrick Mooney return; 3564c87aefeSPatrick Mooney default: 3574c87aefeSPatrick Mooney goto abort; 3584c87aefeSPatrick Mooney } 3594c87aefeSPatrick Mooney default: 3604c87aefeSPatrick Mooney /* EVF_SIGNAL not yet implemented. */ 3614c87aefeSPatrick Mooney goto abort; 3624c87aefeSPatrick Mooney } 3634c87aefeSPatrick Mooney 3644c87aefeSPatrick Mooney abort: 3654c87aefeSPatrick Mooney (void) fprintf(stderr, "%s: unhandled type %d state %d\n", __func__, 3664c87aefeSPatrick Mooney mevp->me_type, mevp->me_state); 3674c87aefeSPatrick Mooney abort(); 3684c87aefeSPatrick Mooney } 3694c87aefeSPatrick Mooney 3704c87aefeSPatrick Mooney static void 3714c87aefeSPatrick Mooney mevent_update_pending(int portfd) 3724c87aefeSPatrick Mooney { 3734c87aefeSPatrick Mooney struct mevent *mevp, *tmpp; 3744c87aefeSPatrick Mooney 3754c87aefeSPatrick Mooney mevent_qlock(); 3764c87aefeSPatrick Mooney 3774c87aefeSPatrick Mooney LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) { 3784c87aefeSPatrick Mooney mevp->me_notify.portnfy_port = portfd; 3794c87aefeSPatrick Mooney mevp->me_notify.portnfy_user = mevp; 3804c87aefeSPatrick Mooney if (mevp->me_closefd) { 3814c87aefeSPatrick Mooney /* 3824c87aefeSPatrick Mooney * A close of the file descriptor will remove the 3834c87aefeSPatrick Mooney * event 3844c87aefeSPatrick Mooney */ 3854c87aefeSPatrick Mooney (void) close(mevp->me_fd); 3864c87aefeSPatrick Mooney mevp->me_fd = -1; 3874c87aefeSPatrick Mooney } else { 3884c87aefeSPatrick Mooney mevent_update_one(mevp); 3894c87aefeSPatrick Mooney } 3904c87aefeSPatrick Mooney 3914c87aefeSPatrick Mooney mevp->me_cq = 0; 3924c87aefeSPatrick Mooney LIST_REMOVE(mevp, me_list); 3934c87aefeSPatrick Mooney 3944c87aefeSPatrick Mooney if (mevp->me_state == MEV_DEL_PENDING) { 3954c87aefeSPatrick Mooney free(mevp); 3964c87aefeSPatrick Mooney } else { 3974c87aefeSPatrick Mooney LIST_INSERT_HEAD(&global_head, mevp, me_list); 3984c87aefeSPatrick Mooney } 3994c87aefeSPatrick Mooney } 4004c87aefeSPatrick Mooney 4014c87aefeSPatrick Mooney mevent_qunlock(); 4024c87aefeSPatrick Mooney } 4034c87aefeSPatrick Mooney 4044c87aefeSPatrick Mooney static void 4054c87aefeSPatrick Mooney mevent_handle_pe(port_event_t *pe) 4064c87aefeSPatrick Mooney { 4074c87aefeSPatrick Mooney struct mevent *mevp = pe->portev_user; 4084c87aefeSPatrick Mooney 4094c87aefeSPatrick Mooney mevent_qunlock(); 4104c87aefeSPatrick Mooney 4114c87aefeSPatrick Mooney (*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param); 4124c87aefeSPatrick Mooney 4134c87aefeSPatrick Mooney mevent_qlock(); 4144c87aefeSPatrick Mooney if (!mevp->me_cq && !mevp->me_auto_requeue) { 4154c87aefeSPatrick Mooney mevent_update_one(mevp); 4164c87aefeSPatrick Mooney } 4174c87aefeSPatrick Mooney mevent_qunlock(); 4184c87aefeSPatrick Mooney } 4194c87aefeSPatrick Mooney #endif 4204c87aefeSPatrick Mooney 4214c87aefeSPatrick Mooney struct mevent * 4224c87aefeSPatrick Mooney mevent_add(int tfd, enum ev_type type, 4234c87aefeSPatrick Mooney void (*func)(int, enum ev_type, void *), void *param) 4244c87aefeSPatrick Mooney { 4254c87aefeSPatrick Mooney struct mevent *lp, *mevp; 4264c87aefeSPatrick Mooney 4274c87aefeSPatrick Mooney if (tfd < 0 || func == NULL) { 4284c87aefeSPatrick Mooney return (NULL); 4294c87aefeSPatrick Mooney } 4304c87aefeSPatrick Mooney 4314c87aefeSPatrick Mooney mevp = NULL; 4324c87aefeSPatrick Mooney 4334c87aefeSPatrick Mooney mevent_qlock(); 4344c87aefeSPatrick Mooney 4354c87aefeSPatrick Mooney /* 4364c87aefeSPatrick Mooney * Verify that the fd/type tuple is not present in any list 4374c87aefeSPatrick Mooney */ 4384c87aefeSPatrick Mooney LIST_FOREACH(lp, &global_head, me_list) { 4394c87aefeSPatrick Mooney if (type != EVF_TIMER && lp->me_fd == tfd && 4404c87aefeSPatrick Mooney lp->me_type == type) { 4414c87aefeSPatrick Mooney goto exit; 4424c87aefeSPatrick Mooney } 4434c87aefeSPatrick Mooney } 4444c87aefeSPatrick Mooney 4454c87aefeSPatrick Mooney LIST_FOREACH(lp, &change_head, me_list) { 4464c87aefeSPatrick Mooney if (type != EVF_TIMER && lp->me_fd == tfd && 4474c87aefeSPatrick Mooney lp->me_type == type) { 4484c87aefeSPatrick Mooney goto exit; 4494c87aefeSPatrick Mooney } 4504c87aefeSPatrick Mooney } 4514c87aefeSPatrick Mooney 4524c87aefeSPatrick Mooney /* 4534c87aefeSPatrick Mooney * Allocate an entry, populate it, and add it to the change list. 4544c87aefeSPatrick Mooney */ 4554c87aefeSPatrick Mooney mevp = calloc(1, sizeof(struct mevent)); 4564c87aefeSPatrick Mooney if (mevp == NULL) { 4574c87aefeSPatrick Mooney goto exit; 4584c87aefeSPatrick Mooney } 4594c87aefeSPatrick Mooney 4604c87aefeSPatrick Mooney if (type == EVF_TIMER) { 4614c87aefeSPatrick Mooney mevp->me_msecs = tfd; 4624c87aefeSPatrick Mooney mevp->me_timid = mevent_timid++; 4634c87aefeSPatrick Mooney } else 4644c87aefeSPatrick Mooney mevp->me_fd = tfd; 4654c87aefeSPatrick Mooney mevp->me_type = type; 4664c87aefeSPatrick Mooney mevp->me_func = func; 4674c87aefeSPatrick Mooney mevp->me_param = param; 4684c87aefeSPatrick Mooney 4694c87aefeSPatrick Mooney LIST_INSERT_HEAD(&change_head, mevp, me_list); 4704c87aefeSPatrick Mooney mevp->me_cq = 1; 4714c87aefeSPatrick Mooney mevp->me_state = MEV_ADD; 4724c87aefeSPatrick Mooney mevent_notify(); 4734c87aefeSPatrick Mooney 4744c87aefeSPatrick Mooney exit: 4754c87aefeSPatrick Mooney mevent_qunlock(); 4764c87aefeSPatrick Mooney 4774c87aefeSPatrick Mooney return (mevp); 4784c87aefeSPatrick Mooney } 4794c87aefeSPatrick Mooney 4804c87aefeSPatrick Mooney static int 4814c87aefeSPatrick Mooney mevent_update(struct mevent *evp, int newstate) 4824c87aefeSPatrick Mooney { 4834c87aefeSPatrick Mooney /* 4844c87aefeSPatrick Mooney * It's not possible to enable/disable a deleted event 4854c87aefeSPatrick Mooney */ 4864c87aefeSPatrick Mooney if (evp->me_state == MEV_DEL_PENDING) 4874c87aefeSPatrick Mooney return (EINVAL); 4884c87aefeSPatrick Mooney 4894c87aefeSPatrick Mooney /* 4904c87aefeSPatrick Mooney * No update needed if state isn't changing 4914c87aefeSPatrick Mooney */ 4924c87aefeSPatrick Mooney if (evp->me_state == newstate) 4934c87aefeSPatrick Mooney return (0); 4944c87aefeSPatrick Mooney 4954c87aefeSPatrick Mooney mevent_qlock(); 4964c87aefeSPatrick Mooney 4974c87aefeSPatrick Mooney evp->me_state = newstate; 4984c87aefeSPatrick Mooney 4994c87aefeSPatrick Mooney /* 5004c87aefeSPatrick Mooney * Place the entry onto the changed list if not already there. 5014c87aefeSPatrick Mooney */ 5024c87aefeSPatrick Mooney if (evp->me_cq == 0) { 5034c87aefeSPatrick Mooney evp->me_cq = 1; 5044c87aefeSPatrick Mooney LIST_REMOVE(evp, me_list); 5054c87aefeSPatrick Mooney LIST_INSERT_HEAD(&change_head, evp, me_list); 5064c87aefeSPatrick Mooney mevent_notify(); 5074c87aefeSPatrick Mooney } 5084c87aefeSPatrick Mooney 5094c87aefeSPatrick Mooney mevent_qunlock(); 5104c87aefeSPatrick Mooney 5114c87aefeSPatrick Mooney return (0); 5124c87aefeSPatrick Mooney } 5134c87aefeSPatrick Mooney 5144c87aefeSPatrick Mooney int 5154c87aefeSPatrick Mooney mevent_enable(struct mevent *evp) 5164c87aefeSPatrick Mooney { 5174c87aefeSPatrick Mooney 5184c87aefeSPatrick Mooney return (mevent_update(evp, MEV_ENABLE)); 5194c87aefeSPatrick Mooney } 5204c87aefeSPatrick Mooney 5214c87aefeSPatrick Mooney int 5224c87aefeSPatrick Mooney mevent_disable(struct mevent *evp) 5234c87aefeSPatrick Mooney { 5244c87aefeSPatrick Mooney 5254c87aefeSPatrick Mooney return (mevent_update(evp, MEV_DISABLE)); 5264c87aefeSPatrick Mooney } 5274c87aefeSPatrick Mooney 5284c87aefeSPatrick Mooney static int 5294c87aefeSPatrick Mooney mevent_delete_event(struct mevent *evp, int closefd) 5304c87aefeSPatrick Mooney { 5314c87aefeSPatrick Mooney mevent_qlock(); 5324c87aefeSPatrick Mooney 5334c87aefeSPatrick Mooney /* 5344c87aefeSPatrick Mooney * Place the entry onto the changed list if not already there, and 5354c87aefeSPatrick Mooney * mark as to be deleted. 5364c87aefeSPatrick Mooney */ 5374c87aefeSPatrick Mooney if (evp->me_cq == 0) { 5384c87aefeSPatrick Mooney evp->me_cq = 1; 5394c87aefeSPatrick Mooney LIST_REMOVE(evp, me_list); 5404c87aefeSPatrick Mooney LIST_INSERT_HEAD(&change_head, evp, me_list); 5414c87aefeSPatrick Mooney mevent_notify(); 5424c87aefeSPatrick Mooney } 5434c87aefeSPatrick Mooney evp->me_state = MEV_DEL_PENDING; 5444c87aefeSPatrick Mooney 5454c87aefeSPatrick Mooney if (closefd) 5464c87aefeSPatrick Mooney evp->me_closefd = 1; 5474c87aefeSPatrick Mooney 5484c87aefeSPatrick Mooney mevent_qunlock(); 5494c87aefeSPatrick Mooney 5504c87aefeSPatrick Mooney return (0); 5514c87aefeSPatrick Mooney } 5524c87aefeSPatrick Mooney 5534c87aefeSPatrick Mooney int 5544c87aefeSPatrick Mooney mevent_delete(struct mevent *evp) 5554c87aefeSPatrick Mooney { 5564c87aefeSPatrick Mooney 5574c87aefeSPatrick Mooney return (mevent_delete_event(evp, 0)); 5584c87aefeSPatrick Mooney } 5594c87aefeSPatrick Mooney 5604c87aefeSPatrick Mooney int 5614c87aefeSPatrick Mooney mevent_delete_close(struct mevent *evp) 5624c87aefeSPatrick Mooney { 5634c87aefeSPatrick Mooney 5644c87aefeSPatrick Mooney return (mevent_delete_event(evp, 1)); 5654c87aefeSPatrick Mooney } 5664c87aefeSPatrick Mooney 5674c87aefeSPatrick Mooney static void 5684c87aefeSPatrick Mooney mevent_set_name(void) 5694c87aefeSPatrick Mooney { 5704c87aefeSPatrick Mooney 5714c87aefeSPatrick Mooney pthread_set_name_np(mevent_tid, "mevent"); 5724c87aefeSPatrick Mooney } 5734c87aefeSPatrick Mooney 5744c87aefeSPatrick Mooney void 5754c87aefeSPatrick Mooney mevent_dispatch(void) 5764c87aefeSPatrick Mooney { 5774c87aefeSPatrick Mooney #ifdef __FreeBSD__ 5784c87aefeSPatrick Mooney struct kevent changelist[MEVENT_MAX]; 5794c87aefeSPatrick Mooney struct kevent eventlist[MEVENT_MAX]; 5804c87aefeSPatrick Mooney struct mevent *pipev; 5814c87aefeSPatrick Mooney int mfd; 5824c87aefeSPatrick Mooney int numev; 5834c87aefeSPatrick Mooney #else 5844c87aefeSPatrick Mooney struct mevent *pipev; 5854c87aefeSPatrick Mooney int portfd; 5864c87aefeSPatrick Mooney #endif 5874c87aefeSPatrick Mooney int ret; 5884c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 5894c87aefeSPatrick Mooney cap_rights_t rights; 5904c87aefeSPatrick Mooney #endif 5914c87aefeSPatrick Mooney 5924c87aefeSPatrick Mooney mevent_tid = pthread_self(); 5934c87aefeSPatrick Mooney mevent_set_name(); 5944c87aefeSPatrick Mooney 5954c87aefeSPatrick Mooney #ifdef __FreeBSD__ 5964c87aefeSPatrick Mooney mfd = kqueue(); 5974c87aefeSPatrick Mooney assert(mfd > 0); 5984c87aefeSPatrick Mooney #else 5994c87aefeSPatrick Mooney portfd = port_create(); 6004c87aefeSPatrick Mooney assert(portfd >= 0); 6014c87aefeSPatrick Mooney #endif 6024c87aefeSPatrick Mooney 6034c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 6044c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_KQUEUE); 6054c87aefeSPatrick Mooney if (caph_rights_limit(mfd, &rights) == -1) 6064c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 6074c87aefeSPatrick Mooney #endif 6084c87aefeSPatrick Mooney 6094c87aefeSPatrick Mooney /* 6104c87aefeSPatrick Mooney * Open the pipe that will be used for other threads to force 6114c87aefeSPatrick Mooney * the blocking kqueue call to exit by writing to it. Set the 6124c87aefeSPatrick Mooney * descriptor to non-blocking. 6134c87aefeSPatrick Mooney */ 6144c87aefeSPatrick Mooney ret = pipe(mevent_pipefd); 6154c87aefeSPatrick Mooney if (ret < 0) { 6164c87aefeSPatrick Mooney perror("pipe"); 6174c87aefeSPatrick Mooney exit(0); 6184c87aefeSPatrick Mooney } 6194c87aefeSPatrick Mooney 6204c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 6214c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE); 6224c87aefeSPatrick Mooney if (caph_rights_limit(mevent_pipefd[0], &rights) == -1) 6234c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 6244c87aefeSPatrick Mooney if (caph_rights_limit(mevent_pipefd[1], &rights) == -1) 6254c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 6264c87aefeSPatrick Mooney #endif 6274c87aefeSPatrick Mooney 6284c87aefeSPatrick Mooney /* 6294c87aefeSPatrick Mooney * Add internal event handler for the pipe write fd 6304c87aefeSPatrick Mooney */ 6314c87aefeSPatrick Mooney pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL); 6324c87aefeSPatrick Mooney assert(pipev != NULL); 6334c87aefeSPatrick Mooney 6344c87aefeSPatrick Mooney for (;;) { 6354c87aefeSPatrick Mooney #ifdef __FreeBSD__ 6364c87aefeSPatrick Mooney /* 6374c87aefeSPatrick Mooney * Build changelist if required. 6384c87aefeSPatrick Mooney * XXX the changelist can be put into the blocking call 6394c87aefeSPatrick Mooney * to eliminate the extra syscall. Currently better for 6404c87aefeSPatrick Mooney * debug. 6414c87aefeSPatrick Mooney */ 6424c87aefeSPatrick Mooney numev = mevent_build(mfd, changelist); 6434c87aefeSPatrick Mooney if (numev) { 6444c87aefeSPatrick Mooney ret = kevent(mfd, changelist, numev, NULL, 0, NULL); 6454c87aefeSPatrick Mooney if (ret == -1) { 6464c87aefeSPatrick Mooney perror("Error return from kevent change"); 6474c87aefeSPatrick Mooney } 6484c87aefeSPatrick Mooney } 6494c87aefeSPatrick Mooney 6504c87aefeSPatrick Mooney /* 6514c87aefeSPatrick Mooney * Block awaiting events 6524c87aefeSPatrick Mooney */ 6534c87aefeSPatrick Mooney ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL); 6544c87aefeSPatrick Mooney if (ret == -1 && errno != EINTR) { 6554c87aefeSPatrick Mooney perror("Error return from kevent monitor"); 6564c87aefeSPatrick Mooney } 6574c87aefeSPatrick Mooney 6584c87aefeSPatrick Mooney /* 6594c87aefeSPatrick Mooney * Handle reported events 6604c87aefeSPatrick Mooney */ 6614c87aefeSPatrick Mooney mevent_handle(eventlist, ret); 6624c87aefeSPatrick Mooney 6634c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 6644c87aefeSPatrick Mooney port_event_t pev; 6654c87aefeSPatrick Mooney 6664c87aefeSPatrick Mooney /* Handle any pending updates */ 6674c87aefeSPatrick Mooney mevent_update_pending(portfd); 6684c87aefeSPatrick Mooney 6694c87aefeSPatrick Mooney /* Block awaiting events */ 6704c87aefeSPatrick Mooney ret = port_get(portfd, &pev, NULL); 6714c87aefeSPatrick Mooney if (ret != 0 && errno != EINTR) { 6724c87aefeSPatrick Mooney perror("Error return from port_get"); 6734c87aefeSPatrick Mooney continue; 6744c87aefeSPatrick Mooney } 6754c87aefeSPatrick Mooney 6764c87aefeSPatrick Mooney /* Handle reported event */ 6774c87aefeSPatrick Mooney mevent_handle_pe(&pev); 6784c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 6794c87aefeSPatrick Mooney } 6804c87aefeSPatrick Mooney } 681