Tcl Source Code

Artifact [d7f1d566ff]
Login

Artifact d7f1d566ffb6d1dd19c01d5cfcc89f707ea7af27:

Attachment "leak.patch" to ticket [1725119fff] added by dgp 2007-05-25 02:08:07.
Index: generic/tclIO.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIO.c,v
retrieving revision 1.61.2.22
diff -u -r1.61.2.22 tclIO.c
--- generic/tclIO.c	25 Sep 2006 21:55:06 -0000	1.61.2.22
+++ generic/tclIO.c	24 May 2007 19:05:23 -0000
@@ -204,97 +204,102 @@
 
 	/* ARGSUSED */
 void
-TclFinalizeIOSubsystem()
+TclFinalizeIOSubsystem(void)
 {
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    Channel *chanPtr;			/* Iterates over open channels. */
-    ChannelState *nextCSPtr;		/* Iterates over open channels. */
-    ChannelState *statePtr;		/* state of channel stack */
+    Channel *chanPtr = NULL;	/* Iterates over open channels. */
+    ChannelState *statePtr;	/* State of channel stack */
+    int active = 1;		/* Flag == 1 while there's still work to do */
 
     /*
      * Walk all channel state structures known to this thread and
      * close corresponding channels.
      */
 
-    for (statePtr = tsdPtr->firstCSPtr; statePtr != (ChannelState *) NULL;
-	 statePtr = nextCSPtr) {
-	chanPtr = statePtr->topChanPtr;
+    while (active) {
 
-        /*
-         * Set the channel back into blocking mode to ensure that we wait
-         * for all data to flush out.
-         */
-
-        (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
-                "-blocking", "on");
-
-        if ((chanPtr == (Channel *) tsdPtr->stdinChannel) ||
-                (chanPtr == (Channel *) tsdPtr->stdoutChannel) ||
-                (chanPtr == (Channel *) tsdPtr->stderrChannel)) {
-            /*
-             * Decrement the refcount which was earlier artificially bumped
-             * up to keep the channel from being closed.
-             */
-
-            statePtr->refCount--;
-        }
+	/*
+	 * Iterate through the open channel list, and find the first
+	 * channel that isn't dead. We start from the head of the list
+	 * each time, because the close action on one channel can close
+	 * others.
+	 */
+
+	active = 0;
+	for (statePtr = tsdPtr->firstCSPtr;
+	     statePtr != NULL;
+	     statePtr = statePtr->nextCSPtr) {
+	    chanPtr = statePtr->topChanPtr;
+	    if (!(statePtr->flags & CHANNEL_DEAD)) {
+		active = 1;
+		break;
+	    }
+	}
 
 	/*
-	 * Preserve statePtr from disappearing until we can get the
-	 * nextCSPtr below.
+	 * We've found a live channel.  Close it.
 	 */
 
-	Tcl_Preserve(statePtr);
-
-        if (statePtr->refCount <= 0) {
+	if (active) {
 
 	    /*
-             * Close it only if the refcount indicates that the channel is not
-             * referenced from any interpreter. If it is, that interpreter will
-             * close the channel when it gets destroyed.
-             */
-
-            (void) Tcl_Close((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr);
-
-        } else {
-
-            /*
-             * The refcount is greater than zero, so flush the channel.
-             */
-
-            Tcl_Flush((Tcl_Channel) chanPtr);
-
-            /*
-             * Call the device driver to actually close the underlying
-             * device for this channel.
-             */
-
-	    if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
-		(chanPtr->typePtr->closeProc)(chanPtr->instanceData,
-			(Tcl_Interp *) NULL);
+	     * Set the channel back into blocking mode to ensure that we 
+	     * wait for all data to flush out.
+	     */
+	    
+	    (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
+					"-blocking", "on");
+	    
+	    if ((chanPtr == (Channel *) tsdPtr->stdinChannel) ||
+		(chanPtr == (Channel *) tsdPtr->stdoutChannel) ||
+		(chanPtr == (Channel *) tsdPtr->stderrChannel)) {
+		/*
+		 * Decrement the refcount which was earlier artificially 
+		 * bumped up to keep the channel from being closed.
+		 */
+		
+		statePtr->refCount--;
+	    }
+	    
+	    if (statePtr->refCount <= 0) {
+		/*
+		 * Close it only if the refcount indicates that the channel 
+		 * is not referenced from any interpreter. If it is, that
+		 * interpreter will close the channel when it gets destroyed.
+		 */
+		
+		(void) Tcl_Close(NULL, (Tcl_Channel) chanPtr);
 	    } else {
-		(chanPtr->typePtr->close2Proc)(chanPtr->instanceData,
-			(Tcl_Interp *) NULL, 0);
+		/*
+		 * The refcount is greater than zero, so flush the channel.
+		 */
+		
+		Tcl_Flush((Tcl_Channel) chanPtr);
+		
+		/*
+		 * Call the device driver to actually close the underlying 
+		 * device for this channel.
+		 */
+		
+		if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
+		    (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL);
+		} else {
+		    (chanPtr->typePtr->close2Proc)(chanPtr->instanceData,
+						   NULL, 0);
+		}
+		
+		/*
+		 * Finally, we clean up the fields in the channel data 
+		 * structure since all of them have been deleted already. 
+		 * We mark the channel with CHANNEL_DEAD to prevent any 
+		 * further IO operations
+		 * on it.
+		 */
+		
+		chanPtr->instanceData = NULL;
+		statePtr->flags |= CHANNEL_DEAD;
 	    }
-
-            /*
-             * Finally, we clean up the fields in the channel data structure
-             * since all of them have been deleted already. We mark the
-             * channel with CHANNEL_DEAD to prevent any further IO operations
-             * on it.
-             */
-
-            chanPtr->instanceData = (ClientData) NULL;
-            statePtr->flags |= CHANNEL_DEAD;
-        }
-
-	/*
-	 * We look for the next pointer now in case we had one closed on up
-	 * during the current channel's closeproc (eg: rechan extension)
-	 */
-
-	nextCSPtr = statePtr->nextCSPtr;
-	Tcl_Release(statePtr);
+	}
     }
 
     TclpFinalizeSockets();