xref: /illumos-gate/usr/src/uts/common/fs/sockfs/socknotify.c (revision 17f1e64a433a4ca00ffed7539e10c297580a7002)
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 	if (IS_KERNEL_SOCKET(so)) {
238 		if (oob_inline)
239 			SO_WAKEUP_READER(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 
250 			SO_WAKEUP_READER(so);
251 		} else {
252 			mutex_exit(&so->so_lock);
253 			pollwakeup(&so->so_poll_list, POLLRDBAND);
254 		}
255 	}
256 
257 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
258 }
259 
260 /*
261  * End-of-file has been reach, so peer will send no new data. Wake up
262  * anyone that is waiting for data.
263  */
264 void
265 so_notify_eof(struct sonode *so)
266 {
267 	int pollev = 0;
268 	int sigev = 0;
269 
270 	ASSERT(MUTEX_HELD(&so->so_lock));
271 
272 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
273 
274 	if (IS_KERNEL_SOCKET(so)) {
275 		SO_WAKEUP_READER(so);
276 		KSOCKET_CALLBACK(so, cantrecvmore, 0);
277 		mutex_exit(&so->so_lock);
278 	} else {
279 		if (sigev != 0)
280 			socket_sendsig(so, sigev);
281 		mutex_exit(&so->so_lock);
282 		if (pollev != 0)
283 			pollwakeup(&so->so_poll_list, pollev);
284 
285 	}
286 
287 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
288 }
289 
290 /*
291  * Wake up anyone waiting for a new connection.
292  */
293 void
294 so_notify_newconn(struct sonode *so)
295 {
296 	ASSERT(MUTEX_HELD(&so->so_lock));
297 
298 	if (IS_KERNEL_SOCKET(so)) {
299 		KSOCKET_CALLBACK(so, newconn, so->so_rcv_queued);
300 		mutex_exit(&so->so_lock);
301 	} else {
302 		socket_sendsig(so, SOCKETSIG_READ);
303 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
304 			so->so_pollev &= ~SO_POLLEV_IN;
305 			mutex_exit(&so->so_lock);
306 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
307 		} else {
308 			mutex_exit(&so->so_lock);
309 		}
310 	}
311 
312 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
313 }
314 
315 /*
316  * User initated shutdown/close, wake anyone that is trying to do
317  * an operation that is no longer possible.
318  */
319 void
320 so_notify_shutdown(struct sonode *so)
321 {
322 	int pollev = 0;
323 	int sigev = 0;
324 
325 	ASSERT(MUTEX_HELD(&so->so_lock));
326 	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
327 
328 	if (so->so_state & SS_CANTSENDMORE)
329 		(void) i_so_notify_last_tx(so, &pollev, &sigev);
330 	if (so->so_state & SS_CANTRCVMORE)
331 		(void) i_so_notify_last_rx(so, &pollev, &sigev);
332 
333 	if (sigev != 0)
334 		socket_sendsig(so, sigev);
335 	mutex_exit(&so->so_lock);
336 	if (pollev != 0)
337 		pollwakeup(&so->so_poll_list, pollev);
338 
339 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
340 }
341 
342 /*
343  * No more data will be coming in, and this will be the last notification
344  * made.
345  */
346 static int
347 i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
348 {
349 	if (!(so->so_state & SS_SENTLASTREADSIG)) {
350 		SOCKET_TIMER_CANCEL(so);
351 		SO_WAKEUP_READER(so);
352 		so->so_state |= SS_SENTLASTREADSIG;
353 		so->so_pollev &= ~SO_POLLEV_IN;
354 
355 		*pollev |= POLLIN|POLLRDNORM;
356 		*sigev |= SOCKETSIG_READ;
357 
358 		return (1);
359 	} else {
360 		return (0);
361 	}
362 }
363 
364 /*
365  * The socket is un-writeable. Make one last notification.
366  */
367 static int
368 i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
369 {
370 	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
371 		SO_WAKEUP_WRITER(so);
372 		so->so_state |= SS_SENTLASTWRITESIG;
373 
374 		*pollev |= POLLOUT;
375 		*sigev |= SOCKETSIG_WRITE;
376 
377 		return (1);
378 	} else {
379 		return (0);
380 	}
381 }
382