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