xref: /titanic_51/usr/src/uts/common/io/signalfd.c (revision 3d729aecc03ea6ebb9bd5d56b8dccd24f57daa41)
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