xref: /illumos-gate/usr/src/uts/common/fs/sockfs/socknotify.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/stropts.h>
31 #include <sys/socketvar.h>
32 #include <sys/ksocket.h>
33 #include <io/ksocket/ksocket_impl.h>
34 #include <fs/sockfs/sockcommon.h>
35 #include <fs/sockfs/sodirect.h>
36 
37 /*
38  * There can only be a single thread waiting for data (enforced by
39  * so_lock_read()), whereas for write there might be multiple threads
40  * waiting for transmit buffers. So therefore we use cv_broadcast for
41  * write and cv_signal for read.
42  */
43 #define	SO_WAKEUP_READER(so) {				\
44 	if ((so)->so_rcv_wakeup) {			\
45 		(so)->so_rcv_wakeup = B_FALSE;		\
46 		cv_signal(&(so)->so_rcv_cv);		\
47 	}						\
48 }
49 
50 #define	SO_WAKEUP_WRITER(so) {			\
51 	if ((so)->so_snd_wakeup) {		\
52 		(so)->so_snd_wakeup = B_FALSE;	\
53 		cv_broadcast(&(so)->so_snd_cv);	\
54 	}					\
55 }
56 
57 static int i_so_notify_last_rx(struct sonode *, int *, int *);
58 static int i_so_notify_last_tx(struct sonode *, int *, int *);
59 
60 /*
61  * The notification functions must be called with so_lock held,
62  * and they will all *drop* so_lock before returning.
63  */
64 
65 /*
66  * Wake up anyone waiting for the connection to be established.
67  */
68 void
69 so_notify_connected(struct sonode *so)
70 {
71 	ASSERT(MUTEX_HELD(&so->so_lock));
72 
73 	if (IS_KERNEL_SOCKET(so)) {
74 		KSOCKET_CALLBACK(so, connected, 0);
75 		mutex_exit(&so->so_lock);
76 	} else {
77 		socket_sendsig(so, SOCKETSIG_WRITE);
78 		mutex_exit(&so->so_lock);
79 		pollwakeup(&so->so_poll_list, POLLOUT);
80 	}
81 
82 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
83 }
84 
85 /*
86  * The socket is disconnecting, so no more data can be sent. Wake up
87  * anyone that is waiting to send data.
88  */
89 void
90 so_notify_disconnecting(struct sonode *so)
91 {
92 	int pollev = 0;
93 	int sigev = 0;
94 
95 	ASSERT(MUTEX_HELD(&so->so_lock));
96 
97 	if (IS_KERNEL_SOCKET(so)) {
98 		SO_WAKEUP_WRITER(so);
99 		KSOCKET_CALLBACK(so, cantsendmore, 0);
100 		mutex_exit(&so->so_lock);
101 	} else if (i_so_notify_last_tx(so, &pollev, &sigev)) {
102 		socket_sendsig(so, sigev);
103 		mutex_exit(&so->so_lock);
104 		pollwakeup(&so->so_poll_list, pollev);
105 	} else {
106 		mutex_exit(&so->so_lock);
107 	}
108 
109 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
110 }
111 
112 /*
113  * The socket is disconnected, so not more data can be sent or received.
114  * Wake up anyone that is waiting to send or receive data.
115  */
116 void
117 so_notify_disconnected(struct sonode *so, int error)
118 {
119 	int pollev = 0;
120 	int sigev = 0;
121 
122 	ASSERT(MUTEX_HELD(&so->so_lock));
123 
124 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
125 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
126 
127 	if (IS_KERNEL_SOCKET(so)) {
128 		KSOCKET_CALLBACK(so, disconnected, error);
129 		mutex_exit(&so->so_lock);
130 	} else {
131 		if (sigev != 0)
132 			socket_sendsig(so, sigev);
133 		mutex_exit(&so->so_lock);
134 		if (pollev != 0)
135 			pollwakeup(&so->so_poll_list, pollev);
136 	}
137 
138 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
139 }
140 
141 /*
142  * The socket is writeable. Wake up anyone waiting to send data.
143  */
144 void
145 so_notify_writable(struct sonode *so)
146 {
147 	ASSERT(MUTEX_HELD(&so->so_lock));
148 
149 	SO_WAKEUP_WRITER(so);
150 
151 	if (IS_KERNEL_SOCKET(so)) {
152 		KSOCKET_CALLBACK(so, cansend, 0);
153 		mutex_exit(&so->so_lock);
154 	} else {
155 		socket_sendsig(so, SOCKETSIG_WRITE);
156 		mutex_exit(&so->so_lock);
157 		pollwakeup(&so->so_poll_list, POLLOUT);
158 	}
159 
160 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
161 }
162 
163 /*
164  * Data is available, so wake up anyone waiting for data.
165  */
166 void
167 so_notify_data(struct sonode *so, size_t qlen)
168 {
169 	ASSERT(MUTEX_HELD(&so->so_lock));
170 
171 	SO_WAKEUP_READER(so);
172 
173 	if (IS_KERNEL_SOCKET(so)) {
174 		KSOCKET_CALLBACK(so, newdata, qlen);
175 		mutex_exit(&so->so_lock);
176 	} else {
177 		socket_sendsig(so, SOCKETSIG_READ);
178 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
179 			so->so_pollev &= ~SO_POLLEV_IN;
180 			mutex_exit(&so->so_lock);
181 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
182 		} else {
183 			mutex_exit(&so->so_lock);
184 		}
185 	}
186 
187 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
188 }
189 
190 /*
191  * Transient error. Wake up anyone waiting to send or receive data.
192  */
193 void
194 so_notify_error(struct sonode *so)
195 {
196 	ASSERT(MUTEX_HELD(&so->so_lock));
197 
198 	SO_WAKEUP_WRITER(so);
199 	SO_WAKEUP_READER(so);
200 
201 	if (IS_KERNEL_SOCKET(so)) {
202 		KSOCKET_CALLBACK(so, error, 0);
203 		mutex_exit(&so->so_lock);
204 	} else {
205 		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
206 		so->so_pollev &= ~SO_POLLEV_IN;
207 		mutex_exit(&so->so_lock);
208 		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
209 	}
210 
211 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
212 }
213 
214 /*
215  * Out-of-band data is incoming, notify any interested parties.
216  */
217 void
218 so_notify_oobsig(struct sonode *so)
219 {
220 	socket_sendsig(so, SOCKETSIG_URG);
221 	mutex_exit(&so->so_lock);
222 	pollwakeup(&so->so_poll_list, POLLRDBAND);
223 }
224 
225 /*
226  * Received out-of-band data. If the OOB data is delivered inline, then
227  * in addition of regular OOB notification, anyone waiting for normal
228  * data is also notified.
229  */
230 void
231 so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
232 {
233 	ASSERT(MUTEX_HELD(&so->so_lock));
234 	if (so->so_direct != NULL)
235 		SOD_UIOAFINI(so->so_direct);
236 
237 	SO_WAKEUP_READER(so);
238 
239 	if (IS_KERNEL_SOCKET(so)) {
240 		KSOCKET_CALLBACK(so, oobdata, 0);
241 		mutex_exit(&so->so_lock);
242 	} else {
243 		if (oob_inline) {
244 			socket_sendsig(so, SOCKETSIG_READ);
245 			so->so_pollev &= ~SO_POLLEV_IN;
246 			mutex_exit(&so->so_lock);
247 			pollwakeup(&so->so_poll_list,
248 			    POLLRDBAND|POLLIN|POLLRDNORM);
249 		} else {
250 			mutex_exit(&so->so_lock);
251 			pollwakeup(&so->so_poll_list, POLLRDBAND);
252 		}
253 	}
254 
255 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
256 }
257 
258 /*
259  * End-of-file has been reach, so peer will send no new data. Wake up
260  * anyone that is waiting for data.
261  */
262 void
263 so_notify_eof(struct sonode *so)
264 {
265 	int pollev = 0;
266 	int sigev = 0;
267 
268 	ASSERT(MUTEX_HELD(&so->so_lock));
269 
270 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
271 
272 	if (IS_KERNEL_SOCKET(so)) {
273 		SO_WAKEUP_READER(so);
274 		KSOCKET_CALLBACK(so, cantrecvmore, 0);
275 		mutex_exit(&so->so_lock);
276 	} else {
277 		if (sigev != 0)
278 			socket_sendsig(so, sigev);
279 		mutex_exit(&so->so_lock);
280 		if (pollev != 0)
281 			pollwakeup(&so->so_poll_list, pollev);
282 
283 	}
284 
285 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
286 }
287 
288 /*
289  * Wake up anyone waiting for a new connection.
290  */
291 void
292 so_notify_newconn(struct sonode *so)
293 {
294 	ASSERT(MUTEX_HELD(&so->so_lock));
295 
296 	if (IS_KERNEL_SOCKET(so)) {
297 		KSOCKET_CALLBACK(so, newconn, so->so_rcv_queued);
298 		mutex_exit(&so->so_lock);
299 	} else {
300 		socket_sendsig(so, SOCKETSIG_READ);
301 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
302 			so->so_pollev &= ~SO_POLLEV_IN;
303 			mutex_exit(&so->so_lock);
304 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
305 		} else {
306 			mutex_exit(&so->so_lock);
307 		}
308 	}
309 
310 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
311 }
312 
313 /*
314  * User initated shutdown/close, wake anyone that is trying to do
315  * an operation that is no longer possible.
316  */
317 void
318 so_notify_shutdown(struct sonode *so)
319 {
320 	int pollev = 0;
321 	int sigev = 0;
322 
323 	ASSERT(MUTEX_HELD(&so->so_lock));
324 	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
325 
326 	if (so->so_state & SS_CANTSENDMORE)
327 		(void) i_so_notify_last_tx(so, &pollev, &sigev);
328 	if (so->so_state & SS_CANTRCVMORE)
329 		(void) i_so_notify_last_rx(so, &pollev, &sigev);
330 
331 	if (sigev != 0)
332 		socket_sendsig(so, sigev);
333 	mutex_exit(&so->so_lock);
334 	if (pollev != 0)
335 		pollwakeup(&so->so_poll_list, pollev);
336 
337 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
338 }
339 
340 /*
341  * No more data will be coming in, and this will be the last notification
342  * made.
343  */
344 static int
345 i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
346 {
347 	if (!(so->so_state & SS_SENTLASTREADSIG)) {
348 		SOCKET_TIMER_CANCEL(so);
349 		SO_WAKEUP_READER(so);
350 		so->so_state |= SS_SENTLASTREADSIG;
351 		so->so_pollev &= ~SO_POLLEV_IN;
352 
353 		*pollev |= POLLIN|POLLRDNORM;
354 		*sigev |= SOCKETSIG_READ;
355 
356 		return (1);
357 	} else {
358 		return (0);
359 	}
360 }
361 
362 /*
363  * The socket is un-writeable. Make one last notification.
364  */
365 static int
366 i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
367 {
368 	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
369 		SO_WAKEUP_WRITER(so);
370 		so->so_state |= SS_SENTLASTWRITESIG;
371 
372 		*pollev |= POLLOUT;
373 		*sigev |= SOCKETSIG_WRITE;
374 
375 		return (1);
376 	} else {
377 		return (0);
378 	}
379 }
380