diff options
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r-- | generic/tclIO.c | 61 |
1 files changed, 43 insertions, 18 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 082cf70..2de8b53 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -396,6 +396,19 @@ TclFinalizeIOSubsystem(void) 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 */ + int doflushnb; + + /* Fetch the pre-TIP#398 compatibility flag */ + { + const char *s; + Tcl_DString ds; + + s = TclGetEnv("TCL_FLUSH_NONBLOCKING_ON_EXIT", &ds); + doflushnb = ((s != NULL) && strcmp(s, "0")); + if (s != NULL) { + Tcl_DStringFree(&ds); + } + } /* * Walk all channel state structures known to this thread and close @@ -414,25 +427,37 @@ TclFinalizeIOSubsystem(void) statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; - if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | CHANNEL_DEAD) + if (GotFlag(statePtr, CHANNEL_DEAD)) { + continue; + } + if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED ) || GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { + ResetFlag(statePtr, BG_FLUSH_SCHEDULED); active = 1; break; } } /* - * We've found a live channel. Close it. + * We've found a live (or bg-closing) channel. Close it. */ if (active) { + /* - * Set the channel back into blocking mode to ensure that we wait - * for all data to flush out. + * TIP #398: by default, we no longer set the channel back into + * blocking mode. To restore the old blocking behavior, the + * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set + * and not be "0". */ - - (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, - "-blocking", "on"); + if (doflushnb) { + /* 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) || @@ -458,7 +483,6 @@ TclFinalizeIOSubsystem(void) * The refcount is greater than zero, so flush the channel. */ - ResetFlag(statePtr, BG_FLUSH_SCHEDULED); Tcl_Flush((Tcl_Channel) chanPtr); /* @@ -4410,14 +4434,12 @@ Tcl_Gets( * for managing the storage. */ { Tcl_Obj *objPtr; - int charsStored, length; - const char *string; + int charsStored; TclNewObj(objPtr); charsStored = Tcl_GetsObj(chan, objPtr); if (charsStored > 0) { - string = TclGetStringFromObj(objPtr, &length); - Tcl_DStringAppend(lineRead, string, length); + TclDStringAppendObj(lineRead, objPtr); } TclDecrRefCount(objPtr); return charsStored; @@ -7529,7 +7551,7 @@ Tcl_BadChannelOption( Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, genericopt, -1); if (optionList && (*optionList)) { - Tcl_DStringAppend(&ds, " ", 1); + TclDStringAppendLiteral(&ds, " "); Tcl_DStringAppend(&ds, optionList, -1); } if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), @@ -8398,8 +8420,8 @@ UpdateInterest( mask &= ~TCL_EXCEPTION; if (!statePtr->timer) { - statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, - chanPtr); + statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, + ChannelTimerProc, chanPtr); } } } @@ -8440,7 +8462,8 @@ ChannelTimerProc( * before UpdateInterest gets called by Tcl_NotifyChannel. */ - statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,chanPtr); + statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, + ChannelTimerProc,chanPtr); #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* @@ -8739,7 +8762,7 @@ CreateScriptRecord( /* * Initialize the structure before calling Tcl_CreateChannelHandler, - * because a reflected channel caling 'chan postevent' aka + * because a reflected channel calling 'chan postevent' aka * 'Tcl_NotifyChannel' in its 'watch'Proc will invoke * 'TclChannelEventScriptInvoker' immediately, and we do not wish it to * see uninitialized memory and crash. See [Bug 2918110]. @@ -8802,6 +8825,7 @@ TclChannelEventScriptInvoker( */ Tcl_Preserve(interp); + Tcl_Preserve(chanPtr); result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL); /* @@ -8818,6 +8842,7 @@ TclChannelEventScriptInvoker( } Tcl_BackgroundException(interp, result); } + Tcl_Release(chanPtr); Tcl_Release(interp); } @@ -8856,7 +8881,7 @@ Tcl_FileEventObjCmd( int modeIndex; /* Index of mode argument. */ int mask; static const char *const modeOptions[] = {"readable", "writable", NULL}; - static int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; + static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); |