diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | generic/tclIO.c | 38 | ||||
-rw-r--r-- | tests/chanio.test | 47 | ||||
-rw-r--r-- | tests/io.test | 47 |
4 files changed, 123 insertions, 16 deletions
@@ -1,3 +1,10 @@ +2008-04-03 Andreas Kupries <andreask@activestate.com> + + * generic/tclIO.c (CopyData): Applied patch [Bug 1932639] to + * tests/io.test: prevent fcopy from calling -command synchronously + * tests/chanio.test: the first time. Thanks to Alexandre Ferrieux + <ferrieux@users.sourceforge.net> for report and patch. + 2008-04-02 Daniel Steffen <das@users.sourceforge.net> * generic/tcl.decls: remove 'export' declarations of symbols now diff --git a/generic/tclIO.c b/generic/tclIO.c index c153e0f..b44c1e6 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.138 2008/04/02 20:26:09 andreas_kupries Exp $ + * RCS: @(#) $Id: tclIO.c,v 1.139 2008/04/03 18:06:01 andreas_kupries Exp $ */ #include "tclInt.h" @@ -8578,23 +8578,33 @@ CopyData( goto writeError; } - /* - * Read up to bufSize bytes. - */ + if (cmdPtr && (mask == 0)) { + /* + * In async mode, we skip reading synchronously and fake an + * underflow instead to prime the readable fileevent. + */ - if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) { - sizeb = csPtr->bufSize; + size = 0; + underflow = 1; } else { - sizeb = csPtr->toRead; - } + /* + * Read up to bufSize bytes. + */ - if (inBinary || sameEncoding) { - size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); - } else { - size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, - 0 /* No append */); + if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) { + sizeb = csPtr->bufSize; + } else { + sizeb = csPtr->toRead; + } + + if (inBinary || sameEncoding) { + size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); + } else { + size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, + 0 /* No append */); + } + underflow = (size >= 0) && (size < sizeb); /* Input underflow */ } - underflow = (size >= 0) && (size < sizeb); /* Input underflow */ if (size < 0) { readError: diff --git a/tests/chanio.test b/tests/chanio.test index 3c56758..4b492d1 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -13,7 +13,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: chanio.test,v 1.3 2007/12/13 15:26:04 dgp Exp $ +# RCS: @(#) $Id: chanio.test,v 1.4 2008/04/03 18:06:02 andreas_kupries Exp $ if {[catch {package require tcltest 2}]} { chan puts stderr "Skipping tests in [info script]. tcltest 2 required." @@ -6887,6 +6887,51 @@ test chan-io-53.7 {CopyData: Flooding chan copy from pipe} {stdio openpipe fcopy # -1=error 0=script error N=number of bytes expr ($fcopyTestDone == 0) ? $fcopyTestCount : -1 } {3450} +test chan-io-53.8 {CopyData: async callback and error handling, Bug 1932639} -setup { + # copy progress callback. errors out intentionally + proc ::cmd args { + lappend ::RES "CMD $args" + error !STOP + } + # capture callback error here + proc ::bgerror args { + lappend ::RES "bgerror/OK $args" + set ::forever has-been-reached + return + } + # Files we use for our channels + set foo [makeFile ashgdfashdgfasdhgfasdhgf foo] + set bar [makeFile {} bar] + # Channels to copy between + set f [open $foo r] ; fconfigure $f -translation binary + set g [open $bar w] ; fconfigure $g -translation binary -buffering none +} -constraints {stdio openpipe fcopy} -body { + # Record input size, so that result is always defined + lappend ::RES [file size $bar] + # Run the copy. Should not invoke -command now. + chan copy $f $g -size 2 -command ::cmd + # Check that -command was not called synchronously + set sbs [file size bar] + lappend ::RES [expr {($sbs > 0) ? "sync/FAIL" : "sync/OK"}] $sbs + # Now let the async part happen. Should capture the error in cmd + # via bgerror. If not break the event loop via timer. + after 1000 { + lappend ::RES {bgerror/FAIL timeout} + set ::forever has-been-reached + } + vwait ::forever + # Report + set ::RES +} -cleanup { + chan close $f + chan close $g + catch {unset ::RES} + catch {unset ::forever} + rename ::cmd {} + rename ::bgerror {} + removeFile foo + removeFile bar +} -result {0 sync/OK 0 {CMD 2} {bgerror/OK !STOP}} test chan-io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive diff --git a/tests/io.test b/tests/io.test index 3ca2239..6c092cb 100644 --- a/tests/io.test +++ b/tests/io.test @@ -13,7 +13,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: io.test,v 1.80 2007/12/13 15:26:06 dgp Exp $ +# RCS: @(#) $Id: io.test,v 1.81 2008/04/03 18:06:01 andreas_kupries Exp $ if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests in [info script]. tcltest 2 required." @@ -6887,6 +6887,51 @@ test io-53.7 {CopyData: Flooding fcopy from pipe} {stdio openpipe fcopy} { # -1=error 0=script error N=number of bytes expr ($fcopyTestDone == 0) ? $fcopyTestCount : -1 } {3450} +test io-53.8 {CopyData: async callback and error handling, Bug 1932639} -setup { + # copy progress callback. errors out intentionally + proc ::cmd args { + lappend ::RES "CMD $args" + error !STOP + } + # capture callback error here + proc ::bgerror args { + lappend ::RES "bgerror/OK $args" + set ::forever has-been-reached + return + } + # Files we use for our channels + set foo [makeFile ashgdfashdgfasdhgfasdhgf foo] + set bar [makeFile {} bar] + # Channels to copy between + set f [open $foo r] ; fconfigure $f -translation binary + set g [open $bar w] ; fconfigure $g -translation binary -buffering none +} -constraints {stdio openpipe fcopy} -body { + # Record input size, so that result is always defined + lappend ::RES [file size $bar] + # Run the copy. Should not invoke -command now. + fcopy $f $g -size 2 -command ::cmd + # Check that -command was not called synchronously + set sbs [file size bar] + lappend ::RES [expr {($sbs > 0) ? "sync/FAIL" : "sync/OK"}] $sbs + # Now let the async part happen. Should capture the error in cmd + # via bgerror. If not break the event loop via timer. + after 1000 { + lappend ::RES {bgerror/FAIL timeout} + set ::forever has-been-reached + } + vwait ::forever + # Report + set ::RES +} -cleanup { + close $f + close $g + catch {unset ::RES} + catch {unset ::forever} + rename ::cmd {} + rename ::bgerror {} + removeFile foo + removeFile bar +} -result {0 sync/OK 0 {CMD 2} {bgerror/OK !STOP}} test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive |