diff options
author | Kevin B Kenny <kennykb@acm.org> | 2007-05-01 22:43:49 (GMT) |
---|---|---|
committer | Kevin B Kenny <kennykb@acm.org> | 2007-05-01 22:43:49 (GMT) |
commit | 17b8d2d3e3ac333f60da3b27fc34190d212670dd (patch) | |
tree | c96aa1e1faf9a0d0ba901be5c85b7737cafc1fce /generic/tclIO.c | |
parent | 2ac57a490ebcd5bd43e7f03e705a243ce67ffa37 (diff) | |
download | tcl-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]
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r-- | generic/tclIO.c | 132 |
1 files changed, 72 insertions, 60 deletions
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); |