From 4469b8019b142def58d2f77fae3229675667eefe Mon Sep 17 00:00:00 2001 From: ferrieux Date: Thu, 22 Mar 2012 07:33:06 +0000 Subject: Implement tip 398 : Quickly Exit with Non-Blocking Blocked Channels. This is simply a revert of the (C part of the) 1025712d5b commit of 2011-08-17. --- generic/tclIO.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 082cf70..cf875a8 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -414,8 +414,8 @@ TclFinalizeIOSubsystem(void) statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; - if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | CHANNEL_DEAD) - || GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { + if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | + CHANNEL_DEAD)) { active = 1; break; } @@ -458,7 +458,6 @@ TclFinalizeIOSubsystem(void) * The refcount is greater than zero, so flush the channel. */ - ResetFlag(statePtr, BG_FLUSH_SCHEDULED); Tcl_Flush((Tcl_Channel) chanPtr); /* -- cgit v0.12 From 5a62da3750ddfade44c3113b96e1f5c7a0cef1f1 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Thu, 22 Mar 2012 08:04:09 +0000 Subject: Take two. Don't forget to apply all patches, even when the phone rings in between. --- generic/tclIO.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index cf875a8..7888352 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -427,13 +427,9 @@ TclFinalizeIOSubsystem(void) if (active) { /* - * Set the channel back into blocking mode to ensure that we wait - * for all data to flush out. + * TIP #398: we no longer set the channel back into blocking mode */ - (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, - "-blocking", "on"); - if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || (chanPtr == (Channel *) tsdPtr->stdoutChannel) || (chanPtr == (Channel *) tsdPtr->stderrChannel)) { -- cgit v0.12 From 39e076480d96baa096f628753c88b68eb9d7f601 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Sat, 28 Apr 2012 17:03:10 +0000 Subject: Compat flag, test, and doc update. --- doc/close.n | 6 ++++-- generic/tclIO.c | 32 +++++++++++++++++++++++++++++--- tests/io.test | 21 ++++++++++++++++++++- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/doc/close.n b/doc/close.n index 4490f6a..2826d82 100644 --- a/doc/close.n +++ b/doc/close.n @@ -48,8 +48,10 @@ When the last interpreter in which the channel is registered invokes \fBinterp\fR command for a description of channel sharing. .PP Channels are automatically closed when an interpreter is destroyed and -when the process exits. Channels are switched to blocking mode, to ensure -that all output is correctly flushed before the process exits. +when the process exits. +.VS 8.6 +From 8.6 on (TIP#398), nonblocking channels are no longer switched to blocking mode when exiting; this guarantees a timely exit even when the peer or a communication channel is stalled. To ensure proper flushing of stalled nonblocking channels on exit, one must now either (a) actively switch them back to blocking or (b) use the environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT, which when set and not equal to "0" restores the previous behavior. +.VE 8.6 .PP The command returns an empty string, and may generate an error if an error occurs while flushing output. If a command in a command diff --git a/generic/tclIO.c b/generic/tclIO.c index e1e1193..527ae0c 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,8 +427,8 @@ TclFinalizeIOSubsystem(void) statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; - if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | - CHANNEL_DEAD)) { + if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | CHANNEL_DEAD) + || (doflushnb && GotFlag(statePtr, BG_FLUSH_SCHEDULED))) { active = 1; break; } @@ -426,9 +439,21 @@ TclFinalizeIOSubsystem(void) */ if (active) { + /* - * TIP #398: we no longer set the channel back into blocking mode + * 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". */ + 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) || @@ -454,6 +479,7 @@ TclFinalizeIOSubsystem(void) * The refcount is greater than zero, so flush the channel. */ + ResetFlag(statePtr, BG_FLUSH_SCHEDULED); Tcl_Flush((Tcl_Channel) chanPtr); /* diff --git a/tests/io.test b/tests/io.test index 53b85fa..74a246c 100644 --- a/tests/io.test +++ b/tests/io.test @@ -2736,6 +2736,25 @@ test io-29.33 {Tcl_Flush, implicit flush on exit} {exec} { close $f set r } "hello\nbye\nstrange\n" +set path(script2) [makeFile {} script2] +test io-29.33b {TIP#398, no implicit flush of nonblocking on exit} {exec} { + set f [open $path(script) w] + puts $f { + fconfigure stdout -blocking 0 + puts -nonewline stdout [string repeat A 655360] + flush stdout + } + close $f + set f [open $path(script2) w] + puts $f {after 2000} + close $f + set t1 [clock seconds] + set ff [open "|[list [interpreter] $path(script2)]" w] + exec [interpreter] $path(script) >@ $ff + set t2 [clock seconds] + close $ff + expr {($t2-$t1)/2} +} 0 test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMac fileevent} { variable c 0 variable x running @@ -7761,7 +7780,7 @@ test io-73.2 {channel Tcl_Obj SetChannelFromAny, bug 2407783} -setup { # ### ### ### ######### ######### ######### # cleanup -foreach file [list fooBar longfile script output test1 pipe my_script \ +foreach file [list fooBar longfile script script2 output test1 pipe my_script \ test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] { removeFile $file } -- cgit v0.12