summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin B Kenny <kennykb@acm.org>2007-05-01 22:43:49 (GMT)
committerKevin B Kenny <kennykb@acm.org>2007-05-01 22:43:49 (GMT)
commit17b8d2d3e3ac333f60da3b27fc34190d212670dd (patch)
treec96aa1e1faf9a0d0ba901be5c85b7737cafc1fce
parent2ac57a490ebcd5bd43e7f03e705a243ce67ffa37 (diff)
downloadtcl-17b8d2d3e3ac333f60da3b27fc34190d212670dd.zip
tcl-17b8d2d3e3ac333f60da3b27fc34190d212670dd.tar.gz
tcl-17b8d2d3e3ac333f60da3b27fc34190d212670dd.tar.bz2
* generic/tclIO.c (DeleteChannelTable): Made changes so that
DeleteChannelTable tries to close all open channels, not just the first. [Bug 1710285] * generic/tclThread.c (TclFinalizeSynchronization): Make sure that TSD blocks get freed on non-threaded builds. [Bug 1710825]
-rw-r--r--ChangeLog8
-rw-r--r--generic/tclIO.c132
-rw-r--r--generic/tclThread.c27
3 files changed, 91 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index e074932..52f4119 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-05-01 Kevin B. Kenny <kennykb@acm.org>
+
+ * generic/tclIO.c (DeleteChannelTable): Made changes so that
+ DeleteChannelTable tries to close all open channels, not just the
+ first. [Bug 1710285]
+ * generic/tclThread.c (TclFinalizeSynchronization): Make sure
+ that TSD blocks get freed on non-threaded builds. [Bug 1710825]
+
2007-05-01 Don Porter <dgp@users.sourceforge.net>
* generic/tclCmdMZ.c (STR_MAP): When [string map] has a pure dict
diff --git a/generic/tclIO.c b/generic/tclIO.c
index ba2cc1c..26d9724 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.119 2007/04/30 21:40:24 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.120 2007/05/01 22:43:49 kennykb Exp $
*/
#include "tclInt.h"
@@ -248,87 +248,98 @@ 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 */
+ 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 != 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.
+ * 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.
*/
- (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--;
+ 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) {
- /*
- * 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 {
- /*
- * The refcount is greater than zero, so flush the channel.
- */
-
- Tcl_Flush((Tcl_Channel) chanPtr);
+ if (active) {
/*
- * Call the device driver to actually close the underlying device
- * for this channel.
+ * Set the channel back into blocking mode to ensure that we
+ * wait for all data to flush out.
*/
-
- if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
- (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL);
+
+ (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, 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 = 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();
@@ -672,6 +683,7 @@ DeleteChannelTable(
(void) Tcl_Close(interp, (Tcl_Channel) chanPtr);
}
}
+
}
Tcl_DeleteHashTable(hTblPtr);
ckfree((char *) hTblPtr);
diff --git a/generic/tclThread.c b/generic/tclThread.c
index 9372d78..60c09ca 100644
--- a/generic/tclThread.c
+++ b/generic/tclThread.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclThread.c,v 1.15 2006/11/07 14:26:26 dkf Exp $
+ * RCS: @(#) $Id: tclThread.c,v 1.16 2007/05/01 22:43:50 kennykb Exp $
*/
#include "tclInt.h"
@@ -357,32 +357,34 @@ TclFinalizeThreadData(void)
void
TclFinalizeSynchronization(void)
{
-#ifdef TCL_THREADS
+ int i;
void *blockPtr;
Tcl_ThreadDataKey *keyPtr;
+#ifdef TCL_THREADS
Tcl_Mutex *mutexPtr;
Tcl_Condition *condPtr;
- int i;
TclpMasterLock();
+#endif
/*
* If we're running unthreaded, the TSD blocks are simply stored inside
* their thread data keys. Free them here.
*/
- for (i=0 ; i<keyRecord.num ; i++) {
- keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
- blockPtr = (void *) *keyPtr;
- ckfree(blockPtr);
- }
if (keyRecord.list != NULL) {
+ for (i=0 ; i<keyRecord.num ; i++) {
+ keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i];
+ blockPtr = (void *) *keyPtr;
+ ckfree(blockPtr);
+ }
ckfree((char *) keyRecord.list);
keyRecord.list = NULL;
}
keyRecord.max = 0;
keyRecord.num = 0;
-
+
+#ifdef TCL_THREADS
/*
* Call thread storage master cleanup.
*/
@@ -416,13 +418,6 @@ TclFinalizeSynchronization(void)
condRecord.num = 0;
TclpMasterUnlock();
-#else /* TCL_THREADS */
- if (keyRecord.list != NULL) {
- ckfree((char *) keyRecord.list);
- keyRecord.list = NULL;
- }
- keyRecord.max = 0;
- keyRecord.num = 0;
#endif /* TCL_THREADS */
}