changeset 2898:a9d0a48c9ff7

6240605 TCP connection in lingering state can't be killed.
author peterte
date Wed, 11 Oct 2006 06:24:52 -0700
parents 78c74f149c12
children 886fb919e004
files usr/src/uts/common/inet/tcp/tcp.c
diffstat 1 files changed, 46 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/tcp/tcp.c	Tue Oct 10 17:52:00 2006 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Wed Oct 11 06:24:52 2006 -0700
@@ -775,6 +775,7 @@
 void		tcp_output(void *arg, mblk_t *mp, void *arg2);
 static void	tcp_rsrv_input(void *arg, mblk_t *mp, void *arg2);
 static void	tcp_timer_handler(void *arg, mblk_t *mp, void *arg2);
+static void	tcp_linger_interrupted(void *arg, mblk_t *mp, void *arg2);
 
 
 /* Prototype for TCP functions */
@@ -3945,6 +3946,8 @@
 	tcp_t		*tcp = connp->conn_tcp;
 	mblk_t 		*mp = &tcp->tcp_closemp;
 	boolean_t	conn_ioctl_cleanup_reqd = B_FALSE;
+	boolean_t	linger_interrupted = B_FALSE;
+	mblk_t		*bp;
 
 	ASSERT(WR(q)->q_next == NULL);
 	ASSERT(connp->conn_ref >= 2);
@@ -3970,10 +3973,31 @@
 	    tcp_close_output, connp, SQTAG_IP_TCP_CLOSE);
 
 	mutex_enter(&tcp->tcp_closelock);
-
-	while (!tcp->tcp_closed)
-		cv_wait(&tcp->tcp_closecv, &tcp->tcp_closelock);
+	while (!tcp->tcp_closed) {
+		if (!cv_wait_sig(&tcp->tcp_closecv, &tcp->tcp_closelock)) {
+			/*
+			 * We got interrupted. Check if we are lingering,
+			 * if yes, post a message to stop and wait until
+			 * tcp_closed is set. If we aren't lingering,
+			 * just go back around.
+			 */
+			if (tcp->tcp_linger &&
+			    tcp->tcp_lingertime > 0 &&
+			    !linger_interrupted) {
+				mutex_exit(&tcp->tcp_closelock);
+				/* Entering squeue, bump ref count. */
+				CONN_INC_REF(connp);
+				bp = allocb_wait(0, BPRI_HI, STR_NOSIG, NULL);
+				squeue_enter(connp->conn_sqp, bp,
+				    tcp_linger_interrupted, connp,
+				    SQTAG_IP_TCP_CLOSE);
+				linger_interrupted = B_TRUE;
+				mutex_enter(&tcp->tcp_closelock);
+			}
+		}
+	}
 	mutex_exit(&tcp->tcp_closelock);
+
 	/*
 	 * In the case of listener streams that have eagers in the q or q0
 	 * we wait for the eagers to drop their reference to us. tcp_rq and
@@ -4032,6 +4056,25 @@
 	return (0);
 }
 
+/*
+ * Called by tcp_close() routine via squeue when lingering is
+ * interrupted by a signal.
+ */
+
+/* ARGSUSED */
+static void
+tcp_linger_interrupted(void *arg, mblk_t *mp, void *arg2)
+{
+	conn_t	*connp = (conn_t *)arg;
+	tcp_t	*tcp = connp->conn_tcp;
+
+	freeb(mp);
+	if (tcp->tcp_linger_tid != 0 &&
+	    TCP_TIMER_CANCEL(tcp, tcp->tcp_linger_tid) >= 0) {
+		tcp_stop_lingering(tcp);
+		tcp->tcp_client_errno = EINTR;
+	}
+}
 
 /*
  * Called by streams close routine via squeues when our client blows off her