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