14c87aefeSPatrick Mooney /*- 2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause 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 294c87aefeSPatrick Mooney /* 304c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 31251becc8SAndy Fiddaman * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 324c87aefeSPatrick Mooney */ 334c87aefeSPatrick Mooney 344c87aefeSPatrick Mooney /* 356dc98349SAndy Fiddaman * Micro event library for FreeBSD, designed for a single i/o thread 364c87aefeSPatrick Mooney * using kqueue, and having events be persistent by default. 374c87aefeSPatrick Mooney */ 384c87aefeSPatrick Mooney 394c87aefeSPatrick Mooney #include <sys/cdefs.h> 404c87aefeSPatrick Mooney 414c87aefeSPatrick Mooney #include <assert.h> 424c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 434c87aefeSPatrick Mooney #include <capsicum_helpers.h> 444c87aefeSPatrick Mooney #endif 454c87aefeSPatrick Mooney #include <err.h> 464c87aefeSPatrick Mooney #include <errno.h> 47154972afSPatrick Mooney #include <stdbool.h> 484c87aefeSPatrick Mooney #include <stdlib.h> 494c87aefeSPatrick Mooney #include <stdio.h> 504c87aefeSPatrick Mooney #include <string.h> 514c87aefeSPatrick Mooney #include <sysexits.h> 524c87aefeSPatrick Mooney #include <unistd.h> 534c87aefeSPatrick Mooney 544c87aefeSPatrick Mooney #include <sys/types.h> 554c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 564c87aefeSPatrick Mooney #include <sys/capsicum.h> 574c87aefeSPatrick Mooney #endif 584c87aefeSPatrick Mooney #ifdef __FreeBSD__ 594c87aefeSPatrick Mooney #include <sys/event.h> 604c87aefeSPatrick Mooney #else 614c87aefeSPatrick Mooney #include <port.h> 624c87aefeSPatrick Mooney #include <sys/poll.h> 634c87aefeSPatrick Mooney #include <sys/siginfo.h> 644c87aefeSPatrick Mooney #include <sys/queue.h> 65154972afSPatrick Mooney #include <sys/debug.h> 66e8d71297SAndy Fiddaman #include <sys/stat.h> 674c87aefeSPatrick Mooney #endif 684c87aefeSPatrick Mooney #include <sys/time.h> 694c87aefeSPatrick Mooney 704c87aefeSPatrick Mooney #include <pthread.h> 714c87aefeSPatrick Mooney #include <pthread_np.h> 724c87aefeSPatrick Mooney 734c87aefeSPatrick Mooney #include "mevent.h" 744c87aefeSPatrick Mooney 754c87aefeSPatrick Mooney #define MEVENT_MAX 64 764c87aefeSPatrick Mooney 77154972afSPatrick Mooney #ifndef __FreeBSD__ 78154972afSPatrick Mooney #define EV_ENABLE 0x01 79154972afSPatrick Mooney #define EV_ADD EV_ENABLE 80154972afSPatrick Mooney #define EV_DISABLE 0x02 81154972afSPatrick Mooney #define EV_DELETE 0x04 82251becc8SAndy Fiddaman 83251becc8SAndy Fiddaman static int mevent_file_poll_interval_ms = 5000; 84154972afSPatrick Mooney #endif 854c87aefeSPatrick Mooney 864c87aefeSPatrick Mooney static pthread_t mevent_tid; 87b0de25cbSAndy Fiddaman static pthread_once_t mevent_once = PTHREAD_ONCE_INIT; 88251becc8SAndy Fiddaman #ifdef __FreeBSD__ 894c87aefeSPatrick Mooney static int mevent_timid = 43; 90251becc8SAndy Fiddaman #endif 914c87aefeSPatrick Mooney static int mevent_pipefd[2]; 92b0de25cbSAndy Fiddaman static int mfd; 934c87aefeSPatrick Mooney static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER; 944c87aefeSPatrick Mooney 954c87aefeSPatrick Mooney struct mevent { 964c87aefeSPatrick Mooney void (*me_func)(int, enum ev_type, void *); 974c87aefeSPatrick Mooney #define me_msecs me_fd 984c87aefeSPatrick Mooney int me_fd; 994c87aefeSPatrick Mooney #ifdef __FreeBSD__ 1004c87aefeSPatrick Mooney int me_timid; 1014c87aefeSPatrick Mooney #else 1024c87aefeSPatrick Mooney timer_t me_timid; 1034c87aefeSPatrick Mooney #endif 1044c87aefeSPatrick Mooney enum ev_type me_type; 1054c87aefeSPatrick Mooney void *me_param; 1064c87aefeSPatrick Mooney int me_cq; 107154972afSPatrick Mooney int me_state; /* Desired kevent flags. */ 1084c87aefeSPatrick Mooney int me_closefd; 109b0de25cbSAndy Fiddaman int me_fflags; 1104c87aefeSPatrick Mooney #ifndef __FreeBSD__ 1114c87aefeSPatrick Mooney port_notify_t me_notify; 1124c87aefeSPatrick Mooney struct sigevent me_sigev; 1134c87aefeSPatrick Mooney boolean_t me_auto_requeue; 114251becc8SAndy Fiddaman struct { 115251becc8SAndy Fiddaman int mp_fd; 116251becc8SAndy Fiddaman off_t mp_size; 117251becc8SAndy Fiddaman void (*mp_func)(int, enum ev_type, void *); 118251becc8SAndy Fiddaman void *mp_param; 119251becc8SAndy Fiddaman } me_poll; 1204c87aefeSPatrick Mooney #endif 1214c87aefeSPatrick Mooney LIST_ENTRY(mevent) me_list; 1224c87aefeSPatrick Mooney }; 1234c87aefeSPatrick Mooney 1244c87aefeSPatrick Mooney static LIST_HEAD(listhead, mevent) global_head, change_head; 1254c87aefeSPatrick Mooney 1264c87aefeSPatrick Mooney static void 1274c87aefeSPatrick Mooney mevent_qlock(void) 1284c87aefeSPatrick Mooney { 1294c87aefeSPatrick Mooney pthread_mutex_lock(&mevent_lmutex); 1304c87aefeSPatrick Mooney } 1314c87aefeSPatrick Mooney 1324c87aefeSPatrick Mooney static void 1334c87aefeSPatrick Mooney mevent_qunlock(void) 1344c87aefeSPatrick Mooney { 1354c87aefeSPatrick Mooney pthread_mutex_unlock(&mevent_lmutex); 1364c87aefeSPatrick Mooney } 1374c87aefeSPatrick Mooney 1384c87aefeSPatrick Mooney static void 13959d65d31SAndy Fiddaman mevent_pipe_read(int fd, enum ev_type type __unused, void *param __unused) 1404c87aefeSPatrick Mooney { 1414c87aefeSPatrick Mooney char buf[MEVENT_MAX]; 1424c87aefeSPatrick Mooney int status; 1434c87aefeSPatrick Mooney 1444c87aefeSPatrick Mooney /* 1454c87aefeSPatrick Mooney * Drain the pipe read side. The fd is non-blocking so this is 1464c87aefeSPatrick Mooney * safe to do. 1474c87aefeSPatrick Mooney */ 1484c87aefeSPatrick Mooney do { 1494c87aefeSPatrick Mooney status = read(fd, buf, sizeof(buf)); 1504c87aefeSPatrick Mooney } while (status == MEVENT_MAX); 1514c87aefeSPatrick Mooney } 1524c87aefeSPatrick Mooney 1534c87aefeSPatrick Mooney static void 1544c87aefeSPatrick Mooney mevent_notify(void) 1554c87aefeSPatrick Mooney { 15684659b24SMichael Zeller char c = '\0'; 1576dc98349SAndy Fiddaman 1584c87aefeSPatrick Mooney /* 1594c87aefeSPatrick Mooney * If calling from outside the i/o thread, write a byte on the 1604c87aefeSPatrick Mooney * pipe to force the i/o thread to exit the blocking kevent call. 1614c87aefeSPatrick Mooney */ 1624c87aefeSPatrick Mooney if (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) { 1634c87aefeSPatrick Mooney write(mevent_pipefd[1], &c, 1); 1644c87aefeSPatrick Mooney } 1654c87aefeSPatrick Mooney } 166b0de25cbSAndy Fiddaman 167b0de25cbSAndy Fiddaman static void 168b0de25cbSAndy Fiddaman mevent_init(void) 169b0de25cbSAndy Fiddaman { 170b0de25cbSAndy Fiddaman #ifndef WITHOUT_CAPSICUM 171b0de25cbSAndy Fiddaman cap_rights_t rights; 172b0de25cbSAndy Fiddaman #endif 173b0de25cbSAndy Fiddaman 174b0de25cbSAndy Fiddaman #ifdef __FreeBSD__ 175b0de25cbSAndy Fiddaman mfd = kqueue(); 176b0de25cbSAndy Fiddaman #else 177b0de25cbSAndy Fiddaman mfd = port_create(); 178b0de25cbSAndy Fiddaman #endif 179b0de25cbSAndy Fiddaman assert(mfd > 0); 180b0de25cbSAndy Fiddaman 181b0de25cbSAndy Fiddaman #ifndef WITHOUT_CAPSICUM 182b0de25cbSAndy Fiddaman cap_rights_init(&rights, CAP_KQUEUE); 183b0de25cbSAndy Fiddaman if (caph_rights_limit(mfd, &rights) == -1) 184b0de25cbSAndy Fiddaman errx(EX_OSERR, "Unable to apply rights for sandbox"); 185251becc8SAndy Fiddaman #endif 186b0de25cbSAndy Fiddaman 187b0de25cbSAndy Fiddaman LIST_INIT(&change_head); 188b0de25cbSAndy Fiddaman LIST_INIT(&global_head); 189b0de25cbSAndy Fiddaman } 190b0de25cbSAndy Fiddaman 191b0de25cbSAndy Fiddaman 1924c87aefeSPatrick Mooney #ifdef __FreeBSD__ 1934c87aefeSPatrick Mooney static int 1944c87aefeSPatrick Mooney mevent_kq_filter(struct mevent *mevp) 1954c87aefeSPatrick Mooney { 1964c87aefeSPatrick Mooney int retval; 1974c87aefeSPatrick Mooney 1984c87aefeSPatrick Mooney retval = 0; 1994c87aefeSPatrick Mooney 2004c87aefeSPatrick Mooney if (mevp->me_type == EVF_READ) 2014c87aefeSPatrick Mooney retval = EVFILT_READ; 2024c87aefeSPatrick Mooney 2034c87aefeSPatrick Mooney if (mevp->me_type == EVF_WRITE) 2044c87aefeSPatrick Mooney retval = EVFILT_WRITE; 2054c87aefeSPatrick Mooney 2064c87aefeSPatrick Mooney if (mevp->me_type == EVF_TIMER) 2074c87aefeSPatrick Mooney retval = EVFILT_TIMER; 2084c87aefeSPatrick Mooney 2094c87aefeSPatrick Mooney if (mevp->me_type == EVF_SIGNAL) 2104c87aefeSPatrick Mooney retval = EVFILT_SIGNAL; 2114c87aefeSPatrick Mooney 212b0de25cbSAndy Fiddaman if (mevp->me_type == EVF_VNODE) 213b0de25cbSAndy Fiddaman retval = EVFILT_VNODE; 214b0de25cbSAndy Fiddaman 2154c87aefeSPatrick Mooney return (retval); 2164c87aefeSPatrick Mooney } 2174c87aefeSPatrick Mooney 2184c87aefeSPatrick Mooney static int 2194c87aefeSPatrick Mooney mevent_kq_flags(struct mevent *mevp) 2204c87aefeSPatrick Mooney { 2216dc98349SAndy Fiddaman int retval; 2226dc98349SAndy Fiddaman 2236dc98349SAndy Fiddaman retval = mevp->me_state; 2246dc98349SAndy Fiddaman 2256dc98349SAndy Fiddaman if (mevp->me_type == EVF_VNODE) 2266dc98349SAndy Fiddaman retval |= EV_CLEAR; 2276dc98349SAndy Fiddaman 2286dc98349SAndy Fiddaman return (retval); 2294c87aefeSPatrick Mooney } 2304c87aefeSPatrick Mooney 2314c87aefeSPatrick Mooney static int 2324c87aefeSPatrick Mooney mevent_kq_fflags(struct mevent *mevp) 2334c87aefeSPatrick Mooney { 234b0de25cbSAndy Fiddaman int retval; 235b0de25cbSAndy Fiddaman 236b0de25cbSAndy Fiddaman retval = 0; 237b0de25cbSAndy Fiddaman 238b0de25cbSAndy Fiddaman switch (mevp->me_type) { 239b0de25cbSAndy Fiddaman case EVF_VNODE: 240b0de25cbSAndy Fiddaman if ((mevp->me_fflags & EVFF_ATTRIB) != 0) 241b0de25cbSAndy Fiddaman retval |= NOTE_ATTRIB; 242b0de25cbSAndy Fiddaman break; 2436dc98349SAndy Fiddaman case EVF_READ: 2446dc98349SAndy Fiddaman case EVF_WRITE: 2456dc98349SAndy Fiddaman case EVF_TIMER: 2466dc98349SAndy Fiddaman case EVF_SIGNAL: 2476dc98349SAndy Fiddaman break; 248b0de25cbSAndy Fiddaman } 249b0de25cbSAndy Fiddaman 250b0de25cbSAndy Fiddaman return (retval); 251b0de25cbSAndy Fiddaman } 252b0de25cbSAndy Fiddaman 253b0de25cbSAndy Fiddaman static void 254b0de25cbSAndy Fiddaman mevent_populate(struct mevent *mevp, struct kevent *kev) 255b0de25cbSAndy Fiddaman { 256b0de25cbSAndy Fiddaman if (mevp->me_type == EVF_TIMER) { 257b0de25cbSAndy Fiddaman kev->ident = mevp->me_timid; 258b0de25cbSAndy Fiddaman kev->data = mevp->me_msecs; 259b0de25cbSAndy Fiddaman } else { 260b0de25cbSAndy Fiddaman kev->ident = mevp->me_fd; 261b0de25cbSAndy Fiddaman kev->data = 0; 262b0de25cbSAndy Fiddaman } 263b0de25cbSAndy Fiddaman kev->filter = mevent_kq_filter(mevp); 264b0de25cbSAndy Fiddaman kev->flags = mevent_kq_flags(mevp); 265b0de25cbSAndy Fiddaman kev->fflags = mevent_kq_fflags(mevp); 266b0de25cbSAndy Fiddaman kev->udata = mevp; 2674c87aefeSPatrick Mooney } 2684c87aefeSPatrick Mooney 2694c87aefeSPatrick Mooney static int 270b0de25cbSAndy Fiddaman mevent_build(struct kevent *kev) 2714c87aefeSPatrick Mooney { 2724c87aefeSPatrick Mooney struct mevent *mevp, *tmpp; 2734c87aefeSPatrick Mooney int i; 2744c87aefeSPatrick Mooney 2754c87aefeSPatrick Mooney i = 0; 2764c87aefeSPatrick Mooney 2774c87aefeSPatrick Mooney mevent_qlock(); 2784c87aefeSPatrick Mooney 2794c87aefeSPatrick Mooney LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) { 2804c87aefeSPatrick Mooney if (mevp->me_closefd) { 2814c87aefeSPatrick Mooney /* 2824c87aefeSPatrick Mooney * A close of the file descriptor will remove the 2834c87aefeSPatrick Mooney * event 2844c87aefeSPatrick Mooney */ 2854c87aefeSPatrick Mooney close(mevp->me_fd); 2864c87aefeSPatrick Mooney } else { 287b0de25cbSAndy Fiddaman assert((mevp->me_state & EV_ADD) == 0); 288b0de25cbSAndy Fiddaman mevent_populate(mevp, &kev[i]); 2894c87aefeSPatrick Mooney i++; 2904c87aefeSPatrick Mooney } 2914c87aefeSPatrick Mooney 2924c87aefeSPatrick Mooney mevp->me_cq = 0; 2934c87aefeSPatrick Mooney LIST_REMOVE(mevp, me_list); 2944c87aefeSPatrick Mooney 295154972afSPatrick Mooney if (mevp->me_state & EV_DELETE) { 2964c87aefeSPatrick Mooney free(mevp); 2974c87aefeSPatrick Mooney } else { 2984c87aefeSPatrick Mooney LIST_INSERT_HEAD(&global_head, mevp, me_list); 2994c87aefeSPatrick Mooney } 3004c87aefeSPatrick Mooney 3014c87aefeSPatrick Mooney assert(i < MEVENT_MAX); 3024c87aefeSPatrick Mooney } 3034c87aefeSPatrick Mooney 3044c87aefeSPatrick Mooney mevent_qunlock(); 3054c87aefeSPatrick Mooney 3064c87aefeSPatrick Mooney return (i); 3074c87aefeSPatrick Mooney } 3084c87aefeSPatrick Mooney 3094c87aefeSPatrick Mooney static void 3104c87aefeSPatrick Mooney mevent_handle(struct kevent *kev, int numev) 3114c87aefeSPatrick Mooney { 3124c87aefeSPatrick Mooney struct mevent *mevp; 3134c87aefeSPatrick Mooney int i; 3144c87aefeSPatrick Mooney 3154c87aefeSPatrick Mooney for (i = 0; i < numev; i++) { 3164c87aefeSPatrick Mooney mevp = kev[i].udata; 3174c87aefeSPatrick Mooney 3184c87aefeSPatrick Mooney /* XXX check for EV_ERROR ? */ 3194c87aefeSPatrick Mooney 3204c87aefeSPatrick Mooney (*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param); 3214c87aefeSPatrick Mooney } 3224c87aefeSPatrick Mooney } 3234c87aefeSPatrick Mooney 3244c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 3254c87aefeSPatrick Mooney 326154972afSPatrick Mooney static boolean_t 327154972afSPatrick Mooney mevent_clarify_state(struct mevent *mevp) 328154972afSPatrick Mooney { 329154972afSPatrick Mooney const int state = mevp->me_state; 330154972afSPatrick Mooney 331154972afSPatrick Mooney if ((state & EV_DELETE) != 0) { 332154972afSPatrick Mooney /* All other intents are overriden by delete. */ 333154972afSPatrick Mooney mevp->me_state = EV_DELETE; 334154972afSPatrick Mooney return (B_TRUE); 335154972afSPatrick Mooney } 336154972afSPatrick Mooney 337154972afSPatrick Mooney /* 338154972afSPatrick Mooney * Without a distinction between EV_ADD and EV_ENABLE in our emulation, 339154972afSPatrick Mooney * handling the add-disabled case means eliding the portfs operation 340154972afSPatrick Mooney * when both flags are present. 341154972afSPatrick Mooney * 342154972afSPatrick Mooney * This is not a concern for subsequent enable/disable operations, as 343154972afSPatrick Mooney * mevent_update() toggles the flags properly so they are not left in 344154972afSPatrick Mooney * conflict. 345154972afSPatrick Mooney */ 346154972afSPatrick Mooney if (state == (EV_ENABLE|EV_DISABLE)) { 347154972afSPatrick Mooney mevp->me_state = EV_DISABLE; 348154972afSPatrick Mooney return (B_FALSE); 349154972afSPatrick Mooney } 350154972afSPatrick Mooney 351154972afSPatrick Mooney return (B_TRUE); 352154972afSPatrick Mooney } 353154972afSPatrick Mooney 3544c87aefeSPatrick Mooney static void 355251becc8SAndy Fiddaman mevent_poll_file_attrib(int fd, enum ev_type type, void *param) 3564c87aefeSPatrick Mooney { 357251becc8SAndy Fiddaman struct mevent *mevp = param; 358251becc8SAndy Fiddaman struct stat st; 3594c87aefeSPatrick Mooney 360251becc8SAndy Fiddaman if (fstat(mevp->me_poll.mp_fd, &st) != 0) { 361e8d71297SAndy Fiddaman (void) fprintf(stderr, "%s: fstat(%d) failed: %s\n", 362e8d71297SAndy Fiddaman __func__, fd, strerror(errno)); 363251becc8SAndy Fiddaman return; 364251becc8SAndy Fiddaman } 3654c87aefeSPatrick Mooney 366e8d71297SAndy Fiddaman /* 367e8d71297SAndy Fiddaman * The only current consumer of file attribute monitoring is 368e8d71297SAndy Fiddaman * blockif, which wants to know about size changes. 369e8d71297SAndy Fiddaman */ 370e8d71297SAndy Fiddaman if (mevp->me_poll.mp_size != st.st_size) { 371251becc8SAndy Fiddaman mevp->me_poll.mp_size = st.st_size; 3724c87aefeSPatrick Mooney 373251becc8SAndy Fiddaman (*mevp->me_poll.mp_func)(mevp->me_poll.mp_fd, EVF_VNODE, 374251becc8SAndy Fiddaman mevp->me_poll.mp_param); 375251becc8SAndy Fiddaman } 376251becc8SAndy Fiddaman } 3774c87aefeSPatrick Mooney 378251becc8SAndy Fiddaman static void 379251becc8SAndy Fiddaman mevent_update_one_readwrite(struct mevent *mevp) 380251becc8SAndy Fiddaman { 381251becc8SAndy Fiddaman int portfd = mevp->me_notify.portnfy_port; 382251becc8SAndy Fiddaman 383251becc8SAndy Fiddaman mevp->me_auto_requeue = B_FALSE; 384251becc8SAndy Fiddaman 385251becc8SAndy Fiddaman switch (mevp->me_state) { 386251becc8SAndy Fiddaman case EV_ENABLE: 387251becc8SAndy Fiddaman { 388251becc8SAndy Fiddaman const int events = (mevp->me_type == EVF_READ) ? 389251becc8SAndy Fiddaman POLLIN : POLLOUT; 390251becc8SAndy Fiddaman 391251becc8SAndy Fiddaman if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd, 392251becc8SAndy Fiddaman events, mevp) != 0) { 393251becc8SAndy Fiddaman (void) fprintf(stderr, 394251becc8SAndy Fiddaman "port_associate fd %d %p failed: %s\n", 395251becc8SAndy Fiddaman mevp->me_fd, mevp, strerror(errno)); 3964c87aefeSPatrick Mooney } 397251becc8SAndy Fiddaman return; 398251becc8SAndy Fiddaman } 399251becc8SAndy Fiddaman case EV_DISABLE: 400251becc8SAndy Fiddaman case EV_DELETE: 401251becc8SAndy Fiddaman /* 402251becc8SAndy Fiddaman * A disable that comes in while an event is being 403251becc8SAndy Fiddaman * handled will result in an ENOENT. 404251becc8SAndy Fiddaman */ 405251becc8SAndy Fiddaman if (port_dissociate(portfd, PORT_SOURCE_FD, 406251becc8SAndy Fiddaman mevp->me_fd) != 0 && errno != ENOENT) { 407251becc8SAndy Fiddaman (void) fprintf(stderr, "port_dissociate " 408251becc8SAndy Fiddaman "portfd %d fd %d mevp %p failed: %s\n", 409251becc8SAndy Fiddaman portfd, mevp->me_fd, mevp, strerror(errno)); 4104c87aefeSPatrick Mooney } 411251becc8SAndy Fiddaman return; 412251becc8SAndy Fiddaman default: 413251becc8SAndy Fiddaman (void) fprintf(stderr, "%s: unhandled state %d\n", __func__, 414251becc8SAndy Fiddaman mevp->me_state); 415251becc8SAndy Fiddaman abort(); 416251becc8SAndy Fiddaman } 417251becc8SAndy Fiddaman } 4184c87aefeSPatrick Mooney 419251becc8SAndy Fiddaman static void 420251becc8SAndy Fiddaman mevent_update_one_timer(struct mevent *mevp) 421251becc8SAndy Fiddaman { 422251becc8SAndy Fiddaman mevp->me_auto_requeue = B_TRUE; 4234c87aefeSPatrick Mooney 424251becc8SAndy Fiddaman switch (mevp->me_state) { 425251becc8SAndy Fiddaman case EV_ENABLE: 426251becc8SAndy Fiddaman { 427251becc8SAndy Fiddaman struct itimerspec it = { 0 }; 4284c87aefeSPatrick Mooney 429251becc8SAndy Fiddaman mevp->me_sigev.sigev_notify = SIGEV_PORT; 430251becc8SAndy Fiddaman mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify; 4314c87aefeSPatrick Mooney 432251becc8SAndy Fiddaman if (timer_create(CLOCK_REALTIME, &mevp->me_sigev, 433251becc8SAndy Fiddaman &mevp->me_timid) != 0) { 434251becc8SAndy Fiddaman (void) fprintf(stderr, "timer_create failed: %s", 435251becc8SAndy Fiddaman strerror(errno)); 436251becc8SAndy Fiddaman return; 437251becc8SAndy Fiddaman } 4384c87aefeSPatrick Mooney 439251becc8SAndy Fiddaman /* The first timeout */ 440251becc8SAndy Fiddaman it.it_value.tv_sec = mevp->me_msecs / MILLISEC; 441251becc8SAndy Fiddaman it.it_value.tv_nsec = 442251becc8SAndy Fiddaman MSEC2NSEC(mevp->me_msecs % MILLISEC); 443251becc8SAndy Fiddaman /* Repeat at the same interval */ 444251becc8SAndy Fiddaman it.it_interval = it.it_value; 4454c87aefeSPatrick Mooney 446251becc8SAndy Fiddaman if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) { 447251becc8SAndy Fiddaman (void) fprintf(stderr, "timer_settime failed: %s", 448251becc8SAndy Fiddaman strerror(errno)); 4494c87aefeSPatrick Mooney } 450251becc8SAndy Fiddaman return; 451251becc8SAndy Fiddaman } 452251becc8SAndy Fiddaman case EV_DISABLE: 453251becc8SAndy Fiddaman case EV_DELETE: 454251becc8SAndy Fiddaman if (timer_delete(mevp->me_timid) != 0) { 455251becc8SAndy Fiddaman (void) fprintf(stderr, "timer_delete failed: %s", 456251becc8SAndy Fiddaman strerror(errno)); 4574c87aefeSPatrick Mooney } 458251becc8SAndy Fiddaman mevp->me_timid = -1; 459251becc8SAndy Fiddaman return; 460251becc8SAndy Fiddaman default: 461251becc8SAndy Fiddaman (void) fprintf(stderr, "%s: unhandled state %d\n", __func__, 462251becc8SAndy Fiddaman mevp->me_state); 463251becc8SAndy Fiddaman abort(); 464251becc8SAndy Fiddaman } 465251becc8SAndy Fiddaman } 466b0de25cbSAndy Fiddaman 467251becc8SAndy Fiddaman static void 468251becc8SAndy Fiddaman mevent_update_one_vnode(struct mevent *mevp) 469251becc8SAndy Fiddaman { 470251becc8SAndy Fiddaman switch (mevp->me_state) { 471251becc8SAndy Fiddaman case EV_ENABLE: 472251becc8SAndy Fiddaman { 473e8d71297SAndy Fiddaman struct stat st; 474251becc8SAndy Fiddaman int events = 0; 475b0de25cbSAndy Fiddaman 476251becc8SAndy Fiddaman if ((mevp->me_fflags & EVFF_ATTRIB) != 0) 477251becc8SAndy Fiddaman events |= FILE_ATTRIB; 478b0de25cbSAndy Fiddaman 479251becc8SAndy Fiddaman assert(events != 0); 480251becc8SAndy Fiddaman 481e8d71297SAndy Fiddaman /* 482e8d71297SAndy Fiddaman * It is tempting to use the PORT_SOURCE_FILE type for this in 483e8d71297SAndy Fiddaman * conjunction with the FILE_ATTRIB event type. Unfortunately 484e8d71297SAndy Fiddaman * this event type triggers on any change to the file's 485e8d71297SAndy Fiddaman * ctime, and therefore for every write as well as attribute 486e8d71297SAndy Fiddaman * changes. It also does not work for ZVOLs. 487e8d71297SAndy Fiddaman * 488e8d71297SAndy Fiddaman * Convert this to a timer event and poll for the file 489e8d71297SAndy Fiddaman * attribute changes that we care about. 490e8d71297SAndy Fiddaman */ 491251becc8SAndy Fiddaman 492e8d71297SAndy Fiddaman if (fstat(mevp->me_fd, &st) != 0) { 493e8d71297SAndy Fiddaman (void) fprintf(stderr, "fstat(%d) failed: %s\n", 494e8d71297SAndy Fiddaman mevp->me_fd, strerror(errno)); 495e8d71297SAndy Fiddaman return; 496e8d71297SAndy Fiddaman } 497b0de25cbSAndy Fiddaman 498e8d71297SAndy Fiddaman mevp->me_poll.mp_fd = mevp->me_fd; 499e8d71297SAndy Fiddaman mevp->me_poll.mp_size = st.st_size; 500251becc8SAndy Fiddaman 501e8d71297SAndy Fiddaman mevp->me_poll.mp_func = mevp->me_func; 502e8d71297SAndy Fiddaman mevp->me_poll.mp_param = mevp->me_param; 503e8d71297SAndy Fiddaman mevp->me_func = mevent_poll_file_attrib; 504e8d71297SAndy Fiddaman mevp->me_param = mevp; 505251becc8SAndy Fiddaman 506e8d71297SAndy Fiddaman mevp->me_type = EVF_TIMER; 507e8d71297SAndy Fiddaman mevp->me_timid = -1; 508e8d71297SAndy Fiddaman mevp->me_msecs = mevent_file_poll_interval_ms; 509e8d71297SAndy Fiddaman mevent_update_one_timer(mevp); 510251becc8SAndy Fiddaman 511251becc8SAndy Fiddaman return; 512251becc8SAndy Fiddaman } 513251becc8SAndy Fiddaman case EV_DISABLE: 514251becc8SAndy Fiddaman case EV_DELETE: 515251becc8SAndy Fiddaman /* 516e8d71297SAndy Fiddaman * These events do not really exist as they are converted to 517e8d71297SAndy Fiddaman * timers; fall through to abort. 518251becc8SAndy Fiddaman */ 5194c87aefeSPatrick Mooney default: 520251becc8SAndy Fiddaman (void) fprintf(stderr, "%s: unhandled state %d\n", __func__, 521251becc8SAndy Fiddaman mevp->me_state); 522251becc8SAndy Fiddaman abort(); 5234c87aefeSPatrick Mooney } 524251becc8SAndy Fiddaman } 5254c87aefeSPatrick Mooney 526251becc8SAndy Fiddaman static void 527251becc8SAndy Fiddaman mevent_update_one(struct mevent *mevp) 528251becc8SAndy Fiddaman { 529251becc8SAndy Fiddaman switch (mevp->me_type) { 530251becc8SAndy Fiddaman case EVF_READ: 531251becc8SAndy Fiddaman case EVF_WRITE: 532251becc8SAndy Fiddaman mevent_update_one_readwrite(mevp); 533251becc8SAndy Fiddaman break; 534251becc8SAndy Fiddaman case EVF_TIMER: 535251becc8SAndy Fiddaman mevent_update_one_timer(mevp); 536251becc8SAndy Fiddaman break; 537251becc8SAndy Fiddaman case EVF_VNODE: 538251becc8SAndy Fiddaman mevent_update_one_vnode(mevp); 539251becc8SAndy Fiddaman break; 540251becc8SAndy Fiddaman case EVF_SIGNAL: /* EVF_SIGNAL not yet implemented. */ 541251becc8SAndy Fiddaman default: 542251becc8SAndy Fiddaman (void) fprintf(stderr, "%s: unhandled event type %d\n", 543251becc8SAndy Fiddaman __func__, mevp->me_type); 544251becc8SAndy Fiddaman abort(); 545251becc8SAndy Fiddaman } 5464c87aefeSPatrick Mooney } 5474c87aefeSPatrick Mooney 5484c87aefeSPatrick Mooney static void 549b0de25cbSAndy Fiddaman mevent_populate(struct mevent *mevp) 550b0de25cbSAndy Fiddaman { 551b0de25cbSAndy Fiddaman mevp->me_notify.portnfy_port = mfd; 552b0de25cbSAndy Fiddaman mevp->me_notify.portnfy_user = mevp; 553b0de25cbSAndy Fiddaman } 554b0de25cbSAndy Fiddaman 555b0de25cbSAndy Fiddaman static void 556b0de25cbSAndy Fiddaman mevent_update_pending() 5574c87aefeSPatrick Mooney { 5584c87aefeSPatrick Mooney struct mevent *mevp, *tmpp; 5594c87aefeSPatrick Mooney 5604c87aefeSPatrick Mooney mevent_qlock(); 5614c87aefeSPatrick Mooney 5624c87aefeSPatrick Mooney LIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) { 563b0de25cbSAndy Fiddaman mevent_populate(mevp); 5644c87aefeSPatrick Mooney if (mevp->me_closefd) { 5654c87aefeSPatrick Mooney /* 5664c87aefeSPatrick Mooney * A close of the file descriptor will remove the 5674c87aefeSPatrick Mooney * event 5684c87aefeSPatrick Mooney */ 5694c87aefeSPatrick Mooney (void) close(mevp->me_fd); 5704c87aefeSPatrick Mooney mevp->me_fd = -1; 5714c87aefeSPatrick Mooney } else { 572154972afSPatrick Mooney if (mevent_clarify_state(mevp)) { 573154972afSPatrick Mooney mevent_update_one(mevp); 574154972afSPatrick Mooney } 5754c87aefeSPatrick Mooney } 5764c87aefeSPatrick Mooney 5774c87aefeSPatrick Mooney mevp->me_cq = 0; 5784c87aefeSPatrick Mooney LIST_REMOVE(mevp, me_list); 5794c87aefeSPatrick Mooney 580154972afSPatrick Mooney if (mevp->me_state & EV_DELETE) { 5814c87aefeSPatrick Mooney free(mevp); 5824c87aefeSPatrick Mooney } else { 5834c87aefeSPatrick Mooney LIST_INSERT_HEAD(&global_head, mevp, me_list); 5844c87aefeSPatrick Mooney } 5854c87aefeSPatrick Mooney } 5864c87aefeSPatrick Mooney 5874c87aefeSPatrick Mooney mevent_qunlock(); 5884c87aefeSPatrick Mooney } 5894c87aefeSPatrick Mooney 5904c87aefeSPatrick Mooney static void 5914c87aefeSPatrick Mooney mevent_handle_pe(port_event_t *pe) 5924c87aefeSPatrick Mooney { 5934c87aefeSPatrick Mooney struct mevent *mevp = pe->portev_user; 5944c87aefeSPatrick Mooney 5954c87aefeSPatrick Mooney (*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param); 5964c87aefeSPatrick Mooney 5974c87aefeSPatrick Mooney mevent_qlock(); 5984c87aefeSPatrick Mooney if (!mevp->me_cq && !mevp->me_auto_requeue) { 5994c87aefeSPatrick Mooney mevent_update_one(mevp); 6004c87aefeSPatrick Mooney } 6014c87aefeSPatrick Mooney mevent_qunlock(); 6024c87aefeSPatrick Mooney } 6034c87aefeSPatrick Mooney #endif 6044c87aefeSPatrick Mooney 605154972afSPatrick Mooney static struct mevent * 606154972afSPatrick Mooney mevent_add_state(int tfd, enum ev_type type, 607154972afSPatrick Mooney void (*func)(int, enum ev_type, void *), void *param, 608b0de25cbSAndy Fiddaman int state, int fflags) 6094c87aefeSPatrick Mooney { 610b0de25cbSAndy Fiddaman #ifdef __FreeBSD__ 611b0de25cbSAndy Fiddaman struct kevent kev; 612b0de25cbSAndy Fiddaman #endif 6134c87aefeSPatrick Mooney struct mevent *lp, *mevp; 614b0de25cbSAndy Fiddaman #ifdef __FreeBSD__ 615b0de25cbSAndy Fiddaman int ret; 616b0de25cbSAndy Fiddaman #endif 6174c87aefeSPatrick Mooney 6184c87aefeSPatrick Mooney if (tfd < 0 || func == NULL) { 6194c87aefeSPatrick Mooney return (NULL); 6204c87aefeSPatrick Mooney } 6214c87aefeSPatrick Mooney 6224c87aefeSPatrick Mooney mevp = NULL; 6234c87aefeSPatrick Mooney 624b0de25cbSAndy Fiddaman pthread_once(&mevent_once, mevent_init); 625b0de25cbSAndy Fiddaman 6264c87aefeSPatrick Mooney mevent_qlock(); 6274c87aefeSPatrick Mooney 6284c87aefeSPatrick Mooney /* 6294c87aefeSPatrick Mooney * Verify that the fd/type tuple is not present in any list 6304c87aefeSPatrick Mooney */ 6314c87aefeSPatrick Mooney LIST_FOREACH(lp, &global_head, me_list) { 6324c87aefeSPatrick Mooney if (type != EVF_TIMER && lp->me_fd == tfd && 6334c87aefeSPatrick Mooney lp->me_type == type) { 6344c87aefeSPatrick Mooney goto exit; 6354c87aefeSPatrick Mooney } 6364c87aefeSPatrick Mooney } 6374c87aefeSPatrick Mooney 6384c87aefeSPatrick Mooney LIST_FOREACH(lp, &change_head, me_list) { 6394c87aefeSPatrick Mooney if (type != EVF_TIMER && lp->me_fd == tfd && 6404c87aefeSPatrick Mooney lp->me_type == type) { 6414c87aefeSPatrick Mooney goto exit; 6424c87aefeSPatrick Mooney } 6434c87aefeSPatrick Mooney } 6444c87aefeSPatrick Mooney 6454c87aefeSPatrick Mooney /* 646b0de25cbSAndy Fiddaman * Allocate an entry and populate it. 6474c87aefeSPatrick Mooney */ 6484c87aefeSPatrick Mooney mevp = calloc(1, sizeof(struct mevent)); 6494c87aefeSPatrick Mooney if (mevp == NULL) { 6504c87aefeSPatrick Mooney goto exit; 6514c87aefeSPatrick Mooney } 6524c87aefeSPatrick Mooney 6534c87aefeSPatrick Mooney if (type == EVF_TIMER) { 6544c87aefeSPatrick Mooney mevp->me_msecs = tfd; 655251becc8SAndy Fiddaman #ifdef __FreeBSD__ 6564c87aefeSPatrick Mooney mevp->me_timid = mevent_timid++; 657251becc8SAndy Fiddaman #else 658251becc8SAndy Fiddaman mevp->me_timid = -1; 659251becc8SAndy Fiddaman #endif 6604c87aefeSPatrick Mooney } else 6614c87aefeSPatrick Mooney mevp->me_fd = tfd; 6624c87aefeSPatrick Mooney mevp->me_type = type; 6634c87aefeSPatrick Mooney mevp->me_func = func; 6644c87aefeSPatrick Mooney mevp->me_param = param; 665154972afSPatrick Mooney mevp->me_state = state; 666b0de25cbSAndy Fiddaman mevp->me_fflags = fflags; 667b0de25cbSAndy Fiddaman 668b0de25cbSAndy Fiddaman /* 669b0de25cbSAndy Fiddaman * Try to add the event. If this fails, report the failure to 670b0de25cbSAndy Fiddaman * the caller. 671b0de25cbSAndy Fiddaman */ 672b0de25cbSAndy Fiddaman #ifdef __FreeBSD__ 673b0de25cbSAndy Fiddaman mevent_populate(mevp, &kev); 674b0de25cbSAndy Fiddaman ret = kevent(mfd, &kev, 1, NULL, 0, NULL); 675b0de25cbSAndy Fiddaman if (ret == -1) { 676b0de25cbSAndy Fiddaman free(mevp); 677b0de25cbSAndy Fiddaman mevp = NULL; 678b0de25cbSAndy Fiddaman goto exit; 679b0de25cbSAndy Fiddaman } 680b0de25cbSAndy Fiddaman mevp->me_state &= ~EV_ADD; 681b0de25cbSAndy Fiddaman #else 682b0de25cbSAndy Fiddaman mevent_populate(mevp); 683b0de25cbSAndy Fiddaman if (mevent_clarify_state(mevp)) 684b0de25cbSAndy Fiddaman mevent_update_one(mevp); 685b0de25cbSAndy Fiddaman #endif 686b0de25cbSAndy Fiddaman 687b0de25cbSAndy Fiddaman LIST_INSERT_HEAD(&global_head, mevp, me_list); 6884c87aefeSPatrick Mooney 6894c87aefeSPatrick Mooney exit: 6904c87aefeSPatrick Mooney mevent_qunlock(); 6914c87aefeSPatrick Mooney 6924c87aefeSPatrick Mooney return (mevp); 6934c87aefeSPatrick Mooney } 6944c87aefeSPatrick Mooney 695154972afSPatrick Mooney struct mevent * 696154972afSPatrick Mooney mevent_add(int tfd, enum ev_type type, 697154972afSPatrick Mooney void (*func)(int, enum ev_type, void *), void *param) 698154972afSPatrick Mooney { 699154972afSPatrick Mooney 700b0de25cbSAndy Fiddaman return (mevent_add_state(tfd, type, func, param, EV_ADD, 0)); 701b0de25cbSAndy Fiddaman } 702b0de25cbSAndy Fiddaman 703b0de25cbSAndy Fiddaman struct mevent * 704b0de25cbSAndy Fiddaman mevent_add_flags(int tfd, enum ev_type type, int fflags, 705b0de25cbSAndy Fiddaman void (*func)(int, enum ev_type, void *), void *param) 706b0de25cbSAndy Fiddaman { 707b0de25cbSAndy Fiddaman 708b0de25cbSAndy Fiddaman return (mevent_add_state(tfd, type, func, param, EV_ADD, fflags)); 709154972afSPatrick Mooney } 710154972afSPatrick Mooney 711154972afSPatrick Mooney struct mevent * 712154972afSPatrick Mooney mevent_add_disabled(int tfd, enum ev_type type, 713154972afSPatrick Mooney void (*func)(int, enum ev_type, void *), void *param) 714154972afSPatrick Mooney { 715154972afSPatrick Mooney 716b0de25cbSAndy Fiddaman return (mevent_add_state(tfd, type, func, param, EV_ADD | EV_DISABLE, 0)); 717154972afSPatrick Mooney } 718154972afSPatrick Mooney 7194c87aefeSPatrick Mooney static int 720154972afSPatrick Mooney mevent_update(struct mevent *evp, bool enable) 7214c87aefeSPatrick Mooney { 722154972afSPatrick Mooney int newstate; 723154972afSPatrick Mooney 724154972afSPatrick Mooney mevent_qlock(); 725154972afSPatrick Mooney 7264c87aefeSPatrick Mooney /* 7274c87aefeSPatrick Mooney * It's not possible to enable/disable a deleted event 7284c87aefeSPatrick Mooney */ 729154972afSPatrick Mooney assert((evp->me_state & EV_DELETE) == 0); 730154972afSPatrick Mooney 731154972afSPatrick Mooney newstate = evp->me_state; 732154972afSPatrick Mooney if (enable) { 733154972afSPatrick Mooney newstate |= EV_ENABLE; 734154972afSPatrick Mooney newstate &= ~EV_DISABLE; 735154972afSPatrick Mooney } else { 736154972afSPatrick Mooney newstate |= EV_DISABLE; 737154972afSPatrick Mooney newstate &= ~EV_ENABLE; 738154972afSPatrick Mooney } 7394c87aefeSPatrick Mooney 7404c87aefeSPatrick Mooney /* 7414c87aefeSPatrick Mooney * No update needed if state isn't changing 7424c87aefeSPatrick Mooney */ 743154972afSPatrick Mooney if (evp->me_state != newstate) { 744154972afSPatrick Mooney evp->me_state = newstate; 745154972afSPatrick Mooney 746154972afSPatrick Mooney /* 747154972afSPatrick Mooney * Place the entry onto the changed list if not 748154972afSPatrick Mooney * already there. 749154972afSPatrick Mooney */ 750154972afSPatrick Mooney if (evp->me_cq == 0) { 751154972afSPatrick Mooney evp->me_cq = 1; 752154972afSPatrick Mooney LIST_REMOVE(evp, me_list); 753154972afSPatrick Mooney LIST_INSERT_HEAD(&change_head, evp, me_list); 754154972afSPatrick Mooney mevent_notify(); 755154972afSPatrick Mooney } 7564c87aefeSPatrick Mooney } 7574c87aefeSPatrick Mooney 7584c87aefeSPatrick Mooney mevent_qunlock(); 7594c87aefeSPatrick Mooney 7604c87aefeSPatrick Mooney return (0); 7614c87aefeSPatrick Mooney } 7624c87aefeSPatrick Mooney 7634c87aefeSPatrick Mooney int 7644c87aefeSPatrick Mooney mevent_enable(struct mevent *evp) 7654c87aefeSPatrick Mooney { 7664c87aefeSPatrick Mooney 767154972afSPatrick Mooney return (mevent_update(evp, true)); 7684c87aefeSPatrick Mooney } 7694c87aefeSPatrick Mooney 7704c87aefeSPatrick Mooney int 7714c87aefeSPatrick Mooney mevent_disable(struct mevent *evp) 7724c87aefeSPatrick Mooney { 7734c87aefeSPatrick Mooney 774154972afSPatrick Mooney return (mevent_update(evp, false)); 7754c87aefeSPatrick Mooney } 7764c87aefeSPatrick Mooney 7774c87aefeSPatrick Mooney static int 7784c87aefeSPatrick Mooney mevent_delete_event(struct mevent *evp, int closefd) 7794c87aefeSPatrick Mooney { 7804c87aefeSPatrick Mooney mevent_qlock(); 7814c87aefeSPatrick Mooney 7824c87aefeSPatrick Mooney /* 7834c87aefeSPatrick Mooney * Place the entry onto the changed list if not already there, and 7844c87aefeSPatrick Mooney * mark as to be deleted. 7854c87aefeSPatrick Mooney */ 7864c87aefeSPatrick Mooney if (evp->me_cq == 0) { 7874c87aefeSPatrick Mooney evp->me_cq = 1; 7884c87aefeSPatrick Mooney LIST_REMOVE(evp, me_list); 7894c87aefeSPatrick Mooney LIST_INSERT_HEAD(&change_head, evp, me_list); 7904c87aefeSPatrick Mooney mevent_notify(); 7914c87aefeSPatrick Mooney } 792154972afSPatrick Mooney evp->me_state = EV_DELETE; 7934c87aefeSPatrick Mooney 7944c87aefeSPatrick Mooney if (closefd) 7954c87aefeSPatrick Mooney evp->me_closefd = 1; 7964c87aefeSPatrick Mooney 7974c87aefeSPatrick Mooney mevent_qunlock(); 7984c87aefeSPatrick Mooney 7994c87aefeSPatrick Mooney return (0); 8004c87aefeSPatrick Mooney } 8014c87aefeSPatrick Mooney 8024c87aefeSPatrick Mooney int 8034c87aefeSPatrick Mooney mevent_delete(struct mevent *evp) 8044c87aefeSPatrick Mooney { 8054c87aefeSPatrick Mooney 8064c87aefeSPatrick Mooney return (mevent_delete_event(evp, 0)); 8074c87aefeSPatrick Mooney } 8084c87aefeSPatrick Mooney 8094c87aefeSPatrick Mooney int 8104c87aefeSPatrick Mooney mevent_delete_close(struct mevent *evp) 8114c87aefeSPatrick Mooney { 8124c87aefeSPatrick Mooney 8134c87aefeSPatrick Mooney return (mevent_delete_event(evp, 1)); 8144c87aefeSPatrick Mooney } 8154c87aefeSPatrick Mooney 8164c87aefeSPatrick Mooney static void 8174c87aefeSPatrick Mooney mevent_set_name(void) 8184c87aefeSPatrick Mooney { 8194c87aefeSPatrick Mooney 8204c87aefeSPatrick Mooney pthread_set_name_np(mevent_tid, "mevent"); 8214c87aefeSPatrick Mooney } 8224c87aefeSPatrick Mooney 8234c87aefeSPatrick Mooney void 8244c87aefeSPatrick Mooney mevent_dispatch(void) 8254c87aefeSPatrick Mooney { 8264c87aefeSPatrick Mooney #ifdef __FreeBSD__ 8274c87aefeSPatrick Mooney struct kevent changelist[MEVENT_MAX]; 8284c87aefeSPatrick Mooney struct kevent eventlist[MEVENT_MAX]; 8294c87aefeSPatrick Mooney struct mevent *pipev; 8304c87aefeSPatrick Mooney int numev; 8314c87aefeSPatrick Mooney #else 8324c87aefeSPatrick Mooney struct mevent *pipev; 8334c87aefeSPatrick Mooney #endif 8344c87aefeSPatrick Mooney int ret; 8354c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 8364c87aefeSPatrick Mooney cap_rights_t rights; 8374c87aefeSPatrick Mooney #endif 8384c87aefeSPatrick Mooney 8394c87aefeSPatrick Mooney mevent_tid = pthread_self(); 8404c87aefeSPatrick Mooney mevent_set_name(); 8414c87aefeSPatrick Mooney 842b0de25cbSAndy Fiddaman pthread_once(&mevent_once, mevent_init); 8434c87aefeSPatrick Mooney 8444c87aefeSPatrick Mooney /* 8454c87aefeSPatrick Mooney * Open the pipe that will be used for other threads to force 8464c87aefeSPatrick Mooney * the blocking kqueue call to exit by writing to it. Set the 8474c87aefeSPatrick Mooney * descriptor to non-blocking. 8484c87aefeSPatrick Mooney */ 8494c87aefeSPatrick Mooney ret = pipe(mevent_pipefd); 8504c87aefeSPatrick Mooney if (ret < 0) { 8514c87aefeSPatrick Mooney perror("pipe"); 8524c87aefeSPatrick Mooney exit(0); 8534c87aefeSPatrick Mooney } 8544c87aefeSPatrick Mooney 8554c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 8564c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE); 8574c87aefeSPatrick Mooney if (caph_rights_limit(mevent_pipefd[0], &rights) == -1) 8584c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 8594c87aefeSPatrick Mooney if (caph_rights_limit(mevent_pipefd[1], &rights) == -1) 8604c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 8614c87aefeSPatrick Mooney #endif 8624c87aefeSPatrick Mooney 8634c87aefeSPatrick Mooney /* 8644c87aefeSPatrick Mooney * Add internal event handler for the pipe write fd 8654c87aefeSPatrick Mooney */ 8664c87aefeSPatrick Mooney pipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL); 8674c87aefeSPatrick Mooney assert(pipev != NULL); 8684c87aefeSPatrick Mooney 8694c87aefeSPatrick Mooney for (;;) { 8704c87aefeSPatrick Mooney #ifdef __FreeBSD__ 8714c87aefeSPatrick Mooney /* 8724c87aefeSPatrick Mooney * Build changelist if required. 8734c87aefeSPatrick Mooney * XXX the changelist can be put into the blocking call 8744c87aefeSPatrick Mooney * to eliminate the extra syscall. Currently better for 8754c87aefeSPatrick Mooney * debug. 8764c87aefeSPatrick Mooney */ 877b0de25cbSAndy Fiddaman numev = mevent_build(changelist); 8784c87aefeSPatrick Mooney if (numev) { 8794c87aefeSPatrick Mooney ret = kevent(mfd, changelist, numev, NULL, 0, NULL); 8804c87aefeSPatrick Mooney if (ret == -1) { 8814c87aefeSPatrick Mooney perror("Error return from kevent change"); 8824c87aefeSPatrick Mooney } 8834c87aefeSPatrick Mooney } 8844c87aefeSPatrick Mooney 8854c87aefeSPatrick Mooney /* 8864c87aefeSPatrick Mooney * Block awaiting events 8874c87aefeSPatrick Mooney */ 8884c87aefeSPatrick Mooney ret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL); 8894c87aefeSPatrick Mooney if (ret == -1 && errno != EINTR) { 8904c87aefeSPatrick Mooney perror("Error return from kevent monitor"); 8914c87aefeSPatrick Mooney } 8926dc98349SAndy Fiddaman 8934c87aefeSPatrick Mooney /* 8944c87aefeSPatrick Mooney * Handle reported events 8954c87aefeSPatrick Mooney */ 8964c87aefeSPatrick Mooney mevent_handle(eventlist, ret); 8974c87aefeSPatrick Mooney 8984c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 8994c87aefeSPatrick Mooney port_event_t pev; 9004c87aefeSPatrick Mooney 9014c87aefeSPatrick Mooney /* Handle any pending updates */ 902b0de25cbSAndy Fiddaman mevent_update_pending(); 9034c87aefeSPatrick Mooney 9044c87aefeSPatrick Mooney /* Block awaiting events */ 905b0de25cbSAndy Fiddaman ret = port_get(mfd, &pev, NULL); 906cf7690ebSMike Zeller if (ret != 0) { 907cf7690ebSMike Zeller if (errno != EINTR) 908cf7690ebSMike Zeller perror("Error return from port_get"); 9094c87aefeSPatrick Mooney continue; 9104c87aefeSPatrick Mooney } 9114c87aefeSPatrick Mooney 9124c87aefeSPatrick Mooney /* Handle reported event */ 9134c87aefeSPatrick Mooney mevent_handle_pe(&pev); 9144c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 9156dc98349SAndy Fiddaman } 9164c87aefeSPatrick Mooney } 917