summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2007-05-24 19:31:54 (GMT)
committerdgp <dgp@users.sourceforge.net>2007-05-24 19:31:54 (GMT)
commit1b79fcd2d05e9bba1b792a5c9e5ff382e905d48d (patch)
tree0dbb6f984446075d5f7ceb0f5e7e96b99257f027 /generic/tclIO.c
parentc8906bba93ebab65da4181fa6e1761e627e67a00 (diff)
downloadtcl-1b79fcd2d05e9bba1b792a5c9e5ff382e905d48d.zip
tcl-1b79fcd2d05e9bba1b792a5c9e5ff382e905d48d.tar.gz
tcl-1b79fcd2d05e9bba1b792a5c9e5ff382e905d48d.tar.bz2
* generic/tclIO.c: Backport memleak fix in TclFinalizeIOSubsystem.
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c153
1 files changed, 79 insertions, 74 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 407a88f..53824b0 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIO.c,v 1.61.2.22 2006/09/25 21:55:06 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.61.2.23 2007/05/24 19:31:55 dgp Exp $
*/
#include "tclInt.h"
@@ -204,97 +204,102 @@ TclInitIOSubsystem()
/* 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.
- */
+ /*
+ * 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.
+ */
- statePtr->refCount--;
- }
+ 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();