xref: /titanic_51/usr/src/uts/common/fs/sockfs/socknotify.c (revision 5a00db9d04809df47502f8002f0295cb0b7966e0)
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 2008 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 
36 /*
37  * There can only be a single thread waiting for data (enforced by
38  * so_lock_read()), whereas for write there might be multiple threads
39  * waiting for transmit buffers. So therefore we use cv_broadcast for
40  * write and cv_signal for read.
41  */
42 #define	SO_WAKEUP_READER(so) {				\
43 	if ((so)->so_rcv_wakeup) {			\
44 		(so)->so_rcv_wakeup = B_FALSE;		\
45 		cv_signal(&(so)->so_rcv_cv);		\
46 	}						\
47 }
48 
49 #define	SO_WAKEUP_WRITER(so) {			\
50 	if ((so)->so_snd_wakeup) {		\
51 		(so)->so_snd_wakeup = B_FALSE;	\
52 		cv_broadcast(&(so)->so_snd_cv);	\
53 	}					\
54 }
55 
56 static int i_so_notify_last_rx(struct sonode *, int *, int *);
57 static int i_so_notify_last_tx(struct sonode *, int *, int *);
58 
59 /*
60  * The notification functions must be called with so_lock held,
61  * and they will all *drop* so_lock before returning.
62  */
63 
64 /*
65  * Wake up anyone waiting for the connection to be established.
66  */
67 void
68 so_notify_connected(struct sonode *so)
69 {
70 	ASSERT(MUTEX_HELD(&so->so_lock));
71 
72 	if (IS_KERNEL_SOCKET(so)) {
73 		KSOCKET_CALLBACK(so, connected, 0);
74 		mutex_exit(&so->so_lock);
75 	} else {
76 		socket_sendsig(so, SOCKETSIG_WRITE);
77 		mutex_exit(&so->so_lock);
78 		pollwakeup(&so->so_poll_list, POLLOUT);
79 	}
80 
81 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
82 }
83 
84 /*
85  * The socket is disconnecting, so no more data can be sent. Wake up
86  * anyone that is waiting to send data.
87  */
88 void
89 so_notify_disconnecting(struct sonode *so)
90 {
91 	int pollev = 0;
92 	int sigev = 0;
93 
94 	ASSERT(MUTEX_HELD(&so->so_lock));
95 
96 	if (IS_KERNEL_SOCKET(so)) {
97 		SO_WAKEUP_WRITER(so);
98 		KSOCKET_CALLBACK(so, cantsendmore, 0);
99 		mutex_exit(&so->so_lock);
100 	} else if (i_so_notify_last_tx(so, &pollev, &sigev)) {
101 		socket_sendsig(so, sigev);
102 		mutex_exit(&so->so_lock);
103 		pollwakeup(&so->so_poll_list, pollev);
104 	} else {
105 		mutex_exit(&so->so_lock);
106 	}
107 
108 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
109 }
110 
111 /*
112  * The socket is disconnected, so not more data can be sent or received.
113  * Wake up anyone that is waiting to send or receive data.
114  */
115 void
116 so_notify_disconnected(struct sonode *so, int error)
117 {
118 	int pollev = 0;
119 	int sigev = 0;
120 
121 	ASSERT(MUTEX_HELD(&so->so_lock));
122 
123 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
124 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
125 
126 	if (IS_KERNEL_SOCKET(so)) {
127 		KSOCKET_CALLBACK(so, disconnected, error);
128 		mutex_exit(&so->so_lock);
129 	} else {
130 		if (sigev != 0)
131 			socket_sendsig(so, sigev);
132 		mutex_exit(&so->so_lock);
133 		if (pollev != 0)
134 			pollwakeup(&so->so_poll_list, pollev);
135 	}
136 
137 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
138 }
139 
140 /*
141  * The socket is writeable. Wake up anyone waiting to send data.
142  */
143 void
144 so_notify_writable(struct sonode *so)
145 {
146 	ASSERT(MUTEX_HELD(&so->so_lock));
147 
148 	SO_WAKEUP_WRITER(so);
149 
150 	if (IS_KERNEL_SOCKET(so)) {
151 		KSOCKET_CALLBACK(so, cansend, 0);
152 		mutex_exit(&so->so_lock);
153 	} else {
154 		socket_sendsig(so, SOCKETSIG_WRITE);
155 		mutex_exit(&so->so_lock);
156 		pollwakeup(&so->so_poll_list, POLLOUT);
157 	}
158 
159 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
160 }
161 
162 /*
163  * Data is available, so wake up anyone waiting for data.
164  */
165 void
166 so_notify_data(struct sonode *so, size_t qlen)
167 {
168 	ASSERT(MUTEX_HELD(&so->so_lock));
169 
170 	SO_WAKEUP_READER(so);
171 
172 	if (IS_KERNEL_SOCKET(so)) {
173 		KSOCKET_CALLBACK(so, newdata, qlen);
174 		mutex_exit(&so->so_lock);
175 	} else {
176 		socket_sendsig(so, SOCKETSIG_READ);
177 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
178 			so->so_pollev &= ~SO_POLLEV_IN;
179 			mutex_exit(&so->so_lock);
180 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
181 		} else {
182 			mutex_exit(&so->so_lock);
183 		}
184 	}
185 
186 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
187 }
188 
189 /*
190  * Transient error. Wake up anyone waiting to send or receive data.
191  */
192 void
193 so_notify_error(struct sonode *so)
194 {
195 	ASSERT(MUTEX_HELD(&so->so_lock));
196 
197 	SO_WAKEUP_WRITER(so);
198 	SO_WAKEUP_READER(so);
199 
200 	if (IS_KERNEL_SOCKET(so)) {
201 		KSOCKET_CALLBACK(so, error, 0);
202 		mutex_exit(&so->so_lock);
203 	} else {
204 		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
205 		so->so_pollev &= ~SO_POLLEV_IN;
206 		mutex_exit(&so->so_lock);
207 		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
208 	}
209 
210 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
211 }
212 
213 /*
214  * Out-of-band data is incoming, notify any interested parties.
215  */
216 void
217 so_notify_oobsig(struct sonode *so)
218 {
219 	socket_sendsig(so, SOCKETSIG_URG);
220 	mutex_exit(&so->so_lock);
221 	pollwakeup(&so->so_poll_list, POLLRDBAND);
222 }
223 
224 /*
225  * Received out-of-band data. If the OOB data is delivered inline, then
226  * in addition of regular OOB notification, anyone waiting for normal
227  * data is also notified.
228  */
229 void
230 so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
231 {
232 	ASSERT(MUTEX_HELD(&so->so_lock));
233 	SOD_UIOAFINI(so->so_direct);
234 
235 	if (IS_KERNEL_SOCKET(so)) {
236 		if (oob_inline)
237 			SO_WAKEUP_READER(so);
238 		KSOCKET_CALLBACK(so, oobdata, 0);
239 		mutex_exit(&so->so_lock);
240 	} else {
241 		if (oob_inline) {
242 			socket_sendsig(so, SOCKETSIG_READ);
243 			so->so_pollev &= ~SO_POLLEV_IN;
244 			mutex_exit(&so->so_lock);
245 			pollwakeup(&so->so_poll_list,
246 			    POLLRDBAND|POLLIN|POLLRDNORM);
247 
248 			SO_WAKEUP_READER(so);
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