From ec3c0c79fbcedda8d038124c3f482e675225e343 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 cababb3290c4faac824be017a821650a819eb3f1 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 1cc03c884b3940c3fa29e8c52ae61c3d019d08fd 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 ed005a749a40a08ef033442e857b3c626f805c47 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 57e43137bdb2bda8f829c945bf12312b0555f1e6 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