/Tests/FindPython/Python2Module/

approach in DoReadChars()). This involves removing some other calls that are now replaced by the new one. Also marked several UpdateInterest() calls throughout tclIO.c with comments raising the suspicion that they serve no function. --- generic/tclIO.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 564df27..9a4735f 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -5317,6 +5317,7 @@ DoReadChars( assert( statePtr->inputEncodingFlags & TCL_ENCODING_END ); assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) ); + /* TODO: We don't need this call? */ UpdateInterest(chanPtr); return 0; } @@ -5328,6 +5329,7 @@ DoReadChars( } ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; + /* TODO: We don't need this call? */ UpdateInterest(chanPtr); return 0; } @@ -7910,6 +7912,11 @@ Tcl_NotifyChannel( */ if (chanPtr->typePtr != NULL) { + /* + * TODO: This call may not be needed. If a handler induced a + * change in interest, that handler should have made its own + * UpdateInterest() call, one would think. + */ UpdateInterest(chanPtr); } @@ -9032,6 +9039,7 @@ DoRead( assert( statePtr->inputEncodingFlags & TCL_ENCODING_END ); assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) ); + /* TODO: Don't need this call */ UpdateInterest(chanPtr); return 0; } @@ -9043,6 +9051,7 @@ DoRead( } ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; + /* TODO: Don't need this call */ UpdateInterest(chanPtr); return 0; } @@ -9109,7 +9118,6 @@ DoRead( */ if (bytesToRead == 0) { - UpdateInterest(chanPtr); break; } @@ -9118,7 +9126,6 @@ DoRead( */ if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) { - UpdateInterest(chanPtr); break; } @@ -9143,7 +9150,6 @@ DoRead( } else if (GotFlag(statePtr, CHANNEL_BLOCKED)) { /* ...and we cannot get more now. */ SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); - UpdateInterest(chanPtr); break; } else { /* ... so we need to get some. */ @@ -9195,6 +9201,7 @@ DoRead( || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0); assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED) == (CHANNEL_EOF|CHANNEL_BLOCKED)) ); + UpdateInterest(chanPtr); TclChannelRelease((Tcl_Channel)chanPtr); return (int)(p - dst); } -- cgit v0.12 From 2c66fc643c1e662526ad4cd59b0b1836b171a35c Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 12 Aug 2015 16:37:28 +0000 Subject: New test io-53.18 adapted from demo script in [32ae34e63a]. This test segfaults without changes to source code. This checkin also contains a revised implementationf of [chan postevent] that stops calling Tcl_NotifyChannel() directly, and queues an event to do it instead. This stops the segfault, but causes tests iocmd-31.[67] to fail. Need advice on whether that matters. --- generic/tclIORChan.c | 26 +++++++++++++++++++++- tests/io.test | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index bbb5b88..6592f9e 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -741,6 +741,24 @@ TclChanCreateObjCmd( *---------------------------------------------------------------------- */ +typedef struct PostEvent { + Tcl_Event event; /* Basic event data, has to be first item */ + Tcl_Channel chan; + int events; +} PostEvent; + +static int +CallNotify( + Tcl_Event *evPtr, + int flags) +{ + PostEvent *pevPtr = (PostEvent *)evPtr; + + Tcl_NotifyChannel(pevPtr->chan, pevPtr->events); + TclChannelRelease(pevPtr->chan); + return 1; +} + int TclChanPostEventObjCmd( ClientData clientData, @@ -769,6 +787,7 @@ TclChanPostEventObjCmd( int events; /* Mask of events to post */ ReflectedChannelMap* rcmPtr; /* Map of reflected channels with handlers in this interp */ Tcl_HashEntry* hPtr; /* Entry in the above map */ + PostEvent *pevPtr; /* * Number of arguments... @@ -857,7 +876,12 @@ TclChanPostEventObjCmd( * We have the channel and the events to post. */ - Tcl_NotifyChannel(chan, events); + pevPtr = (PostEvent *)ckalloc(sizeof(PostEvent)); + pevPtr->event.proc = CallNotify; + pevPtr->chan = chan; + pevPtr->events = events; + TclChannelPreserve(chan); + Tcl_QueueEvent((Tcl_Event *)pevPtr, TCL_QUEUE_HEAD); /* * Squash interp results left by the event script. diff --git a/tests/io.test b/tests/io.test index 50c5808..46e3f05 100644 --- a/tests/io.test +++ b/tests/io.test @@ -7886,6 +7886,68 @@ test io-53.15 {[ed29c4da21] DoRead: fblocked seen as error} -setup { removeFile out } -result 100 +test io-53.18 {[32ae34e63a] recursize CopyData} -setup { + proc driver {cmd args} { + variable buffer + variable index + set chan [lindex $args 0] + switch -- $cmd { + initialize { + set index($chan) 0 + set buffer($chan) [encoding convertto utf-8 \ + [string repeat a 100]] + return {initialize finalize watch read} + } + finalize { + unset index($chan) buffer($chan) + return + } + watch { + if {"read" in [lindex $args 1]} { + chan postevent $chan read + } + return + } + read { + set n [lindex $args 1] + set new [expr {$index($chan) + $n}] + set result [string range $buffer($chan) $index($chan) $new-1] + set index($chan) $new + return $result + } + } + } + proc more {c outChan bytes args} { + if {[eof $c]} { + set ::done eof + catch {close $c} + return + } + if {[llength $args]} { + set ::done error + } else { + chan copy $c $outChan -command [list [namespace which more] $c $outChan] + } + } + set c [chan create read [namespace which driver]] + chan configure $c -encoding utf-8 + set out [makeFile {} out] + set outChan [open $out w] + # Different encoding to force use of DoReadChars() + chan configure $outChan -encoding iso8859-1 +} -body { + after 2000 {set ::done timeout} + chan copy $c $outChan -size 99 -command [list [namespace which more] $c $outChan] + vwait ::done + set ::done +} -cleanup { + close $outChan + removeFile out + rename driver {} + rename more {} + unset ::done +} -result eof + test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. -- cgit v0.12 From 1db16b915a2fc6e315586502121d1ab7c9b39a59 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 12 Aug 2015 17:49:42 +0000 Subject: Adjustments to failing tests to account for changed [chan postevent]. --- tests/ioCmd.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ioCmd.test b/tests/ioCmd.test index 5a76d48..c706e50 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -1949,26 +1949,26 @@ test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body { set c [chan create {r w} foo] note [fileevent $c readable {note TOCK}] set stop [after 10000 {note TIMEOUT}] - after 1000 {note [chan postevent $c r]} + after 1000 {chan postevent $c r} vwait ::res catch {after cancel $stop} close $c rename foo {} set res -} -result {{watch rc* read} {} TOCK {} {watch rc* {}}} +} -result {{watch rc* read} {} TOCK {watch rc* {}}} test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body { set res {} proc foo {args} {oninit; onfinal; track; return} set c [chan create {r w} foo] note [fileevent $c writable {note TOCK}] set stop [after 10000 {note TIMEOUT}] - after 1000 {note [chan postevent $c w]} + after 1000 {chan postevent $c w} vwait ::res catch {after cancel $stop} close $c rename foo {} set res -} -result {{watch rc* write} {} TOCK {} {watch rc* {}}} +} -result {{watch rc* write} {} TOCK {watch rc* {}}} test iocmd-31.8 {chan postevent after close throws error} -match glob -setup { proc foo {args} {oninit; onfinal; track; return} proc dummy args { return } -- cgit v0.12 From 13850d4952b34d30e3e2ae68c3cb2c10c0019737 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Aug 2015 16:45:03 +0000 Subject: A bit of code safety, and then a test demonstrating next issue. --- generic/tclIORChan.c | 5 +++- tests/io.test | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 6592f9e..85a35b8 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -753,8 +753,11 @@ CallNotify( int flags) { PostEvent *pevPtr = (PostEvent *)evPtr; + Channel *chanPtr = (Channel *)pevPtr->chan; - Tcl_NotifyChannel(pevPtr->chan, pevPtr->events); + if (chanPtr->typePtr != NULL) { + Tcl_NotifyChannel(pevPtr->chan, pevPtr->events); + } TclChannelRelease(pevPtr->chan); return 1; } diff --git a/tests/io.test b/tests/io.test index 46e3f05..840274d 100644 --- a/tests/io.test +++ b/tests/io.test @@ -7936,7 +7936,7 @@ test io-53.18 {[32ae34e63a] recursize CopyData} -setup { # Different encoding to force use of DoReadChars() chan configure $outChan -encoding iso8859-1 } -body { - after 2000 {set ::done timeout} + after 100 {set ::done timeout} chan copy $c $outChan -size 99 -command [list [namespace which more] $c $outChan] vwait ::done set ::done @@ -7948,6 +7948,68 @@ test io-53.18 {[32ae34e63a] recursize CopyData} -setup { unset ::done } -result eof +test io-53.19 {[e0a7b3e5f8] DoRead calls to UpdateInterest} -setup { + proc driver {cmd args} { + variable buffer + variable index + set chan [lindex $args 0] + switch -- $cmd { + initialize { + set index($chan) 0 + set buffer($chan) [encoding convertto utf-8 \ + [string repeat a 100]] + return {initialize finalize watch read} + } + finalize { + unset index($chan) buffer($chan) + return + } + watch { + if {"read" in [lindex $args 1]} { + chan postevent $chan read + } + return + } + read { + set n [lindex $args 1] + set new [expr {$index($chan) + $n}] + set result [string range $buffer($chan) $index($chan) $new-1] + set index($chan) $new + return $result + } + } + } + proc more {c outChan bytes args} { + if {[eof $c]} { + set ::done eof + catch {close $c} + return + } + if {[llength $args]} { + set ::done error + } else { + chan copy $c $outChan -size 30 -command [list [namespace which more] $c $outChan] + } + } + set c [chan create read [namespace which driver]] + chan configure $c -encoding utf-8 -buffersize 20 + set out [makeFile {} out] + set outChan [open $out w] + # Different encoding to force use of DoReadChar() + chan configure $outChan -encoding iso8859-1 +} -body { + after 100 {set ::done timeout} + chan copy $c $outChan -size 30 -command [list [namespace which more] $c $outChan] + vwait ::done + set ::done +} -cleanup { + catch {close $outChan} + removeFile out + rename driver {} + rename more {} + unset ::done +} -result eof + test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. -- cgit v0.12 From bf4a5c995fc82d4d7841bdf0970e027623904529 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Aug 2015 17:02:04 +0000 Subject: Disable the filtering of ReflectWatch so that every UpdateInterest() call flows through to become a [driver watch] evaluation. This makes new test io-53.19 pass. It also makes a collection of 10 test in ioCmd.test start failing, all of which are recording detailed reflected channel driver command evaluation. The now unfiltered [driver watch] change this record without (at least apparently) changing any behavior. Need review. --- generic/tclIORChan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 85a35b8..b059c79 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -1535,7 +1535,7 @@ ReflectWatch( mask &= rcPtr->mode; - if (mask == rcPtr->interest) { + if (0 && mask == rcPtr->interest) { /* * Same old, same old, why should we do something? */ -- cgit v0.12 From 65644eeb87cb55253126bba237afb569d3fe6f4a Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 13 Aug 2015 19:28:26 +0000 Subject: New test attempting to demo Bug [e0a7b3e5f8]. Doesn't work yet. --- tests/io.test | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/tests/io.test b/tests/io.test index 840274d..914cbca 100644 --- a/tests/io.test +++ b/tests/io.test @@ -7886,7 +7886,7 @@ test io-53.15 {[ed29c4da21] DoRead: fblocked seen as error} -setup { removeFile out } -result 100 -test io-53.18 {[32ae34e63a] recursize CopyData} -setup { +test io-53.18 {[32ae34e63a] recursive CopyData} -setup { proc driver {cmd args} { variable buffer variable index @@ -7948,7 +7948,7 @@ test io-53.18 {[32ae34e63a] recursize CopyData} -setup { unset ::done } -result eof -test io-53.19 {[e0a7b3e5f8] DoRead calls to UpdateInterest} -setup { +test io-53.19 {[32ae34e63a] stop ReflectWatch filtering} -setup { proc driver {cmd args} { variable buffer variable index @@ -7995,7 +7995,7 @@ test io-53.19 {[e0a7b3e5f8] DoRead calls to UpdateInterest} -setup { chan configure $c -encoding utf-8 -buffersize 20 set out [makeFile {} out] set outChan [open $out w] - # Different encoding to force use of DoReadChar() + # Different encoding to force use of DoReadChars() chan configure $outChan -encoding iso8859-1 } -body { after 100 {set ::done timeout} @@ -8010,6 +8010,68 @@ test io-53.19 {[e0a7b3e5f8] DoRead calls to UpdateInterest} -setup { unset ::done } -result eof +test io-53.20 {[e0a7b3e5f8] DoRead calls to UpdateInterest} -setup { + proc driver {cmd args} { + variable buffer + variable index + set chan [lindex $args 0] + switch -- $cmd { + initialize { + set index($chan) 0 + set buffer($chan) [encoding convertto utf-8 \ + [string repeat a 100]] + return {initialize finalize watch read} + } + finalize { + unset index($chan) buffer($chan) + return + } + watch { + if {"read" in [lindex $args 1]} { + chan postevent $chan read + } + return + } + read { + set n [lindex $args 1] + set new [expr {$index($chan) + $n}] + set result [string range $buffer($chan) $index($chan) $new-1] + set index($chan) $new + return $result + } + } + } + proc more {c outChan bytes args} { + if {[eof $c]} { + set ::done eof + catch {close $c} + return + } + if {[llength $args]} { + set ::done error + } else { + chan copy $c $outChan -size 10 -command [list [namespace which more] $c $outChan] + } + } + set c [chan create read [namespace which driver]] + chan configure $c -encoding utf-8 -buffersize 20 + set out [makeFile {} out] + set outChan [open $out w] + # Same encoding to force use of DoRead() + chan configure $outChan -encoding utf-8 +} -body { + after 100 {set ::done timeout} + chan copy $c $outChan -size 10 -command [list [namespace which more] $c $outChan] + vwait ::done + set ::done +} -cleanup { + catch {close $outChan} + removeFile out + rename driver {} + rename more {} + unset ::done +} -result eof + test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. -- cgit v0.12 From 58cebf8eebe511c29bb83d3d64ee229d2e72b594 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 09:40:46 +0000 Subject: WIP --- generic/tclIO.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 564df27..d4db7ec 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -113,11 +113,32 @@ typedef struct CopyState { Tcl_WideInt total; /* Total bytes transferred (written). */ Tcl_Interp *interp; /* Interp that started the copy. */ Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ + int refCount; /* Claim count on the struct */ int bufSize; /* Size of appended buffer. */ char buffer[1]; /* Copy buffer, this must be the last * field. */ } CopyState; +static void +PreserveCopyState( + CopyState *csPtr) +{ + csPtr->refCount++; +fprintf(stdout, "PRESERVE -> %d %p\n", csPtr->refCount, csPtr); fflush(stdout); +} + +static void +ReleaseCopyState( + CopyState *csPtr) +{ +fprintf(stdout, "%d -> RELEASE %p\n", csPtr->refCount, csPtr); fflush(stdout); + if (--csPtr->refCount) { + return; + } +fprintf(stdout, "FREE %p\n", csPtr); fflush(stdout); + ckfree((char *) csPtr); +} + /* * All static variables used in this file are collected into a single instance * of the following structure. For multi-threaded implementations, there is @@ -8642,9 +8663,12 @@ TclCopyChannel( Tcl_IncrRefCount(cmdPtr); } csPtr->cmdPtr = cmdPtr; + csPtr->refCount = 1; inStatePtr->csPtrR = csPtr; + PreserveCopyState(csPtr); outStatePtr->csPtrW = csPtr; + PreserveCopyState(csPtr); /* * Special handling of -size 0 async transfers, so that the -command is @@ -8696,6 +8720,9 @@ CopyData( /* Encoding control */ int underflow; /* Input underflow */ +fprintf(stdout, "CD: %p\n", csPtr); fflush(stdout); + PreserveCopyState(csPtr); + inChan = (Tcl_Channel) csPtr->readPtr; outChan = (Tcl_Channel) csPtr->writePtr; inStatePtr = csPtr->readPtr->state; @@ -8807,6 +8834,8 @@ CopyData( TclDecrRefCount(bufObj); bufObj = NULL; } +fprintf(stdout, "ECD 1: %p\n", csPtr); fflush(stdout); + ReleaseCopyState(csPtr); return TCL_OK; } } @@ -8898,6 +8927,8 @@ CopyData( TclDecrRefCount(bufObj); bufObj = NULL; } +fprintf(stdout, "ECD 2: %p\n", csPtr); fflush(stdout); + ReleaseCopyState(csPtr); return TCL_OK; } @@ -8920,6 +8951,8 @@ CopyData( TclDecrRefCount(bufObj); bufObj = NULL; } +fprintf(stdout, "ECD 3: %p\n", csPtr); fflush(stdout); + ReleaseCopyState(csPtr); return TCL_OK; } } /* while */ @@ -8971,6 +9004,8 @@ CopyData( } } } +fprintf(stdout, "ECD 4: %p\n", csPtr); fflush(stdout); + ReleaseCopyState(csPtr); return result; } @@ -9253,6 +9288,7 @@ StopCopy( return; } +fprintf(stdout, "SC: %p\n", csPtr); fflush(stdout); inStatePtr = csPtr->readPtr->state; outStatePtr = csPtr->writePtr->state; @@ -9285,9 +9321,17 @@ StopCopy( } TclDecrRefCount(csPtr->cmdPtr); } - inStatePtr->csPtrR = NULL; - outStatePtr->csPtrW = NULL; - ckfree((char *) csPtr); + if (inStatePtr->csPtrR) { + ReleaseCopyState(inStatePtr->csPtrR); + inStatePtr->csPtrR = NULL; + } + if (outStatePtr->csPtrW) { + ReleaseCopyState(outStatePtr->csPtrW); + outStatePtr->csPtrW = NULL; + } + ReleaseCopyState(csPtr); +// ckfree((char *) csPtr); +fprintf(stdout, "ESC: %p\n", csPtr); fflush(stdout); } /* -- cgit v0.12 From 55cb367ecb24a49e0fe76b104f6fe709672b066b Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 13:18:32 +0000 Subject: CopyData() now tolerates recursion enough so that io-53.18 does not segfault. --- generic/tclIO.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index d4db7ec..27eee5a 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -124,18 +124,15 @@ PreserveCopyState( CopyState *csPtr) { csPtr->refCount++; -fprintf(stdout, "PRESERVE -> %d %p\n", csPtr->refCount, csPtr); fflush(stdout); } static void ReleaseCopyState( CopyState *csPtr) { -fprintf(stdout, "%d -> RELEASE %p\n", csPtr->refCount, csPtr); fflush(stdout); if (--csPtr->refCount) { return; } -fprintf(stdout, "FREE %p\n", csPtr); fflush(stdout); ckfree((char *) csPtr); } @@ -8720,7 +8717,6 @@ CopyData( /* Encoding control */ int underflow; /* Input underflow */ -fprintf(stdout, "CD: %p\n", csPtr); fflush(stdout); PreserveCopyState(csPtr); inChan = (Tcl_Channel) csPtr->readPtr; @@ -8834,7 +8830,6 @@ fprintf(stdout, "CD: %p\n", csPtr); fflush(stdout); TclDecrRefCount(bufObj); bufObj = NULL; } -fprintf(stdout, "ECD 1: %p\n", csPtr); fflush(stdout); ReleaseCopyState(csPtr); return TCL_OK; } @@ -8927,7 +8922,6 @@ fprintf(stdout, "ECD 1: %p\n", csPtr); fflush(stdout); TclDecrRefCount(bufObj); bufObj = NULL; } -fprintf(stdout, "ECD 2: %p\n", csPtr); fflush(stdout); ReleaseCopyState(csPtr); return TCL_OK; } @@ -8951,7 +8945,6 @@ fprintf(stdout, "ECD 2: %p\n", csPtr); fflush(stdout); TclDecrRefCount(bufObj); bufObj = NULL; } -fprintf(stdout, "ECD 3: %p\n", csPtr); fflush(stdout); ReleaseCopyState(csPtr); return TCL_OK; } @@ -8968,15 +8961,14 @@ fprintf(stdout, "ECD 3: %p\n", csPtr); fflush(stdout); */ total = csPtr->total; - if (cmdPtr && interp) { + if (cmdPtr && interp && csPtr->cmdPtr) { int code; /* * Get a private copy of the command so we can mutate it by adding * arguments. Note that StopCopy frees our saved reference to the * original command obj. */ - - cmdPtr = Tcl_DuplicateObj(cmdPtr); + cmdPtr = Tcl_DuplicateObj(csPtr->cmdPtr); Tcl_IncrRefCount(cmdPtr); StopCopy(csPtr); Tcl_Preserve(interp); @@ -9004,7 +8996,6 @@ fprintf(stdout, "ECD 3: %p\n", csPtr); fflush(stdout); } } } -fprintf(stdout, "ECD 4: %p\n", csPtr); fflush(stdout); ReleaseCopyState(csPtr); return result; } @@ -9288,7 +9279,6 @@ StopCopy( return; } -fprintf(stdout, "SC: %p\n", csPtr); fflush(stdout); inStatePtr = csPtr->readPtr->state; outStatePtr = csPtr->writePtr->state; @@ -9320,18 +9310,16 @@ fprintf(stdout, "SC: %p\n", csPtr); fflush(stdout); CopyEventProc, csPtr); } TclDecrRefCount(csPtr->cmdPtr); + csPtr->cmdPtr = NULL; } - if (inStatePtr->csPtrR) { - ReleaseCopyState(inStatePtr->csPtrR); - inStatePtr->csPtrR = NULL; - } - if (outStatePtr->csPtrW) { - ReleaseCopyState(outStatePtr->csPtrW); - outStatePtr->csPtrW = NULL; + if (inStatePtr->csPtrR == NULL) { + return; } + ReleaseCopyState(inStatePtr->csPtrR); + inStatePtr->csPtrR = NULL; + ReleaseCopyState(outStatePtr->csPtrW); + outStatePtr->csPtrW = NULL; ReleaseCopyState(csPtr); -// ckfree((char *) csPtr); -fprintf(stdout, "ESC: %p\n", csPtr); fflush(stdout); } /* -- cgit v0.12 From 4fb1c76abea23369b4d961e2b20f900dd0294e82 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 16:00:57 +0000 Subject: Protect CopyState buffer from conflicting uses when CopyData() is called recursively. Also, have ReflectWatch() always give driver a chance to act. --- generic/tclIO.c | 7 +++++++ generic/tclIORChan.c | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 27eee5a..09b2537 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -114,6 +114,7 @@ typedef struct CopyState { Tcl_Interp *interp; /* Interp that started the copy. */ Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ int refCount; /* Claim count on the struct */ + int bufInUse; /* Flag to govern access to buffer */ int bufSize; /* Size of appended buffer. */ char buffer[1]; /* Copy buffer, this must be the last * field. */ @@ -8661,6 +8662,7 @@ TclCopyChannel( } csPtr->cmdPtr = cmdPtr; csPtr->refCount = 1; + csPtr->bufInUse = 0; inStatePtr->csPtrR = csPtr; PreserveCopyState(csPtr); @@ -8717,6 +8719,9 @@ CopyData( /* Encoding control */ int underflow; /* Input underflow */ + if (csPtr->bufInUse) { + return TCL_OK; + } PreserveCopyState(csPtr); inChan = (Tcl_Channel) csPtr->readPtr; @@ -8780,6 +8785,7 @@ CopyData( sizeb = csPtr->toRead; } + csPtr->bufInUse = 1; if (inBinary || sameEncoding) { size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); } else { @@ -8851,6 +8857,7 @@ CopyData( } else { sizeb = WriteChars(outStatePtr->topChanPtr, buffer, sizeb); } + csPtr->bufInUse = 0; /* * [Bug 2895565]. At this point 'size' still contains the number of diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index bbb5b88..2e5fa45 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -1508,14 +1508,6 @@ ReflectWatch( mask &= rcPtr->mode; - if (mask == rcPtr->interest) { - /* - * Same old, same old, why should we do something? - */ - - return; - } - rcPtr->interest = mask; /* -- cgit v0.12 From 261ff342b1e18433e104577ad6f8dc7c50f9292a Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 16:08:30 +0000 Subject: Update tests to account for changed ReflectWatch behavior. --- tests/ioCmd.test | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/ioCmd.test b/tests/ioCmd.test index 5a76d48..e2a6d84 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -981,7 +981,7 @@ test iocmd-23.1 {chan read, regular data return} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} {read rc* 4096} snarfsnarf} +} -result {{read rc* 4096} {read rc* 4096} {watch rc* {}} snarfsnarf} test iocmd-23.2 {chan read, bad data return, to much} -match glob -body { set res {} proc foo {args} { @@ -993,7 +993,7 @@ test iocmd-23.2 {chan read, bad data return, to much} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 {read delivered more than requested}} +} -result {{read rc* 4096} {watch rc* {}} 1 {read delivered more than requested}} test iocmd-23.3 {chan read, for non-readable channel} -match glob -body { set res {} proc foo {args} { @@ -1016,7 +1016,7 @@ test iocmd-23.4 {chan read, error return} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 BOOM!} +} -result {{read rc* 4096} {watch rc* {}} 1 BOOM!} test iocmd-23.5 {chan read, break return is error} -match glob -body { set res {} proc foo {args} { @@ -1028,7 +1028,7 @@ test iocmd-23.5 {chan read, break return is error} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} test iocmd-23.6 {chan read, continue return is error} -match glob -body { set res {} proc foo {args} { @@ -1040,7 +1040,7 @@ test iocmd-23.6 {chan read, continue return is error} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} test iocmd-23.7 {chan read, custom return is error} -match glob -body { set res {} proc foo {args} { @@ -1052,7 +1052,7 @@ test iocmd-23.7 {chan read, custom return is error} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} test iocmd-23.8 {chan read, level is squashed} -match glob -body { set res {} proc foo {args} { @@ -1064,7 +1064,7 @@ test iocmd-23.8 {chan read, level is squashed} -match glob -body { close $c rename foo {} set res -} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} test iocmd-23.9 {chan read, no data means eof} -match glob -setup { set res {} proc foo {args} { @@ -1080,7 +1080,7 @@ test iocmd-23.9 {chan read, no data means eof} -match glob -setup { close $c rename foo {} unset res -} -result {{read rc* 4096} {} 1} +} -result {{read rc* 4096} {watch rc* {}} {} 1} test iocmd-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup { set res {} proc foo {args} { @@ -1096,7 +1096,7 @@ test iocmd-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glo close $c rename foo {} unset res -} -result {{read rc* 4096} {} 0} +} -result {{read rc* 4096} {watch rc* {}} {} 0} test iocmd-23.11 {chan read, close pulls the rug out} -match glob -body { set res {} proc foo {args} { @@ -1410,14 +1410,14 @@ test iocmd-25.10 {chan configure, cgetall, level is ignored} -match glob -body { test iocmd-26.1 {chan configure, set standard option} -match glob -body { set res {} proc foo {args} { - oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return + oninit configure; onfinal; track; return } set c [chan create {r w} foo] note [fconfigure $c -translation lf] close $c rename foo {} set res -} -result {{}} +} -result {{watch rc* {}} {}} test iocmd-26.2 {chan configure, set option, error return} -match glob -body { set res {} proc foo {args} { @@ -1955,7 +1955,7 @@ test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body { close $c rename foo {} set res -} -result {{watch rc* read} {} TOCK {} {watch rc* {}}} +} -result {{watch rc* read} {} TOCK {watch rc* read} {} {watch rc* {}}} test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body { set res {} proc foo {args} {oninit; onfinal; track; return} @@ -1968,7 +1968,7 @@ test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body { close $c rename foo {} set res -} -result {{watch rc* write} {} TOCK {} {watch rc* {}}} +} -result {{watch rc* write} {} TOCK {watch rc* write} {} {watch rc* {}}} test iocmd-31.8 {chan postevent after close throws error} -match glob -setup { proc foo {args} {oninit; onfinal; track; return} proc dummy args { return } -- cgit v0.12 From 2b9f58aaac9d943888960daa1394c1abeae2e374 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 23 Sep 2015 17:29:15 +0000 Subject: Update tests to new ReflectWatch() behavior. --- tests/ioCmd.test | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ioCmd.test b/tests/ioCmd.test index a0caab2..f66480a 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -2300,7 +2300,7 @@ test iocmd.tf-23.1 {chan read, regular data return} -match glob -body { } c] rename foo {} set res -} -constraints {testchannel thread} -result {{read rc* 4096} {read rc* 4096} snarfsnarf} +} -constraints {testchannel thread} -result {{read rc* 4096} {read rc* 4096} {watch rc* {}} snarfsnarf} test iocmd.tf-23.2 {chan read, bad data return, to much} -match glob -body { set res {} proc foo {args} { @@ -2315,7 +2315,7 @@ test iocmd.tf-23.2 {chan read, bad data return, to much} -match glob -body { } c] rename foo {} set res -} -constraints {testchannel thread} -result {{read rc* 4096} 1 {read delivered more than requested}} +} -constraints {testchannel thread} -result {{read rc* 4096} {watch rc* {}} 1 {read delivered more than requested}} test iocmd.tf-23.3 {chan read, for non-readable channel} -match glob -body { set res {} proc foo {args} { @@ -2344,7 +2344,7 @@ test iocmd.tf-23.4 {chan read, error return} -match glob -body { } c] rename foo {} set res -} -result {{read rc* 4096} 1 BOOM!} \ +} -result {{read rc* 4096} {watch rc* {}} 1 BOOM!} \ -constraints {testchannel thread} test iocmd.tf-23.5 {chan read, break return is error} -match glob -body { set res {} @@ -2360,7 +2360,7 @@ test iocmd.tf-23.5 {chan read, break return is error} -match glob -body { } c] rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} \ +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} \ -constraints {testchannel thread} test iocmd.tf-23.6 {chan read, continue return is error} -match glob -body { set res {} @@ -2376,7 +2376,7 @@ test iocmd.tf-23.6 {chan read, continue return is error} -match glob -body { } c] rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} \ +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} \ -constraints {testchannel thread} test iocmd.tf-23.7 {chan read, custom return is error} -match glob -body { set res {} @@ -2392,7 +2392,7 @@ test iocmd.tf-23.7 {chan read, custom return is error} -match glob -body { } c] rename foo {} set res -} -result {{read rc* 4096} 1 *bad code*} \ +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code*} \ -constraints {testchannel thread} test iocmd.tf-23.8 {chan read, level is squashed} -match glob -body { set res {} @@ -2408,7 +2408,7 @@ test iocmd.tf-23.8 {chan read, level is squashed} -match glob -body { } c] rename foo {} set res -} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \ +} -result {{read rc* 4096} {watch rc* {}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \ -constraints {testchannel thread} test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup { set res {} @@ -2428,7 +2428,7 @@ test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup { } -cleanup { rename foo {} unset res -} -result {{read rc* 4096} {} 1} \ +} -result {{read rc* 4096} {watch rc* {}} {} 1} \ -constraints {testchannel thread} test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup { set res {} @@ -2448,7 +2448,7 @@ test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match } -cleanup { rename foo {} unset res -} -result {{read rc* 4096} {} 0} \ +} -result {{read rc* 4096} {watch rc* {}} {} 0} \ -constraints {testchannel thread} # --- === *** ########################### @@ -3001,7 +3001,7 @@ test iocmd.tf-25.10 {chan configure, cgetall, level is ignored} -match glob -bod test iocmd.tf-26.1 {chan configure, set standard option} -match glob -body { set res {} proc foo {args} { - oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return + oninit configure; onfinal; track; return } set c [chan create {r w} foo] notes [inthread $c { @@ -3011,7 +3011,