summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpooryorick <com.digitalsmarties@pooryorick.com>2019-04-27 07:19:49 (GMT)
committerpooryorick <com.digitalsmarties@pooryorick.com>2019-04-27 07:19:49 (GMT)
commit36073e502b5ea157b656d98ea6c86287f5fc855d (patch)
tree77c79ab55f98d4aa4ecf0c0422d5ff9593f7c09b
parent35396a7f5c0759d9cf20079bdf1700d0e55dba78 (diff)
downloadtcl-36073e502b5ea157b656d98ea6c86287f5fc855d.zip
tcl-36073e502b5ea157b656d98ea6c86287f5fc855d.tar.gz
tcl-36073e502b5ea157b656d98ea6c86287f5fc855d.tar.bz2
Fix for de232b49f2, write-only nonblocking refchan and Tcl internal buffers.
-rw-r--r--generic/tclIO.c38
-rw-r--r--tests/io.test63
2 files changed, 96 insertions, 5 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index cf91307..4775820 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -3463,6 +3463,11 @@ Tcl_Close(
Tcl_ClearChannelHandlers(chan);
/*
+ * Cancel any outstanding timer.
+ */
+ Tcl_DeleteTimerHandler(statePtr->timer);
+
+ /*
* Invoke the registered close callbacks and delete their records.
*/
@@ -4447,6 +4452,8 @@ Write(
}
}
+ UpdateInterest(chanPtr);
+
return total;
}
@@ -8475,9 +8482,9 @@ UpdateInterest(
*
* - Tcl drops READABLE here, because it has data in its own
* buffers waiting to be read by the extension.
- * - A READABLE event is syntesized via timer.
+ * - A READABLE event is synthesized via timer.
* - The OS still reports the EXCEPTION condition on the file.
- * - And the extension gets the EXCPTION event first, and handles
+ * - And the extension gets the EXCEPTION event first, and handles
* this as EOF.
*
* End result ==> Premature end of reading from a file.
@@ -8503,6 +8510,16 @@ UpdateInterest(
}
}
}
+
+ if (statePtr->timer == NULL
+ && mask & TCL_WRITABLE
+ && GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
+
+ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
+ ChannelTimerProc,chanPtr);
+ }
+
+
ChanWatch(chanPtr, mask);
}
@@ -8531,6 +8548,19 @@ ChannelTimerProc(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
+ Tcl_Preserve(statePtr);
+ statePtr->timer = NULL;
+ if (statePtr->interestMask & TCL_WRITABLE
+ && GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
+ /*
+ * Restart the timer in case a channel handler reenters the event loop
+ * before UpdateInterest gets called by Tcl_NotifyChannel.
+ */
+ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
+ ChannelTimerProc,chanPtr);
+ Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
+ }
+
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
&& (statePtr->interestMask & TCL_READABLE)
&& (statePtr->inQueueHead != NULL)
@@ -8542,13 +8572,11 @@ ChannelTimerProc(
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
- Tcl_Preserve(statePtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
- Tcl_Release(statePtr);
} else {
- statePtr->timer = NULL;
UpdateInterest(chanPtr);
}
+ Tcl_Release(statePtr);
}
/*
diff --git a/tests/io.test b/tests/io.test
index d42f59e..6470282 100644
--- a/tests/io.test
+++ b/tests/io.test
@@ -5963,6 +5963,69 @@ test io-44.5 {FileEventProc procedure: end of file} {stdio unixExecs openpipe fi
} {initial foo eof}
close $f
+
+test chan-io-44.6 {FileEventProc procedure: write-only non-blocking channel} -setup {
+} -constraints {stdio unixExecs fileevent openpipe} -body {
+
+ namespace eval refchan {
+ namespace ensemble create
+ namespace export *
+
+
+ proc finalize {chan args} {
+ namespace delete c_$chan
+ }
+
+ proc initialize {chan args} {
+ namespace eval c_$chan {}
+ namespace upvar c_$chan watching watching
+ set watching {}
+ list finalize initialize seek watch write
+ }
+
+
+ proc watch {chan args} {
+ namespace upvar c_$chan watching watching
+ foreach arg $args {
+ switch $arg {
+ write {
+ if {$arg ni $watching} {
+ lappend watching $arg
+ }
+ chan postevent $chan $arg
+ }
+ }
+ }
+ }
+
+
+ proc write {chan args} {
+ chan postevent $chan write
+ return 1
+ }
+ }
+ set f [chan create w [namespace which refchan]]
+ chan configure $f -blocking 0
+ set data "some data"
+ set x 0
+ chan event $f writable [namespace code {
+ puts $f $data
+ incr count [string length $data]
+ if {$count > 262144} {
+ chan event $f writable {}
+ set x done
+ }
+ }]
+ after 10000 [namespace code {
+ set x timeout
+ }]
+ vwait [namespace which -variable x]
+ return $x
+} -cleanup {
+ catch {chan close $f}
+} -result done
+
+
makeFile "foo bar" foo
test io-45.1 {DeleteFileEvent, cleanup on close} {fileevent} {