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