| Ticket UUID: | d48728e10b820296e45fa73202e135f90952cb46 | ||
| Title: | Blocking [gets] on a [chan push] transformed channel waits for 4096 bytes or EOF | ||
| Type: | Bug | Created on: | 2026-10-17 10:51:11 |
| Submitter: | serhiy.storchaka | Assigned to: | |
| Subsystem: | 26. Channel Transforms | Severity: | Important |
| Priority: | 5 Medium | Last modified: | 2026-10-20 18:11:28 |
| Status: | Open | Closed by: | |
| Resolution: | None | Closed on: | |
| Version: | 8.6.18, 9.0.5, 9.1.0 | ||
| Description: | ||||
|
A blocking [gets] (or [read $ch $n]) on a channel with a reflected transform ([chan push]) does not return while complete lines are available. It waits until the transform has filled the whole 4096-byte input buffer or the other side closes the channel. Without the transform the same [gets] returns at once. Repro with a pipe (a socket behaves the same):
proc xform {cmd handle args} {
switch -- $cmd {
initialize {return {initialize finalize read write}}
finalize {}
read - write {return [lindex $args 0]}
}
}
# child writes three lines and keeps its stdout open for 3 seconds
set f [open [list | [info nameofexecutable] << {
puts -nonewline "one\ntwo\nthree\n"; flush stdout; after 3000
}] r]
chan push $f xform
after 500
set t0 [clock milliseconds]
set line [gets $f]
puts "gets -> $line after [expr {[clock milliseconds]-$t0}] ms"
Actual: gets -> one after 2500 ms (returns only when the child exits). Expected: gets -> one after 0 ms, as without the [chan push]. Cause: ReflectInput() in generic/tclIORTrans.c loops "until the request is satisfied" and calls Tcl_ReadRaw() on the parent channel again after it already has data. In blocking mode that second read blocks. Only the non-blocking case returns a short read (when Tcl_InputBlocked() reports it). A plain channel driver returns what one read gives, so ReflectInput() could stop reading from the parent once it has some data. The loop dates from the TIP #230 implementation [057ba9eab5]. Reproduced with 8.6.0 through 8.6.18, 9.0.5 and main (Linux, pipes and sockets). | ||||
| User Comments: | ||||
serhiy.storchaka added on 2026-10-17 11:39:03:
Proposed fix in branch transform-short-read: ReflectInput() returns a short read once it has data, as other channel drivers do; [gets] and [read] ask again if they need more. Test iortrans-bug-d48728e10b. | ||||
