xref: /illumos-gate/usr/src/uts/common/fs/sockfs/socknotify.c (revision a5eb7107f06a6e23e8e77e8d3a84c1ff90a73ac6)
10f1702c5SYu Xiangning /*
20f1702c5SYu Xiangning  * CDDL HEADER START
30f1702c5SYu Xiangning  *
40f1702c5SYu Xiangning  * The contents of this file are subject to the terms of the
50f1702c5SYu Xiangning  * Common Development and Distribution License (the "License").
60f1702c5SYu Xiangning  * You may not use this file except in compliance with the License.
70f1702c5SYu Xiangning  *
80f1702c5SYu Xiangning  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90f1702c5SYu Xiangning  * or http://www.opensolaris.org/os/licensing.
100f1702c5SYu Xiangning  * See the License for the specific language governing permissions
110f1702c5SYu Xiangning  * and limitations under the License.
120f1702c5SYu Xiangning  *
130f1702c5SYu Xiangning  * When distributing Covered Code, include this CDDL HEADER in each
140f1702c5SYu Xiangning  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150f1702c5SYu Xiangning  * If applicable, add the following below this CDDL HEADER, with the
160f1702c5SYu Xiangning  * fields enclosed by brackets "[]" replaced with your own identifying
170f1702c5SYu Xiangning  * information: Portions Copyright [yyyy] [name of copyright owner]
180f1702c5SYu Xiangning  *
190f1702c5SYu Xiangning  * CDDL HEADER END
200f1702c5SYu Xiangning  */
210f1702c5SYu Xiangning 
220f1702c5SYu Xiangning /*
233e95bd4aSAnders Persson  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
240f1702c5SYu Xiangning  */
250f1702c5SYu Xiangning 
2668846fd0SBryan Cantrill /*
2768846fd0SBryan Cantrill  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
2868846fd0SBryan Cantrill  */
2968846fd0SBryan Cantrill 
300f1702c5SYu Xiangning #include <sys/types.h>
310f1702c5SYu Xiangning #include <sys/param.h>
320f1702c5SYu Xiangning #include <sys/systm.h>
330f1702c5SYu Xiangning #include <sys/stropts.h>
340f1702c5SYu Xiangning #include <sys/socketvar.h>
350f1702c5SYu Xiangning #include <sys/ksocket.h>
360f1702c5SYu Xiangning #include <io/ksocket/ksocket_impl.h>
370f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
38bbc000e5SAnders Persson #include <fs/sockfs/sodirect.h>
393e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h>
400f1702c5SYu Xiangning 
410f1702c5SYu Xiangning /*
420f1702c5SYu Xiangning  * There can only be a single thread waiting for data (enforced by
430f1702c5SYu Xiangning  * so_lock_read()), whereas for write there might be multiple threads
440f1702c5SYu Xiangning  * waiting for transmit buffers. So therefore we use cv_broadcast for
450f1702c5SYu Xiangning  * write and cv_signal for read.
460f1702c5SYu Xiangning  */
470f1702c5SYu Xiangning #define	SO_WAKEUP_READER(so) {				\
480f1702c5SYu Xiangning 	if ((so)->so_rcv_wakeup) {			\
490f1702c5SYu Xiangning 		(so)->so_rcv_wakeup = B_FALSE;		\
500f1702c5SYu Xiangning 		cv_signal(&(so)->so_rcv_cv);		\
510f1702c5SYu Xiangning 	}						\
520f1702c5SYu Xiangning }
530f1702c5SYu Xiangning 
540f1702c5SYu Xiangning #define	SO_WAKEUP_WRITER(so) {			\
550f1702c5SYu Xiangning 	if ((so)->so_snd_wakeup) {		\
560f1702c5SYu Xiangning 		(so)->so_snd_wakeup = B_FALSE;	\
570f1702c5SYu Xiangning 		cv_broadcast(&(so)->so_snd_cv);	\
580f1702c5SYu Xiangning 	}					\
590f1702c5SYu Xiangning }
600f1702c5SYu Xiangning 
610f1702c5SYu Xiangning static int i_so_notify_last_rx(struct sonode *, int *, int *);
620f1702c5SYu Xiangning static int i_so_notify_last_tx(struct sonode *, int *, int *);
630f1702c5SYu Xiangning 
640f1702c5SYu Xiangning /*
650f1702c5SYu Xiangning  * The notification functions must be called with so_lock held,
660f1702c5SYu Xiangning  * and they will all *drop* so_lock before returning.
670f1702c5SYu Xiangning  */
680f1702c5SYu Xiangning 
690f1702c5SYu Xiangning /*
700f1702c5SYu Xiangning  * Wake up anyone waiting for the connection to be established.
710f1702c5SYu Xiangning  */
720f1702c5SYu Xiangning void
so_notify_connected(struct sonode * so)730f1702c5SYu Xiangning so_notify_connected(struct sonode *so)
740f1702c5SYu Xiangning {
750f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
760f1702c5SYu Xiangning 
770f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
780f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, connected, 0);
790f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
800f1702c5SYu Xiangning 	} else {
810f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_WRITE);
820f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
830f1702c5SYu Xiangning 		pollwakeup(&so->so_poll_list, POLLOUT);
840f1702c5SYu Xiangning 	}
853e95bd4aSAnders Persson 	sof_sonode_notify_filters(so, SOF_EV_CONNECTED, 0);
860f1702c5SYu Xiangning 
870f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
880f1702c5SYu Xiangning }
890f1702c5SYu Xiangning 
900f1702c5SYu Xiangning /*
910f1702c5SYu Xiangning  * The socket is disconnecting, so no more data can be sent. Wake up
920f1702c5SYu Xiangning  * anyone that is waiting to send data.
930f1702c5SYu Xiangning  */
940f1702c5SYu Xiangning void
so_notify_disconnecting(struct sonode * so)950f1702c5SYu Xiangning so_notify_disconnecting(struct sonode *so)
960f1702c5SYu Xiangning {
970f1702c5SYu Xiangning 	int pollev = 0;
980f1702c5SYu Xiangning 	int sigev = 0;
990f1702c5SYu Xiangning 
1000f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
1013e95bd4aSAnders Persson 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
1020f1702c5SYu Xiangning 
1030f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
1040f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, cantsendmore, 0);
1050f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1063e95bd4aSAnders Persson 	} else {
1073e95bd4aSAnders Persson 		if (sigev != 0)
1080f1702c5SYu Xiangning 			socket_sendsig(so, sigev);
1090f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
11068846fd0SBryan Cantrill 
1113e95bd4aSAnders Persson 		if (pollev != 0)
1120f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, pollev);
1130f1702c5SYu Xiangning 	}
1143e95bd4aSAnders Persson 	sof_sonode_notify_filters(so, SOF_EV_CANTSENDMORE, 0);
1150f1702c5SYu Xiangning 
1160f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
1170f1702c5SYu Xiangning }
1180f1702c5SYu Xiangning 
1190f1702c5SYu Xiangning /*
1200f1702c5SYu Xiangning  * The socket is disconnected, so not more data can be sent or received.
1210f1702c5SYu Xiangning  * Wake up anyone that is waiting to send or receive data.
1220f1702c5SYu Xiangning  */
1230f1702c5SYu Xiangning void
so_notify_disconnected(struct sonode * so,boolean_t connfailed,int error)1243e95bd4aSAnders Persson so_notify_disconnected(struct sonode *so, boolean_t connfailed, int error)
1250f1702c5SYu Xiangning {
1260f1702c5SYu Xiangning 	int pollev = 0;
1270f1702c5SYu Xiangning 	int sigev = 0;
1280f1702c5SYu Xiangning 
1290f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
1300f1702c5SYu Xiangning 
1310f1702c5SYu Xiangning 	(void) i_so_notify_last_tx(so, &pollev, &sigev);
1320f1702c5SYu Xiangning 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
1330f1702c5SYu Xiangning 
1340f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
1353e95bd4aSAnders Persson 		if (connfailed) {
1360f1702c5SYu Xiangning 			KSOCKET_CALLBACK(so, disconnected, error);
1373e95bd4aSAnders Persson 		} else {
1383e95bd4aSAnders Persson 			KSOCKET_CALLBACK(so, connectfailed, error);
1393e95bd4aSAnders Persson 		}
1400f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1410f1702c5SYu Xiangning 	} else {
1420f1702c5SYu Xiangning 		if (sigev != 0)
1430f1702c5SYu Xiangning 			socket_sendsig(so, sigev);
1440f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
14568846fd0SBryan Cantrill 
14668846fd0SBryan Cantrill 		/*
14768846fd0SBryan Cantrill 		 * If we're here because the socket has become disconnected,
14868846fd0SBryan Cantrill 		 * we explicitly set POLLHUP.  At the same time, we also clear
14968846fd0SBryan Cantrill 		 * POLLOUT, as POLLOUT and POLLHUP are defined to be mutually
15068846fd0SBryan Cantrill 		 * exclusive with respect to one another.
15168846fd0SBryan Cantrill 		 */
15268846fd0SBryan Cantrill 		if (!connfailed)
15368846fd0SBryan Cantrill 			pollev = (pollev | POLLHUP) & ~POLLOUT;
15468846fd0SBryan Cantrill 
1550f1702c5SYu Xiangning 		if (pollev != 0)
1560f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, pollev);
1570f1702c5SYu Xiangning 	}
1583e95bd4aSAnders Persson 	sof_sonode_notify_filters(so, (connfailed) ? SOF_EV_CONNECTFAILED :
1593e95bd4aSAnders Persson 	    SOF_EV_DISCONNECTED, error);
1600f1702c5SYu Xiangning 
1610f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
1620f1702c5SYu Xiangning }
1630f1702c5SYu Xiangning 
1640f1702c5SYu Xiangning /*
1650f1702c5SYu Xiangning  * The socket is writeable. Wake up anyone waiting to send data.
1660f1702c5SYu Xiangning  */
1670f1702c5SYu Xiangning void
so_notify_writable(struct sonode * so)1680f1702c5SYu Xiangning so_notify_writable(struct sonode *so)
1690f1702c5SYu Xiangning {
1700f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
1710f1702c5SYu Xiangning 
1720f1702c5SYu Xiangning 	SO_WAKEUP_WRITER(so);
1730f1702c5SYu Xiangning 
1740f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
1750f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, cansend, 0);
1760f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1770f1702c5SYu Xiangning 	} else {
1780f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_WRITE);
1790f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
1800f1702c5SYu Xiangning 		pollwakeup(&so->so_poll_list, POLLOUT);
1810f1702c5SYu Xiangning 	}
1820f1702c5SYu Xiangning 
1830f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
1843e95bd4aSAnders Persson 
1853e95bd4aSAnders Persson 	/* filters can start injecting data */
1863e95bd4aSAnders Persson 	if (so->so_filter_active > 0)
1873e95bd4aSAnders Persson 		sof_sonode_notify_filters(so, SOF_EV_INJECT_DATA_OUT_OK, 0);
1880f1702c5SYu Xiangning }
1890f1702c5SYu Xiangning 
1900f1702c5SYu Xiangning /*
1910f1702c5SYu Xiangning  * Data is available, so wake up anyone waiting for data.
1920f1702c5SYu Xiangning  */
1930f1702c5SYu Xiangning void
so_notify_data(struct sonode * so,size_t qlen)1940f1702c5SYu Xiangning so_notify_data(struct sonode *so, size_t qlen)
1950f1702c5SYu Xiangning {
1960f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
1970f1702c5SYu Xiangning 
1980f1702c5SYu Xiangning 	SO_WAKEUP_READER(so);
1990f1702c5SYu Xiangning 
2000f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
2010f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, newdata, qlen);
2020f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2030f1702c5SYu Xiangning 	} else {
2040f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_READ);
2050f1702c5SYu Xiangning 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
2060f1702c5SYu Xiangning 			so->so_pollev &= ~SO_POLLEV_IN;
2070f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
2080f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
2090f1702c5SYu Xiangning 		} else {
2100f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
2110f1702c5SYu Xiangning 		}
2120f1702c5SYu Xiangning 	}
2130f1702c5SYu Xiangning 
2140f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2150f1702c5SYu Xiangning }
2160f1702c5SYu Xiangning 
2170f1702c5SYu Xiangning /*
2180f1702c5SYu Xiangning  * Transient error. Wake up anyone waiting to send or receive data.
2190f1702c5SYu Xiangning  */
2200f1702c5SYu Xiangning void
so_notify_error(struct sonode * so)2210f1702c5SYu Xiangning so_notify_error(struct sonode *so)
2220f1702c5SYu Xiangning {
2230f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
2240f1702c5SYu Xiangning 
2250f1702c5SYu Xiangning 	SO_WAKEUP_WRITER(so);
2260f1702c5SYu Xiangning 	SO_WAKEUP_READER(so);
2270f1702c5SYu Xiangning 
2280f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
2290f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, error, 0);
2300f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2310f1702c5SYu Xiangning 	} else {
2320f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_WRITE|SOCKETSIG_READ);
2330f1702c5SYu Xiangning 		so->so_pollev &= ~SO_POLLEV_IN;
2340f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2350f1702c5SYu Xiangning 		pollwakeup(&so->so_poll_list, POLLOUT|POLLIN|POLLRDNORM);
2360f1702c5SYu Xiangning 	}
2370f1702c5SYu Xiangning 
2380f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2390f1702c5SYu Xiangning }
2400f1702c5SYu Xiangning 
2410f1702c5SYu Xiangning /*
2420f1702c5SYu Xiangning  * Out-of-band data is incoming, notify any interested parties.
2430f1702c5SYu Xiangning  */
2440f1702c5SYu Xiangning void
so_notify_oobsig(struct sonode * so)2450f1702c5SYu Xiangning so_notify_oobsig(struct sonode *so)
2460f1702c5SYu Xiangning {
2470f1702c5SYu Xiangning 	socket_sendsig(so, SOCKETSIG_URG);
2480f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
2490f1702c5SYu Xiangning 	pollwakeup(&so->so_poll_list, POLLRDBAND);
2500f1702c5SYu Xiangning }
2510f1702c5SYu Xiangning 
2520f1702c5SYu Xiangning /*
2530f1702c5SYu Xiangning  * Received out-of-band data. If the OOB data is delivered inline, then
2540f1702c5SYu Xiangning  * in addition of regular OOB notification, anyone waiting for normal
2550f1702c5SYu Xiangning  * data is also notified.
2560f1702c5SYu Xiangning  */
2570f1702c5SYu Xiangning void
so_notify_oobdata(struct sonode * so,boolean_t oob_inline)2580f1702c5SYu Xiangning so_notify_oobdata(struct sonode *so, boolean_t oob_inline)
2590f1702c5SYu Xiangning {
2600f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
261bbc000e5SAnders Persson 	if (so->so_direct != NULL)
2620f1702c5SYu Xiangning 		SOD_UIOAFINI(so->so_direct);
2630f1702c5SYu Xiangning 
2640f1702c5SYu Xiangning 	SO_WAKEUP_READER(so);
2658591a19aSAnders Persson 
2668591a19aSAnders Persson 	if (IS_KERNEL_SOCKET(so)) {
2670f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, oobdata, 0);
2680f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
2690f1702c5SYu Xiangning 	} else {
2700f1702c5SYu Xiangning 		if (oob_inline) {
2710f1702c5SYu Xiangning 			socket_sendsig(so, SOCKETSIG_READ);
2720f1702c5SYu Xiangning 			so->so_pollev &= ~SO_POLLEV_IN;
2730f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
2740f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list,
2750f1702c5SYu Xiangning 			    POLLRDBAND|POLLIN|POLLRDNORM);
2760f1702c5SYu Xiangning 		} else {
2770f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
2780f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, POLLRDBAND);
2790f1702c5SYu Xiangning 		}
2800f1702c5SYu Xiangning 	}
2810f1702c5SYu Xiangning 
2820f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
2830f1702c5SYu Xiangning }
2840f1702c5SYu Xiangning 
2850f1702c5SYu Xiangning /*
2860f1702c5SYu Xiangning  * End-of-file has been reach, so peer will send no new data. Wake up
2870f1702c5SYu Xiangning  * anyone that is waiting for data.
2880f1702c5SYu Xiangning  */
2890f1702c5SYu Xiangning void
so_notify_eof(struct sonode * so)2900f1702c5SYu Xiangning so_notify_eof(struct sonode *so)
2910f1702c5SYu Xiangning {
2920f1702c5SYu Xiangning 	int pollev = 0;
2930f1702c5SYu Xiangning 	int sigev = 0;
2940f1702c5SYu Xiangning 
2950f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
2960f1702c5SYu Xiangning 
2970f1702c5SYu Xiangning 	(void) i_so_notify_last_rx(so, &pollev, &sigev);
2980f1702c5SYu Xiangning 
2990f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
3000f1702c5SYu Xiangning 		KSOCKET_CALLBACK(so, cantrecvmore, 0);
3010f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3020f1702c5SYu Xiangning 	} else {
3030f1702c5SYu Xiangning 		if (sigev != 0)
3040f1702c5SYu Xiangning 			socket_sendsig(so, sigev);
3050f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3060f1702c5SYu Xiangning 		if (pollev != 0)
3070f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, pollev);
3080f1702c5SYu Xiangning 
3090f1702c5SYu Xiangning 	}
3103e95bd4aSAnders Persson 	sof_sonode_notify_filters(so, SOF_EV_CANTRECVMORE, 0);
3110f1702c5SYu Xiangning 
3120f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3130f1702c5SYu Xiangning }
3140f1702c5SYu Xiangning 
3150f1702c5SYu Xiangning /*
3160f1702c5SYu Xiangning  * Wake up anyone waiting for a new connection.
3170f1702c5SYu Xiangning  */
3180f1702c5SYu Xiangning void
so_notify_newconn(struct sonode * so)3190f1702c5SYu Xiangning so_notify_newconn(struct sonode *so)
3200f1702c5SYu Xiangning {
3210f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
3220f1702c5SYu Xiangning 
3230f1702c5SYu Xiangning 	if (IS_KERNEL_SOCKET(so)) {
3243e95bd4aSAnders Persson 		KSOCKET_CALLBACK(so, newconn, 0);
3250f1702c5SYu Xiangning 		mutex_exit(&so->so_lock);
3260f1702c5SYu Xiangning 	} else {
3270f1702c5SYu Xiangning 		socket_sendsig(so, SOCKETSIG_READ);
3280f1702c5SYu Xiangning 		if (so->so_pollev & (SO_POLLEV_IN|SO_POLLEV_ALWAYS)) {
3290f1702c5SYu Xiangning 			so->so_pollev &= ~SO_POLLEV_IN;
3300f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
3310f1702c5SYu Xiangning 			pollwakeup(&so->so_poll_list, POLLIN|POLLRDNORM);
3320f1702c5SYu Xiangning 		} else {
3330f1702c5SYu Xiangning 			mutex_exit(&so->so_lock);
3340f1702c5SYu Xiangning 		}
3350f1702c5SYu Xiangning 	}
3360f1702c5SYu Xiangning 
3370f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3380f1702c5SYu Xiangning }
3390f1702c5SYu Xiangning 
3400f1702c5SYu Xiangning /*
3410f1702c5SYu Xiangning  * User initated shutdown/close, wake anyone that is trying to do
3420f1702c5SYu Xiangning  * an operation that is no longer possible.
3430f1702c5SYu Xiangning  */
3440f1702c5SYu Xiangning void
so_notify_shutdown(struct sonode * so)3450f1702c5SYu Xiangning so_notify_shutdown(struct sonode *so)
3460f1702c5SYu Xiangning {
3470f1702c5SYu Xiangning 	int pollev = 0;
3480f1702c5SYu Xiangning 	int sigev = 0;
3490f1702c5SYu Xiangning 
3500f1702c5SYu Xiangning 	ASSERT(MUTEX_HELD(&so->so_lock));
3510f1702c5SYu Xiangning 	ASSERT(so->so_state & (SS_CANTSENDMORE|SS_CANTRCVMORE));
3520f1702c5SYu Xiangning 
3530f1702c5SYu Xiangning 	if (so->so_state & SS_CANTSENDMORE)
3540f1702c5SYu Xiangning 		(void) i_so_notify_last_tx(so, &pollev, &sigev);
3550f1702c5SYu Xiangning 	if (so->so_state & SS_CANTRCVMORE)
3560f1702c5SYu Xiangning 		(void) i_so_notify_last_rx(so, &pollev, &sigev);
3570f1702c5SYu Xiangning 
3580f1702c5SYu Xiangning 	if (sigev != 0)
3590f1702c5SYu Xiangning 		socket_sendsig(so, sigev);
3600f1702c5SYu Xiangning 	mutex_exit(&so->so_lock);
3610f1702c5SYu Xiangning 	if (pollev != 0)
3620f1702c5SYu Xiangning 		pollwakeup(&so->so_poll_list, pollev);
3630f1702c5SYu Xiangning 
3640f1702c5SYu Xiangning 	ASSERT(MUTEX_NOT_HELD(&so->so_lock));
3650f1702c5SYu Xiangning }
3660f1702c5SYu Xiangning 
3670f1702c5SYu Xiangning /*
3680f1702c5SYu Xiangning  * No more data will be coming in, and this will be the last notification
3690f1702c5SYu Xiangning  * made.
3700f1702c5SYu Xiangning  */
3710f1702c5SYu Xiangning static int
i_so_notify_last_rx(struct sonode * so,int * pollev,int * sigev)3720f1702c5SYu Xiangning i_so_notify_last_rx(struct sonode *so, int *pollev, int *sigev)
3730f1702c5SYu Xiangning {
3740f1702c5SYu Xiangning 	if (!(so->so_state & SS_SENTLASTREADSIG)) {
3750f1702c5SYu Xiangning 		SOCKET_TIMER_CANCEL(so);
3760f1702c5SYu Xiangning 		SO_WAKEUP_READER(so);
3770f1702c5SYu Xiangning 		so->so_state |= SS_SENTLASTREADSIG;
3780f1702c5SYu Xiangning 		so->so_pollev &= ~SO_POLLEV_IN;
3790f1702c5SYu Xiangning 
380*a5eb7107SBryan Cantrill 		*pollev |= POLLIN|POLLRDNORM|POLLRDHUP;
3810f1702c5SYu Xiangning 		*sigev |= SOCKETSIG_READ;
3820f1702c5SYu Xiangning 
3830f1702c5SYu Xiangning 		return (1);
3840f1702c5SYu Xiangning 	} else {
3850f1702c5SYu Xiangning 		return (0);
3860f1702c5SYu Xiangning 	}
3870f1702c5SYu Xiangning }
3880f1702c5SYu Xiangning 
3890f1702c5SYu Xiangning /*
3900f1702c5SYu Xiangning  * The socket is un-writeable. Make one last notification.
3910f1702c5SYu Xiangning  */
3920f1702c5SYu Xiangning static int
i_so_notify_last_tx(struct sonode * so,int * pollev,int * sigev)3930f1702c5SYu Xiangning i_so_notify_last_tx(struct sonode *so, int *pollev, int *sigev)
3940f1702c5SYu Xiangning {
3950f1702c5SYu Xiangning 	if (!(so->so_state & SS_SENTLASTWRITESIG)) {
3960f1702c5SYu Xiangning 		SO_WAKEUP_WRITER(so);
3970f1702c5SYu Xiangning 		so->so_state |= SS_SENTLASTWRITESIG;
3980f1702c5SYu Xiangning 
3990f1702c5SYu Xiangning 		*pollev |= POLLOUT;
4000f1702c5SYu Xiangning 		*sigev |= SOCKETSIG_WRITE;
4010f1702c5SYu Xiangning 
4020f1702c5SYu Xiangning 		return (1);
4030f1702c5SYu Xiangning 	} else {
4040f1702c5SYu Xiangning 		return (0);
4050f1702c5SYu Xiangning 	}
4060f1702c5SYu Xiangning }
407