1*3d729aecSJerry Jelinek /* 2*3d729aecSJerry Jelinek * This file and its contents are supplied under the terms of the 3*3d729aecSJerry Jelinek * Common Development and Distribution License ("CDDL"), version 1.0. 4*3d729aecSJerry Jelinek * You may only use this file in accordance with the terms of version 5*3d729aecSJerry Jelinek * 1.0 of the CDDL. 6*3d729aecSJerry Jelinek * 7*3d729aecSJerry Jelinek * A full copy of the text of the CDDL should have accompanied this 8*3d729aecSJerry Jelinek * source. A copy of the CDDL is also available via the Internet at 9*3d729aecSJerry Jelinek * http://www.illumos.org/license/CDDL. 10*3d729aecSJerry Jelinek */ 11*3d729aecSJerry Jelinek 12*3d729aecSJerry Jelinek /* 13*3d729aecSJerry Jelinek * Copyright 2015 Joyent, Inc. 14*3d729aecSJerry Jelinek */ 15*3d729aecSJerry Jelinek 16*3d729aecSJerry Jelinek /* 17*3d729aecSJerry Jelinek * Support for the signalfd facility, a Linux-borne facility for 18*3d729aecSJerry Jelinek * file descriptor-based synchronous signal consumption. 19*3d729aecSJerry Jelinek * 20*3d729aecSJerry Jelinek * As described on the signalfd(3C) man page, the general idea behind these 21*3d729aecSJerry Jelinek * file descriptors is that they can be used to synchronously consume signals 22*3d729aecSJerry Jelinek * via the read(2) syscall. That capability already exists with the 23*3d729aecSJerry Jelinek * sigwaitinfo(3C) function but the key advantage of signalfd is that, because 24*3d729aecSJerry Jelinek * it is file descriptor based, poll(2) can be used to determine when signals 25*3d729aecSJerry Jelinek * are available to be consumed. 26*3d729aecSJerry Jelinek * 27*3d729aecSJerry Jelinek * The general implementation uses signalfd_state to hold both the signal set 28*3d729aecSJerry Jelinek * and poll head for an open file descriptor. Because a process can be using 29*3d729aecSJerry Jelinek * different sigfds with different signal sets, each signalfd_state poll head 30*3d729aecSJerry Jelinek * can be thought of as an independent signal stream and the thread(s) waiting 31*3d729aecSJerry Jelinek * on that stream will get poll notification when any signal in the 32*3d729aecSJerry Jelinek * corresponding set is received. 33*3d729aecSJerry Jelinek * 34*3d729aecSJerry Jelinek * The sigfd_proc_state_t struct lives on the proc_t and maintains per-proc 35*3d729aecSJerry Jelinek * state for function callbacks and data when the proc needs to do work during 36*3d729aecSJerry Jelinek * signal delivery for pollwakeup. 37*3d729aecSJerry Jelinek * 38*3d729aecSJerry Jelinek * The read side of the implementation is straightforward and mimics the 39*3d729aecSJerry Jelinek * kernel behavior for sigtimedwait(). Signals continue to live on either 40*3d729aecSJerry Jelinek * the proc's p_sig, or thread's t_sig, member. Read consumes the signal so 41*3d729aecSJerry Jelinek * that it is no longer pending. 42*3d729aecSJerry Jelinek * 43*3d729aecSJerry Jelinek * The poll side is more complex since all of the sigfds on the process need 44*3d729aecSJerry Jelinek * to be examined every time a signal is delivered to the process in order to 45*3d729aecSJerry Jelinek * pollwake any thread waiting in poll for that signal. 46*3d729aecSJerry Jelinek * 47*3d729aecSJerry Jelinek * Because it is likely that a process will only be using one, or a few, sigfds, 48*3d729aecSJerry Jelinek * but many total file descriptors, we maintain a list of sigfds which need 49*3d729aecSJerry Jelinek * pollwakeup. The list lives on the proc's p_sigfd struct. In this way only 50*3d729aecSJerry Jelinek * zero, or a few, of the state structs will need to be examined every time a 51*3d729aecSJerry Jelinek * signal is delivered to the process, instead of having to examine all of the 52*3d729aecSJerry Jelinek * file descriptors to find the state structs. When a state struct with a 53*3d729aecSJerry Jelinek * matching signal set is found then pollwakeup is called. 54*3d729aecSJerry Jelinek * 55*3d729aecSJerry Jelinek * The sigfd_list is self-cleaning; as signalfd_pollwake_cb is called, the list 56*3d729aecSJerry Jelinek * will clear out on its own. There is an exit helper (signalfd_exit_helper) 57*3d729aecSJerry Jelinek * which cleans up any remaining per-proc state when the process exits. 58*3d729aecSJerry Jelinek * 59*3d729aecSJerry Jelinek * The main complexity with signalfd is the interaction of forking and polling. 60*3d729aecSJerry Jelinek * This interaction is complex because now two processes have a fd that 61*3d729aecSJerry Jelinek * references the same dev_t (and its associated signalfd_state), but signals 62*3d729aecSJerry Jelinek * go to only one of those processes. Also, we don't know when one of the 63*3d729aecSJerry Jelinek * processes closes its fd because our 'close' entry point is only called when 64*3d729aecSJerry Jelinek * the last fd is closed (which could be by either process). 65*3d729aecSJerry Jelinek * 66*3d729aecSJerry Jelinek * Because the state struct is referenced by both file descriptors, and the 67*3d729aecSJerry Jelinek * state struct represents a signal stream needing a pollwakeup, if both 68*3d729aecSJerry Jelinek * processes were polling then both processes would get a pollwakeup when a 69*3d729aecSJerry Jelinek * signal arrives for either process (that is, the pollhead is associated with 70*3d729aecSJerry Jelinek * our dev_t so when a signal arrives the pollwakeup wakes up all waiters). 71*3d729aecSJerry Jelinek * 72*3d729aecSJerry Jelinek * Fortunately this is not a common problem in practice, but the implementation 73*3d729aecSJerry Jelinek * attempts to mitigate unexpected behavior. The typical behavior is that the 74*3d729aecSJerry Jelinek * parent has been polling the signalfd (which is why it was open in the first 75*3d729aecSJerry Jelinek * place) and the parent might have a pending signalfd_state (with the 76*3d729aecSJerry Jelinek * pollhead) on its per-process sigfd_list. After the fork the child will 77*3d729aecSJerry Jelinek * simply close that fd (among others) as part of the typical fork/close/exec 78*3d729aecSJerry Jelinek * pattern. Because the child will never poll that fd, it will never get any 79*3d729aecSJerry Jelinek * state onto its own sigfd_list (the child starts with a null list). The 80*3d729aecSJerry Jelinek * intention is that the child sees no pollwakeup activity for signals unless 81*3d729aecSJerry Jelinek * it explicitly reinvokes poll on the sigfd. 82*3d729aecSJerry Jelinek * 83*3d729aecSJerry Jelinek * As background, there are two primary polling cases to consider when the 84*3d729aecSJerry Jelinek * parent process forks: 85*3d729aecSJerry Jelinek * 1) If any thread is blocked in poll(2) then both the parent and child will 86*3d729aecSJerry Jelinek * return from the poll syscall with EINTR. This means that if either 87*3d729aecSJerry Jelinek * process wants to re-poll on a sigfd then it needs to re-run poll and 88*3d729aecSJerry Jelinek * would come back in to the signalfd_poll entry point. The parent would 89*3d729aecSJerry Jelinek * already have the dev_t's state on its sigfd_list and the child would not 90*3d729aecSJerry Jelinek * have anything there unless it called poll again on its fd. 91*3d729aecSJerry Jelinek * 2) If the process is using /dev/poll(7D) then the polling info is being 92*3d729aecSJerry Jelinek * cached by the poll device and the process might not currently be blocked 93*3d729aecSJerry Jelinek * on anything polling related. A subsequent DP_POLL ioctl will not invoke 94*3d729aecSJerry Jelinek * our signalfd_poll entry point again. Because the parent still has its 95*3d729aecSJerry Jelinek * sigfd_list setup, an incoming signal will hit our signalfd_pollwake_cb 96*3d729aecSJerry Jelinek * entry point, which in turn calls pollwake, and /dev/poll will do the 97*3d729aecSJerry Jelinek * right thing on DP_POLL. The child will not have a sigfd_list yet so the 98*3d729aecSJerry Jelinek * signal will not cause a pollwakeup. The dp code does its own handling for 99*3d729aecSJerry Jelinek * cleaning up its cache. 100*3d729aecSJerry Jelinek * 101*3d729aecSJerry Jelinek * This leaves only one odd corner case. If the parent and child both use 102*3d729aecSJerry Jelinek * the dup-ed sigfd to poll then when a signal is delivered to either process 103*3d729aecSJerry Jelinek * there is no way to determine which one should get the pollwakeup (since 104*3d729aecSJerry Jelinek * both processes will be queued on the same signal stream poll head). What 105*3d729aecSJerry Jelinek * happens in this case is that both processes will return from poll, but only 106*3d729aecSJerry Jelinek * one of them will actually have a signal to read. The other will return 107*3d729aecSJerry Jelinek * from read with EAGAIN, or block. This case is actually similar to the 108*3d729aecSJerry Jelinek * situation within a single process which got two different sigfd's with the 109*3d729aecSJerry Jelinek * same mask (or poll on two fd's that are dup-ed). Both would return from poll 110*3d729aecSJerry Jelinek * when a signal arrives but only one read would consume the signal and the 111*3d729aecSJerry Jelinek * other read would fail or block. Applications which poll on shared fd's 112*3d729aecSJerry Jelinek * cannot assume that a subsequent read will actually obtain data. 113*3d729aecSJerry Jelinek */ 114*3d729aecSJerry Jelinek 115*3d729aecSJerry Jelinek #include <sys/ddi.h> 116*3d729aecSJerry Jelinek #include <sys/sunddi.h> 117*3d729aecSJerry Jelinek #include <sys/signalfd.h> 118*3d729aecSJerry Jelinek #include <sys/conf.h> 119*3d729aecSJerry Jelinek #include <sys/sysmacros.h> 120*3d729aecSJerry Jelinek #include <sys/filio.h> 121*3d729aecSJerry Jelinek #include <sys/stat.h> 122*3d729aecSJerry Jelinek #include <sys/file.h> 123*3d729aecSJerry Jelinek #include <sys/schedctl.h> 124*3d729aecSJerry Jelinek #include <sys/id_space.h> 125*3d729aecSJerry Jelinek #include <sys/sdt.h> 126*3d729aecSJerry Jelinek 127*3d729aecSJerry Jelinek typedef struct signalfd_state signalfd_state_t; 128*3d729aecSJerry Jelinek 129*3d729aecSJerry Jelinek struct signalfd_state { 130*3d729aecSJerry Jelinek kmutex_t sfd_lock; /* lock protecting state */ 131*3d729aecSJerry Jelinek pollhead_t sfd_pollhd; /* poll head */ 132*3d729aecSJerry Jelinek k_sigset_t sfd_set; /* signals for this fd */ 133*3d729aecSJerry Jelinek signalfd_state_t *sfd_next; /* next state on global list */ 134*3d729aecSJerry Jelinek }; 135*3d729aecSJerry Jelinek 136*3d729aecSJerry Jelinek /* 137*3d729aecSJerry Jelinek * Internal global variables. 138*3d729aecSJerry Jelinek */ 139*3d729aecSJerry Jelinek static kmutex_t signalfd_lock; /* lock protecting state */ 140*3d729aecSJerry Jelinek static dev_info_t *signalfd_devi; /* device info */ 141*3d729aecSJerry Jelinek static id_space_t *signalfd_minor; /* minor number arena */ 142*3d729aecSJerry Jelinek static void *signalfd_softstate; /* softstate pointer */ 143*3d729aecSJerry Jelinek static signalfd_state_t *signalfd_state; /* global list of state */ 144*3d729aecSJerry Jelinek 145*3d729aecSJerry Jelinek /* 146*3d729aecSJerry Jelinek * If we don't already have an entry in the proc's list for this state, add one. 147*3d729aecSJerry Jelinek */ 148*3d729aecSJerry Jelinek static void 149*3d729aecSJerry Jelinek signalfd_wake_list_add(signalfd_state_t *state) 150*3d729aecSJerry Jelinek { 151*3d729aecSJerry Jelinek proc_t *p = curproc; 152*3d729aecSJerry Jelinek list_t *lst; 153*3d729aecSJerry Jelinek sigfd_wake_list_t *wlp; 154*3d729aecSJerry Jelinek 155*3d729aecSJerry Jelinek ASSERT(MUTEX_HELD(&p->p_lock)); 156*3d729aecSJerry Jelinek ASSERT(p->p_sigfd != NULL); 157*3d729aecSJerry Jelinek 158*3d729aecSJerry Jelinek lst = &((sigfd_proc_state_t *)p->p_sigfd)->sigfd_list; 159*3d729aecSJerry Jelinek for (wlp = list_head(lst); wlp != NULL; wlp = list_next(lst, wlp)) { 160*3d729aecSJerry Jelinek if (wlp->sigfd_wl_state == state) 161*3d729aecSJerry Jelinek break; 162*3d729aecSJerry Jelinek } 163*3d729aecSJerry Jelinek 164*3d729aecSJerry Jelinek if (wlp == NULL) { 165*3d729aecSJerry Jelinek wlp = kmem_zalloc(sizeof (sigfd_wake_list_t), KM_SLEEP); 166*3d729aecSJerry Jelinek wlp->sigfd_wl_state = state; 167*3d729aecSJerry Jelinek list_insert_head(lst, wlp); 168*3d729aecSJerry Jelinek } 169*3d729aecSJerry Jelinek } 170*3d729aecSJerry Jelinek 171*3d729aecSJerry Jelinek static void 172*3d729aecSJerry Jelinek signalfd_wake_rm(list_t *lst, sigfd_wake_list_t *wlp) 173*3d729aecSJerry Jelinek { 174*3d729aecSJerry Jelinek list_remove(lst, wlp); 175*3d729aecSJerry Jelinek kmem_free(wlp, sizeof (sigfd_wake_list_t)); 176*3d729aecSJerry Jelinek } 177*3d729aecSJerry Jelinek 178*3d729aecSJerry Jelinek static void 179*3d729aecSJerry Jelinek signalfd_wake_list_rm(proc_t *p, signalfd_state_t *state) 180*3d729aecSJerry Jelinek { 181*3d729aecSJerry Jelinek sigfd_wake_list_t *wlp; 182*3d729aecSJerry Jelinek list_t *lst; 183*3d729aecSJerry Jelinek 184*3d729aecSJerry Jelinek ASSERT(MUTEX_HELD(&p->p_lock)); 185*3d729aecSJerry Jelinek 186*3d729aecSJerry Jelinek if (p->p_sigfd == NULL) 187*3d729aecSJerry Jelinek return; 188*3d729aecSJerry Jelinek 189*3d729aecSJerry Jelinek lst = &((sigfd_proc_state_t *)p->p_sigfd)->sigfd_list; 190*3d729aecSJerry Jelinek for (wlp = list_head(lst); wlp != NULL; wlp = list_next(lst, wlp)) { 191*3d729aecSJerry Jelinek if (wlp->sigfd_wl_state == state) { 192*3d729aecSJerry Jelinek signalfd_wake_rm(lst, wlp); 193*3d729aecSJerry Jelinek break; 194*3d729aecSJerry Jelinek } 195*3d729aecSJerry Jelinek } 196*3d729aecSJerry Jelinek 197*3d729aecSJerry Jelinek if (list_is_empty(lst)) { 198*3d729aecSJerry Jelinek ((sigfd_proc_state_t *)p->p_sigfd)->sigfd_pollwake_cb = NULL; 199*3d729aecSJerry Jelinek list_destroy(lst); 200*3d729aecSJerry Jelinek kmem_free(p->p_sigfd, sizeof (sigfd_proc_state_t)); 201*3d729aecSJerry Jelinek p->p_sigfd = NULL; 202*3d729aecSJerry Jelinek } 203*3d729aecSJerry Jelinek } 204*3d729aecSJerry Jelinek 205*3d729aecSJerry Jelinek static void 206*3d729aecSJerry Jelinek signalfd_wake_list_cleanup(proc_t *p) 207*3d729aecSJerry Jelinek { 208*3d729aecSJerry Jelinek sigfd_wake_list_t *wlp; 209*3d729aecSJerry Jelinek list_t *lst; 210*3d729aecSJerry Jelinek 211*3d729aecSJerry Jelinek ASSERT(MUTEX_HELD(&p->p_lock)); 212*3d729aecSJerry Jelinek 213*3d729aecSJerry Jelinek ((sigfd_proc_state_t *)p->p_sigfd)->sigfd_pollwake_cb = NULL; 214*3d729aecSJerry Jelinek 215*3d729aecSJerry Jelinek lst = &((sigfd_proc_state_t *)p->p_sigfd)->sigfd_list; 216*3d729aecSJerry Jelinek while (!list_is_empty(lst)) { 217*3d729aecSJerry Jelinek wlp = (sigfd_wake_list_t *)list_remove_head(lst); 218*3d729aecSJerry Jelinek kmem_free(wlp, sizeof (sigfd_wake_list_t)); 219*3d729aecSJerry Jelinek } 220*3d729aecSJerry Jelinek } 221*3d729aecSJerry Jelinek 222*3d729aecSJerry Jelinek static void 223*3d729aecSJerry Jelinek signalfd_exit_helper(void) 224*3d729aecSJerry Jelinek { 225*3d729aecSJerry Jelinek proc_t *p = curproc; 226*3d729aecSJerry Jelinek list_t *lst; 227*3d729aecSJerry Jelinek 228*3d729aecSJerry Jelinek /* This being non-null is the only way we can get here */ 229*3d729aecSJerry Jelinek ASSERT(p->p_sigfd != NULL); 230*3d729aecSJerry Jelinek 231*3d729aecSJerry Jelinek mutex_enter(&p->p_lock); 232*3d729aecSJerry Jelinek lst = &((sigfd_proc_state_t *)p->p_sigfd)->sigfd_list; 233*3d729aecSJerry Jelinek 234*3d729aecSJerry Jelinek signalfd_wake_list_cleanup(p); 235*3d729aecSJerry Jelinek list_destroy(lst); 236*3d729aecSJerry Jelinek kmem_free(p->p_sigfd, sizeof (sigfd_proc_state_t)); 237*3d729aecSJerry Jelinek p->p_sigfd = NULL; 238*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 239*3d729aecSJerry Jelinek } 240*3d729aecSJerry Jelinek 241*3d729aecSJerry Jelinek /* 242*3d729aecSJerry Jelinek * Called every time a signal is delivered to the process so that we can 243*3d729aecSJerry Jelinek * see if any signal stream needs a pollwakeup. We maintain a list of 244*3d729aecSJerry Jelinek * signal state elements so that we don't have to look at every file descriptor 245*3d729aecSJerry Jelinek * on the process. If necessary, a further optimization would be to maintain a 246*3d729aecSJerry Jelinek * signal set mask that is a union of all of the sets in the list so that 247*3d729aecSJerry Jelinek * we don't even traverse the list if the signal is not in one of the elements. 248*3d729aecSJerry Jelinek * However, since the list is likely to be very short, this is not currently 249*3d729aecSJerry Jelinek * being done. A more complex data structure might also be used, but it is 250*3d729aecSJerry Jelinek * unclear what that would be since each signal set needs to be checked for a 251*3d729aecSJerry Jelinek * match. 252*3d729aecSJerry Jelinek */ 253*3d729aecSJerry Jelinek static void 254*3d729aecSJerry Jelinek signalfd_pollwake_cb(void *arg0, int sig) 255*3d729aecSJerry Jelinek { 256*3d729aecSJerry Jelinek proc_t *p = (proc_t *)arg0; 257*3d729aecSJerry Jelinek list_t *lst; 258*3d729aecSJerry Jelinek sigfd_wake_list_t *wlp; 259*3d729aecSJerry Jelinek 260*3d729aecSJerry Jelinek ASSERT(MUTEX_HELD(&p->p_lock)); 261*3d729aecSJerry Jelinek 262*3d729aecSJerry Jelinek if (p->p_sigfd == NULL) 263*3d729aecSJerry Jelinek return; 264*3d729aecSJerry Jelinek 265*3d729aecSJerry Jelinek lst = &((sigfd_proc_state_t *)p->p_sigfd)->sigfd_list; 266*3d729aecSJerry Jelinek wlp = list_head(lst); 267*3d729aecSJerry Jelinek while (wlp != NULL) { 268*3d729aecSJerry Jelinek signalfd_state_t *state = wlp->sigfd_wl_state; 269*3d729aecSJerry Jelinek 270*3d729aecSJerry Jelinek mutex_enter(&state->sfd_lock); 271*3d729aecSJerry Jelinek 272*3d729aecSJerry Jelinek if (sigismember(&state->sfd_set, sig) && 273*3d729aecSJerry Jelinek state->sfd_pollhd.ph_list != NULL) { 274*3d729aecSJerry Jelinek sigfd_wake_list_t *tmp = wlp; 275*3d729aecSJerry Jelinek 276*3d729aecSJerry Jelinek /* remove it from the list */ 277*3d729aecSJerry Jelinek wlp = list_next(lst, wlp); 278*3d729aecSJerry Jelinek signalfd_wake_rm(lst, tmp); 279*3d729aecSJerry Jelinek 280*3d729aecSJerry Jelinek mutex_exit(&state->sfd_lock); 281*3d729aecSJerry Jelinek pollwakeup(&state->sfd_pollhd, POLLRDNORM | POLLIN); 282*3d729aecSJerry Jelinek } else { 283*3d729aecSJerry Jelinek mutex_exit(&state->sfd_lock); 284*3d729aecSJerry Jelinek wlp = list_next(lst, wlp); 285*3d729aecSJerry Jelinek } 286*3d729aecSJerry Jelinek } 287*3d729aecSJerry Jelinek } 288*3d729aecSJerry Jelinek 289*3d729aecSJerry Jelinek _NOTE(ARGSUSED(1)) 290*3d729aecSJerry Jelinek static int 291*3d729aecSJerry Jelinek signalfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 292*3d729aecSJerry Jelinek { 293*3d729aecSJerry Jelinek signalfd_state_t *state; 294*3d729aecSJerry Jelinek major_t major = getemajor(*devp); 295*3d729aecSJerry Jelinek minor_t minor = getminor(*devp); 296*3d729aecSJerry Jelinek 297*3d729aecSJerry Jelinek if (minor != SIGNALFDMNRN_SIGNALFD) 298*3d729aecSJerry Jelinek return (ENXIO); 299*3d729aecSJerry Jelinek 300*3d729aecSJerry Jelinek mutex_enter(&signalfd_lock); 301*3d729aecSJerry Jelinek 302*3d729aecSJerry Jelinek minor = (minor_t)id_allocff(signalfd_minor); 303*3d729aecSJerry Jelinek 304*3d729aecSJerry Jelinek if (ddi_soft_state_zalloc(signalfd_softstate, minor) != DDI_SUCCESS) { 305*3d729aecSJerry Jelinek id_free(signalfd_minor, minor); 306*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 307*3d729aecSJerry Jelinek return (ENODEV); 308*3d729aecSJerry Jelinek } 309*3d729aecSJerry Jelinek 310*3d729aecSJerry Jelinek state = ddi_get_soft_state(signalfd_softstate, minor); 311*3d729aecSJerry Jelinek *devp = makedevice(major, minor); 312*3d729aecSJerry Jelinek 313*3d729aecSJerry Jelinek state->sfd_next = signalfd_state; 314*3d729aecSJerry Jelinek signalfd_state = state; 315*3d729aecSJerry Jelinek 316*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 317*3d729aecSJerry Jelinek 318*3d729aecSJerry Jelinek return (0); 319*3d729aecSJerry Jelinek } 320*3d729aecSJerry Jelinek 321*3d729aecSJerry Jelinek /* 322*3d729aecSJerry Jelinek * Consume one signal from our set in a manner similar to sigtimedwait(). 323*3d729aecSJerry Jelinek * The block parameter is used to control whether we wait for a signal or 324*3d729aecSJerry Jelinek * return immediately if no signal is pending. We use the thread's t_sigwait 325*3d729aecSJerry Jelinek * member in the same way that it is used by sigtimedwait. 326*3d729aecSJerry Jelinek * 327*3d729aecSJerry Jelinek * Return 0 if we successfully consumed a signal or an errno if not. 328*3d729aecSJerry Jelinek */ 329*3d729aecSJerry Jelinek static int 330*3d729aecSJerry Jelinek consume_signal(k_sigset_t set, uio_t *uio, boolean_t block) 331*3d729aecSJerry Jelinek { 332*3d729aecSJerry Jelinek k_sigset_t oldmask; 333*3d729aecSJerry Jelinek kthread_t *t = curthread; 334*3d729aecSJerry Jelinek klwp_t *lwp = ttolwp(t); 335*3d729aecSJerry Jelinek proc_t *p = ttoproc(t); 336*3d729aecSJerry Jelinek timespec_t now; 337*3d729aecSJerry Jelinek timespec_t *rqtp = NULL; /* null means blocking */ 338*3d729aecSJerry Jelinek int timecheck = 0; 339*3d729aecSJerry Jelinek int ret = 0; 340*3d729aecSJerry Jelinek k_siginfo_t info, *infop; 341*3d729aecSJerry Jelinek signalfd_siginfo_t ssi, *ssp = &ssi; 342*3d729aecSJerry Jelinek 343*3d729aecSJerry Jelinek if (block == B_FALSE) { 344*3d729aecSJerry Jelinek timecheck = timechanged; 345*3d729aecSJerry Jelinek gethrestime(&now); 346*3d729aecSJerry Jelinek rqtp = &now; /* non-blocking check for pending signals */ 347*3d729aecSJerry Jelinek } 348*3d729aecSJerry Jelinek 349*3d729aecSJerry Jelinek t->t_sigwait = set; 350*3d729aecSJerry Jelinek 351*3d729aecSJerry Jelinek mutex_enter(&p->p_lock); 352*3d729aecSJerry Jelinek /* 353*3d729aecSJerry Jelinek * set the thread's signal mask to unmask those signals in the 354*3d729aecSJerry Jelinek * specified set. 355*3d729aecSJerry Jelinek */ 356*3d729aecSJerry Jelinek schedctl_finish_sigblock(t); 357*3d729aecSJerry Jelinek oldmask = t->t_hold; 358*3d729aecSJerry Jelinek sigdiffset(&t->t_hold, &t->t_sigwait); 359*3d729aecSJerry Jelinek 360*3d729aecSJerry Jelinek /* 361*3d729aecSJerry Jelinek * Based on rqtp, wait indefinitely until we take a signal in our set 362*3d729aecSJerry Jelinek * or return immediately if there are no signals pending from our set. 363*3d729aecSJerry Jelinek */ 364*3d729aecSJerry Jelinek while ((ret = cv_waituntil_sig(&t->t_delay_cv, &p->p_lock, rqtp, 365*3d729aecSJerry Jelinek timecheck)) > 0) 366*3d729aecSJerry Jelinek continue; 367*3d729aecSJerry Jelinek 368*3d729aecSJerry Jelinek /* Restore thread's signal mask to its previous value. */ 369*3d729aecSJerry Jelinek t->t_hold = oldmask; 370*3d729aecSJerry Jelinek t->t_sig_check = 1; /* so post_syscall sees new t_hold mask */ 371*3d729aecSJerry Jelinek 372*3d729aecSJerry Jelinek if (ret == -1) { 373*3d729aecSJerry Jelinek /* no signals pending */ 374*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 375*3d729aecSJerry Jelinek sigemptyset(&t->t_sigwait); 376*3d729aecSJerry Jelinek return (EAGAIN); /* no signals pending */ 377*3d729aecSJerry Jelinek } 378*3d729aecSJerry Jelinek 379*3d729aecSJerry Jelinek /* Don't bother with signal if it is not in request set. */ 380*3d729aecSJerry Jelinek if (lwp->lwp_cursig == 0 || 381*3d729aecSJerry Jelinek !sigismember(&t->t_sigwait, lwp->lwp_cursig)) { 382*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 383*3d729aecSJerry Jelinek /* 384*3d729aecSJerry Jelinek * lwp_cursig is zero if pokelwps() awakened cv_wait_sig(). 385*3d729aecSJerry Jelinek * This happens if some other thread in this process called 386*3d729aecSJerry Jelinek * forkall() or exit(). 387*3d729aecSJerry Jelinek */ 388*3d729aecSJerry Jelinek sigemptyset(&t->t_sigwait); 389*3d729aecSJerry Jelinek return (EINTR); 390*3d729aecSJerry Jelinek } 391*3d729aecSJerry Jelinek 392*3d729aecSJerry Jelinek if (lwp->lwp_curinfo) { 393*3d729aecSJerry Jelinek infop = &lwp->lwp_curinfo->sq_info; 394*3d729aecSJerry Jelinek } else { 395*3d729aecSJerry Jelinek infop = &info; 396*3d729aecSJerry Jelinek bzero(infop, sizeof (info)); 397*3d729aecSJerry Jelinek infop->si_signo = lwp->lwp_cursig; 398*3d729aecSJerry Jelinek infop->si_code = SI_NOINFO; 399*3d729aecSJerry Jelinek } 400*3d729aecSJerry Jelinek 401*3d729aecSJerry Jelinek lwp->lwp_ru.nsignals++; 402*3d729aecSJerry Jelinek 403*3d729aecSJerry Jelinek DTRACE_PROC2(signal__clear, int, ret, ksiginfo_t *, infop); 404*3d729aecSJerry Jelinek lwp->lwp_cursig = 0; 405*3d729aecSJerry Jelinek lwp->lwp_extsig = 0; 406*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 407*3d729aecSJerry Jelinek 408*3d729aecSJerry Jelinek /* Convert k_siginfo into external, datamodel independent, struct. */ 409*3d729aecSJerry Jelinek bzero(ssp, sizeof (*ssp)); 410*3d729aecSJerry Jelinek ssp->ssi_signo = infop->si_signo; 411*3d729aecSJerry Jelinek ssp->ssi_errno = infop->si_errno; 412*3d729aecSJerry Jelinek ssp->ssi_code = infop->si_code; 413*3d729aecSJerry Jelinek ssp->ssi_pid = infop->si_pid; 414*3d729aecSJerry Jelinek ssp->ssi_uid = infop->si_uid; 415*3d729aecSJerry Jelinek ssp->ssi_fd = infop->si_fd; 416*3d729aecSJerry Jelinek ssp->ssi_band = infop->si_band; 417*3d729aecSJerry Jelinek ssp->ssi_trapno = infop->si_trapno; 418*3d729aecSJerry Jelinek ssp->ssi_status = infop->si_status; 419*3d729aecSJerry Jelinek ssp->ssi_utime = infop->si_utime; 420*3d729aecSJerry Jelinek ssp->ssi_stime = infop->si_stime; 421*3d729aecSJerry Jelinek ssp->ssi_addr = (uint64_t)(intptr_t)infop->si_addr; 422*3d729aecSJerry Jelinek 423*3d729aecSJerry Jelinek ret = uiomove(ssp, sizeof (*ssp), UIO_READ, uio); 424*3d729aecSJerry Jelinek 425*3d729aecSJerry Jelinek if (lwp->lwp_curinfo) { 426*3d729aecSJerry Jelinek siginfofree(lwp->lwp_curinfo); 427*3d729aecSJerry Jelinek lwp->lwp_curinfo = NULL; 428*3d729aecSJerry Jelinek } 429*3d729aecSJerry Jelinek sigemptyset(&t->t_sigwait); 430*3d729aecSJerry Jelinek return (ret); 431*3d729aecSJerry Jelinek } 432*3d729aecSJerry Jelinek 433*3d729aecSJerry Jelinek /* 434*3d729aecSJerry Jelinek * This is similar to sigtimedwait. Based on the fd mode we may wait until a 435*3d729aecSJerry Jelinek * signal within our specified set is posted. We consume as many available 436*3d729aecSJerry Jelinek * signals within our set as we can. 437*3d729aecSJerry Jelinek */ 438*3d729aecSJerry Jelinek _NOTE(ARGSUSED(2)) 439*3d729aecSJerry Jelinek static int 440*3d729aecSJerry Jelinek signalfd_read(dev_t dev, uio_t *uio, cred_t *cr) 441*3d729aecSJerry Jelinek { 442*3d729aecSJerry Jelinek signalfd_state_t *state; 443*3d729aecSJerry Jelinek minor_t minor = getminor(dev); 444*3d729aecSJerry Jelinek boolean_t block = B_TRUE; 445*3d729aecSJerry Jelinek k_sigset_t set; 446*3d729aecSJerry Jelinek boolean_t got_one = B_FALSE; 447*3d729aecSJerry Jelinek int res; 448*3d729aecSJerry Jelinek 449*3d729aecSJerry Jelinek if (uio->uio_resid < sizeof (signalfd_siginfo_t)) 450*3d729aecSJerry Jelinek return (EINVAL); 451*3d729aecSJerry Jelinek 452*3d729aecSJerry Jelinek state = ddi_get_soft_state(signalfd_softstate, minor); 453*3d729aecSJerry Jelinek 454*3d729aecSJerry Jelinek if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) 455*3d729aecSJerry Jelinek block = B_FALSE; 456*3d729aecSJerry Jelinek 457*3d729aecSJerry Jelinek mutex_enter(&state->sfd_lock); 458*3d729aecSJerry Jelinek set = state->sfd_set; 459*3d729aecSJerry Jelinek mutex_exit(&state->sfd_lock); 460*3d729aecSJerry Jelinek 461*3d729aecSJerry Jelinek if (sigisempty(&set)) 462*3d729aecSJerry Jelinek return (set_errno(EINVAL)); 463*3d729aecSJerry Jelinek 464*3d729aecSJerry Jelinek do { 465*3d729aecSJerry Jelinek res = consume_signal(state->sfd_set, uio, block); 466*3d729aecSJerry Jelinek if (res == 0) 467*3d729aecSJerry Jelinek got_one = B_TRUE; 468*3d729aecSJerry Jelinek 469*3d729aecSJerry Jelinek /* 470*3d729aecSJerry Jelinek * After consuming one signal we won't block trying to consume 471*3d729aecSJerry Jelinek * further signals. 472*3d729aecSJerry Jelinek */ 473*3d729aecSJerry Jelinek block = B_FALSE; 474*3d729aecSJerry Jelinek } while (res == 0 && uio->uio_resid >= sizeof (signalfd_siginfo_t)); 475*3d729aecSJerry Jelinek 476*3d729aecSJerry Jelinek if (got_one) 477*3d729aecSJerry Jelinek res = 0; 478*3d729aecSJerry Jelinek 479*3d729aecSJerry Jelinek return (res); 480*3d729aecSJerry Jelinek } 481*3d729aecSJerry Jelinek 482*3d729aecSJerry Jelinek /* 483*3d729aecSJerry Jelinek * If ksigset_t's were a single word, we would do: 484*3d729aecSJerry Jelinek * return (((p->p_sig | t->t_sig) & set) & fillset); 485*3d729aecSJerry Jelinek */ 486*3d729aecSJerry Jelinek static int 487*3d729aecSJerry Jelinek signalfd_sig_pending(proc_t *p, kthread_t *t, k_sigset_t set) 488*3d729aecSJerry Jelinek { 489*3d729aecSJerry Jelinek return (((p->p_sig.__sigbits[0] | t->t_sig.__sigbits[0]) & 490*3d729aecSJerry Jelinek set.__sigbits[0]) | 491*3d729aecSJerry Jelinek ((p->p_sig.__sigbits[1] | t->t_sig.__sigbits[1]) & 492*3d729aecSJerry Jelinek set.__sigbits[1]) | 493*3d729aecSJerry Jelinek (((p->p_sig.__sigbits[2] | t->t_sig.__sigbits[2]) & 494*3d729aecSJerry Jelinek set.__sigbits[2]) & FILLSET2)); 495*3d729aecSJerry Jelinek } 496*3d729aecSJerry Jelinek 497*3d729aecSJerry Jelinek _NOTE(ARGSUSED(4)) 498*3d729aecSJerry Jelinek static int 499*3d729aecSJerry Jelinek signalfd_poll(dev_t dev, short events, int anyyet, short *reventsp, 500*3d729aecSJerry Jelinek struct pollhead **phpp) 501*3d729aecSJerry Jelinek { 502*3d729aecSJerry Jelinek signalfd_state_t *state; 503*3d729aecSJerry Jelinek minor_t minor = getminor(dev); 504*3d729aecSJerry Jelinek kthread_t *t = curthread; 505*3d729aecSJerry Jelinek proc_t *p = ttoproc(t); 506*3d729aecSJerry Jelinek short revents = 0; 507*3d729aecSJerry Jelinek 508*3d729aecSJerry Jelinek state = ddi_get_soft_state(signalfd_softstate, minor); 509*3d729aecSJerry Jelinek 510*3d729aecSJerry Jelinek mutex_enter(&state->sfd_lock); 511*3d729aecSJerry Jelinek 512*3d729aecSJerry Jelinek if (signalfd_sig_pending(p, t, state->sfd_set) != 0) 513*3d729aecSJerry Jelinek revents |= POLLRDNORM | POLLIN; 514*3d729aecSJerry Jelinek 515*3d729aecSJerry Jelinek mutex_exit(&state->sfd_lock); 516*3d729aecSJerry Jelinek 517*3d729aecSJerry Jelinek if (!(*reventsp = revents & events) && !anyyet) { 518*3d729aecSJerry Jelinek *phpp = &state->sfd_pollhd; 519*3d729aecSJerry Jelinek 520*3d729aecSJerry Jelinek /* 521*3d729aecSJerry Jelinek * Enable pollwakeup handling. 522*3d729aecSJerry Jelinek */ 523*3d729aecSJerry Jelinek if (p->p_sigfd == NULL) { 524*3d729aecSJerry Jelinek sigfd_proc_state_t *pstate; 525*3d729aecSJerry Jelinek 526*3d729aecSJerry Jelinek pstate = kmem_zalloc(sizeof (sigfd_proc_state_t), 527*3d729aecSJerry Jelinek KM_SLEEP); 528*3d729aecSJerry Jelinek list_create(&pstate->sigfd_list, 529*3d729aecSJerry Jelinek sizeof (sigfd_wake_list_t), 530*3d729aecSJerry Jelinek offsetof(sigfd_wake_list_t, sigfd_wl_lst)); 531*3d729aecSJerry Jelinek 532*3d729aecSJerry Jelinek mutex_enter(&p->p_lock); 533*3d729aecSJerry Jelinek /* check again now that we're locked */ 534*3d729aecSJerry Jelinek if (p->p_sigfd == NULL) { 535*3d729aecSJerry Jelinek p->p_sigfd = pstate; 536*3d729aecSJerry Jelinek } else { 537*3d729aecSJerry Jelinek /* someone beat us to it */ 538*3d729aecSJerry Jelinek list_destroy(&pstate->sigfd_list); 539*3d729aecSJerry Jelinek kmem_free(pstate, sizeof (sigfd_proc_state_t)); 540*3d729aecSJerry Jelinek } 541*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 542*3d729aecSJerry Jelinek } 543*3d729aecSJerry Jelinek 544*3d729aecSJerry Jelinek mutex_enter(&p->p_lock); 545*3d729aecSJerry Jelinek if (((sigfd_proc_state_t *)p->p_sigfd)->sigfd_pollwake_cb == 546*3d729aecSJerry Jelinek NULL) { 547*3d729aecSJerry Jelinek ((sigfd_proc_state_t *)p->p_sigfd)->sigfd_pollwake_cb = 548*3d729aecSJerry Jelinek signalfd_pollwake_cb; 549*3d729aecSJerry Jelinek } 550*3d729aecSJerry Jelinek signalfd_wake_list_add(state); 551*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 552*3d729aecSJerry Jelinek } 553*3d729aecSJerry Jelinek 554*3d729aecSJerry Jelinek return (0); 555*3d729aecSJerry Jelinek } 556*3d729aecSJerry Jelinek 557*3d729aecSJerry Jelinek _NOTE(ARGSUSED(4)) 558*3d729aecSJerry Jelinek static int 559*3d729aecSJerry Jelinek signalfd_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) 560*3d729aecSJerry Jelinek { 561*3d729aecSJerry Jelinek signalfd_state_t *state; 562*3d729aecSJerry Jelinek minor_t minor = getminor(dev); 563*3d729aecSJerry Jelinek sigset_t mask; 564*3d729aecSJerry Jelinek 565*3d729aecSJerry Jelinek state = ddi_get_soft_state(signalfd_softstate, minor); 566*3d729aecSJerry Jelinek 567*3d729aecSJerry Jelinek switch (cmd) { 568*3d729aecSJerry Jelinek case SIGNALFDIOC_MASK: 569*3d729aecSJerry Jelinek if (ddi_copyin((caddr_t)arg, (caddr_t)&mask, sizeof (sigset_t), 570*3d729aecSJerry Jelinek md) != 0) 571*3d729aecSJerry Jelinek return (set_errno(EFAULT)); 572*3d729aecSJerry Jelinek 573*3d729aecSJerry Jelinek mutex_enter(&state->sfd_lock); 574*3d729aecSJerry Jelinek sigutok(&mask, &state->sfd_set); 575*3d729aecSJerry Jelinek mutex_exit(&state->sfd_lock); 576*3d729aecSJerry Jelinek 577*3d729aecSJerry Jelinek return (0); 578*3d729aecSJerry Jelinek 579*3d729aecSJerry Jelinek default: 580*3d729aecSJerry Jelinek break; 581*3d729aecSJerry Jelinek } 582*3d729aecSJerry Jelinek 583*3d729aecSJerry Jelinek return (ENOTTY); 584*3d729aecSJerry Jelinek } 585*3d729aecSJerry Jelinek 586*3d729aecSJerry Jelinek _NOTE(ARGSUSED(1)) 587*3d729aecSJerry Jelinek static int 588*3d729aecSJerry Jelinek signalfd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 589*3d729aecSJerry Jelinek { 590*3d729aecSJerry Jelinek signalfd_state_t *state, **sp; 591*3d729aecSJerry Jelinek minor_t minor = getminor(dev); 592*3d729aecSJerry Jelinek proc_t *p = curproc; 593*3d729aecSJerry Jelinek 594*3d729aecSJerry Jelinek state = ddi_get_soft_state(signalfd_softstate, minor); 595*3d729aecSJerry Jelinek 596*3d729aecSJerry Jelinek if (state->sfd_pollhd.ph_list != NULL) { 597*3d729aecSJerry Jelinek pollwakeup(&state->sfd_pollhd, POLLERR); 598*3d729aecSJerry Jelinek pollhead_clean(&state->sfd_pollhd); 599*3d729aecSJerry Jelinek } 600*3d729aecSJerry Jelinek 601*3d729aecSJerry Jelinek /* Make sure our state is removed from our proc's pollwake list. */ 602*3d729aecSJerry Jelinek mutex_enter(&p->p_lock); 603*3d729aecSJerry Jelinek signalfd_wake_list_rm(p, state); 604*3d729aecSJerry Jelinek mutex_exit(&p->p_lock); 605*3d729aecSJerry Jelinek 606*3d729aecSJerry Jelinek mutex_enter(&signalfd_lock); 607*3d729aecSJerry Jelinek 608*3d729aecSJerry Jelinek /* Remove our state from our global list. */ 609*3d729aecSJerry Jelinek for (sp = &signalfd_state; *sp != state; sp = &((*sp)->sfd_next)) 610*3d729aecSJerry Jelinek VERIFY(*sp != NULL); 611*3d729aecSJerry Jelinek 612*3d729aecSJerry Jelinek *sp = (*sp)->sfd_next; 613*3d729aecSJerry Jelinek 614*3d729aecSJerry Jelinek ddi_soft_state_free(signalfd_softstate, minor); 615*3d729aecSJerry Jelinek id_free(signalfd_minor, minor); 616*3d729aecSJerry Jelinek 617*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 618*3d729aecSJerry Jelinek 619*3d729aecSJerry Jelinek return (0); 620*3d729aecSJerry Jelinek } 621*3d729aecSJerry Jelinek 622*3d729aecSJerry Jelinek static int 623*3d729aecSJerry Jelinek signalfd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 624*3d729aecSJerry Jelinek { 625*3d729aecSJerry Jelinek if (cmd != DDI_ATTACH || signalfd_devi != NULL) 626*3d729aecSJerry Jelinek return (DDI_FAILURE); 627*3d729aecSJerry Jelinek 628*3d729aecSJerry Jelinek mutex_enter(&signalfd_lock); 629*3d729aecSJerry Jelinek 630*3d729aecSJerry Jelinek signalfd_minor = id_space_create("signalfd_minor", 1, L_MAXMIN32 + 1); 631*3d729aecSJerry Jelinek if (signalfd_minor == NULL) { 632*3d729aecSJerry Jelinek cmn_err(CE_WARN, "signalfd couldn't create id space"); 633*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 634*3d729aecSJerry Jelinek return (DDI_FAILURE); 635*3d729aecSJerry Jelinek } 636*3d729aecSJerry Jelinek 637*3d729aecSJerry Jelinek if (ddi_soft_state_init(&signalfd_softstate, 638*3d729aecSJerry Jelinek sizeof (signalfd_state_t), 0) != 0) { 639*3d729aecSJerry Jelinek cmn_err(CE_WARN, "signalfd failed to create soft state"); 640*3d729aecSJerry Jelinek id_space_destroy(signalfd_minor); 641*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 642*3d729aecSJerry Jelinek return (DDI_FAILURE); 643*3d729aecSJerry Jelinek } 644*3d729aecSJerry Jelinek 645*3d729aecSJerry Jelinek if (ddi_create_minor_node(devi, "signalfd", S_IFCHR, 646*3d729aecSJerry Jelinek SIGNALFDMNRN_SIGNALFD, DDI_PSEUDO, NULL) == DDI_FAILURE) { 647*3d729aecSJerry Jelinek cmn_err(CE_NOTE, "/dev/signalfd couldn't create minor node"); 648*3d729aecSJerry Jelinek ddi_soft_state_fini(&signalfd_softstate); 649*3d729aecSJerry Jelinek id_space_destroy(signalfd_minor); 650*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 651*3d729aecSJerry Jelinek return (DDI_FAILURE); 652*3d729aecSJerry Jelinek } 653*3d729aecSJerry Jelinek 654*3d729aecSJerry Jelinek ddi_report_dev(devi); 655*3d729aecSJerry Jelinek signalfd_devi = devi; 656*3d729aecSJerry Jelinek 657*3d729aecSJerry Jelinek sigfd_exit_helper = signalfd_exit_helper; 658*3d729aecSJerry Jelinek 659*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 660*3d729aecSJerry Jelinek 661*3d729aecSJerry Jelinek return (DDI_SUCCESS); 662*3d729aecSJerry Jelinek } 663*3d729aecSJerry Jelinek 664*3d729aecSJerry Jelinek _NOTE(ARGSUSED(0)) 665*3d729aecSJerry Jelinek static int 666*3d729aecSJerry Jelinek signalfd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 667*3d729aecSJerry Jelinek { 668*3d729aecSJerry Jelinek switch (cmd) { 669*3d729aecSJerry Jelinek case DDI_DETACH: 670*3d729aecSJerry Jelinek break; 671*3d729aecSJerry Jelinek 672*3d729aecSJerry Jelinek default: 673*3d729aecSJerry Jelinek return (DDI_FAILURE); 674*3d729aecSJerry Jelinek } 675*3d729aecSJerry Jelinek 676*3d729aecSJerry Jelinek /* list should be empty */ 677*3d729aecSJerry Jelinek VERIFY(signalfd_state == NULL); 678*3d729aecSJerry Jelinek 679*3d729aecSJerry Jelinek mutex_enter(&signalfd_lock); 680*3d729aecSJerry Jelinek id_space_destroy(signalfd_minor); 681*3d729aecSJerry Jelinek 682*3d729aecSJerry Jelinek ddi_remove_minor_node(signalfd_devi, NULL); 683*3d729aecSJerry Jelinek signalfd_devi = NULL; 684*3d729aecSJerry Jelinek sigfd_exit_helper = NULL; 685*3d729aecSJerry Jelinek 686*3d729aecSJerry Jelinek ddi_soft_state_fini(&signalfd_softstate); 687*3d729aecSJerry Jelinek mutex_exit(&signalfd_lock); 688*3d729aecSJerry Jelinek 689*3d729aecSJerry Jelinek return (DDI_SUCCESS); 690*3d729aecSJerry Jelinek } 691*3d729aecSJerry Jelinek 692*3d729aecSJerry Jelinek _NOTE(ARGSUSED(0)) 693*3d729aecSJerry Jelinek static int 694*3d729aecSJerry Jelinek signalfd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 695*3d729aecSJerry Jelinek { 696*3d729aecSJerry Jelinek int error; 697*3d729aecSJerry Jelinek 698*3d729aecSJerry Jelinek switch (infocmd) { 699*3d729aecSJerry Jelinek case DDI_INFO_DEVT2DEVINFO: 700*3d729aecSJerry Jelinek *result = (void *)signalfd_devi; 701*3d729aecSJerry Jelinek error = DDI_SUCCESS; 702*3d729aecSJerry Jelinek break; 703*3d729aecSJerry Jelinek case DDI_INFO_DEVT2INSTANCE: 704*3d729aecSJerry Jelinek *result = (void *)0; 705*3d729aecSJerry Jelinek error = DDI_SUCCESS; 706*3d729aecSJerry Jelinek break; 707*3d729aecSJerry Jelinek default: 708*3d729aecSJerry Jelinek error = DDI_FAILURE; 709*3d729aecSJerry Jelinek } 710*3d729aecSJerry Jelinek return (error); 711*3d729aecSJerry Jelinek } 712*3d729aecSJerry Jelinek 713*3d729aecSJerry Jelinek static struct cb_ops signalfd_cb_ops = { 714*3d729aecSJerry Jelinek signalfd_open, /* open */ 715*3d729aecSJerry Jelinek signalfd_close, /* close */ 716*3d729aecSJerry Jelinek nulldev, /* strategy */ 717*3d729aecSJerry Jelinek nulldev, /* print */ 718*3d729aecSJerry Jelinek nodev, /* dump */ 719*3d729aecSJerry Jelinek signalfd_read, /* read */ 720*3d729aecSJerry Jelinek nodev, /* write */ 721*3d729aecSJerry Jelinek signalfd_ioctl, /* ioctl */ 722*3d729aecSJerry Jelinek nodev, /* devmap */ 723*3d729aecSJerry Jelinek nodev, /* mmap */ 724*3d729aecSJerry Jelinek nodev, /* segmap */ 725*3d729aecSJerry Jelinek signalfd_poll, /* poll */ 726*3d729aecSJerry Jelinek ddi_prop_op, /* cb_prop_op */ 727*3d729aecSJerry Jelinek 0, /* streamtab */ 728*3d729aecSJerry Jelinek D_NEW | D_MP /* Driver compatibility flag */ 729*3d729aecSJerry Jelinek }; 730*3d729aecSJerry Jelinek 731*3d729aecSJerry Jelinek static struct dev_ops signalfd_ops = { 732*3d729aecSJerry Jelinek DEVO_REV, /* devo_rev */ 733*3d729aecSJerry Jelinek 0, /* refcnt */ 734*3d729aecSJerry Jelinek signalfd_info, /* get_dev_info */ 735*3d729aecSJerry Jelinek nulldev, /* identify */ 736*3d729aecSJerry Jelinek nulldev, /* probe */ 737*3d729aecSJerry Jelinek signalfd_attach, /* attach */ 738*3d729aecSJerry Jelinek signalfd_detach, /* detach */ 739*3d729aecSJerry Jelinek nodev, /* reset */ 740*3d729aecSJerry Jelinek &signalfd_cb_ops, /* driver operations */ 741*3d729aecSJerry Jelinek NULL, /* bus operations */ 742*3d729aecSJerry Jelinek nodev, /* dev power */ 743*3d729aecSJerry Jelinek ddi_quiesce_not_needed, /* quiesce */ 744*3d729aecSJerry Jelinek }; 745*3d729aecSJerry Jelinek 746*3d729aecSJerry Jelinek static struct modldrv modldrv = { 747*3d729aecSJerry Jelinek &mod_driverops, /* module type (this is a pseudo driver) */ 748*3d729aecSJerry Jelinek "signalfd support", /* name of module */ 749*3d729aecSJerry Jelinek &signalfd_ops, /* driver ops */ 750*3d729aecSJerry Jelinek }; 751*3d729aecSJerry Jelinek 752*3d729aecSJerry Jelinek static struct modlinkage modlinkage = { 753*3d729aecSJerry Jelinek MODREV_1, 754*3d729aecSJerry Jelinek (void *)&modldrv, 755*3d729aecSJerry Jelinek NULL 756*3d729aecSJerry Jelinek }; 757*3d729aecSJerry Jelinek 758*3d729aecSJerry Jelinek int 759*3d729aecSJerry Jelinek _init(void) 760*3d729aecSJerry Jelinek { 761*3d729aecSJerry Jelinek return (mod_install(&modlinkage)); 762*3d729aecSJerry Jelinek } 763*3d729aecSJerry Jelinek 764*3d729aecSJerry Jelinek int 765*3d729aecSJerry Jelinek _info(struct modinfo *modinfop) 766*3d729aecSJerry Jelinek { 767*3d729aecSJerry Jelinek return (mod_info(&modlinkage, modinfop)); 768*3d729aecSJerry Jelinek } 769*3d729aecSJerry Jelinek 770*3d729aecSJerry Jelinek int 771*3d729aecSJerry Jelinek _fini(void) 772*3d729aecSJerry Jelinek { 773*3d729aecSJerry Jelinek return (mod_remove(&modlinkage)); 774*3d729aecSJerry Jelinek } 775