summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--generic/tclIO.c38
-rw-r--r--tests/chanio.test47
-rw-r--r--tests/io.test47
4 files changed, 123 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index f78f29c..5d06fc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 Andreas Kupries <andreask@activestate.com>
* generic/tclIO.c (CopyData): Applied patch for the fcopy problem
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 8222681..eadd56b 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.137.2.1 2008/04/02 20:27:08 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.137.2.2 2008/04/03 18:06:24 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..c2a6940 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.3.2.1 2008/04/03 18:06:26 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..86ccddc 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.80.2.1 2008/04/03 18:06:25 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