Posted to tcl by sebres at Wed Dec 05 16:47:49 GMT 2018view raw
- ## ================================================================================
- ## Following code shows the unexpected behavior: no EOF on pipe of the child process,
- ## if still one child started from.
- ## PoC:
- ## Initial process starts a child process asynchronously and waits for end of file,
- ## the result of the script execution depends on first parameter (WITH_DELAY_SUBPROC):
- ## 0. This child is alone and does not start another child, then EOF is signaled
- ## in the main process.
- ## 1. This child started still one process, then NO EOF signaled
- ## in the main process (one see a timeout after 2 seconds).
- ##
- ## Reproducible for unix/windows for all tcl-versions > 8.5
- ##
- ## Conclusion:
- ## The handle to pipe seems to be inherited from sub-child.
- ## ================================================================================
- lassign $::argv WITH_DELAY_SUBPROC WITH_TIMEOUT WITH_TICKS
- if {$WITH_DELAY_SUBPROC eq ""} {set WITH_DELAY_SUBPROC 1}
- if {$WITH_TIMEOUT eq ""} {set WITH_TIMEOUT 1}
- if {$WITH_TICKS eq ""} {set WITH_TICKS 0}
- # Scripts:
- set script [file join [if [info exists env(TEMP)] {set env(TEMP)} {set _ /tmp}] test-script-sock-12.2.tcl]
- set script1 [file root $script]--2.tcl
- if {$WITH_DELAY_SUBPROC} {
- set f [open $script1 w]
- puts $f {
- after 5000 exit
- vwait forever
- }
- close $f
- }
- set f [open $script w]
- puts $f {puts "testing start"}
- if {$WITH_DELAY_SUBPROC} {
- puts $f {puts " sub-process ..."}
- puts $f [list exec [info nameofexecutable] $script1 &]
- }
- puts $f {
- puts "testing end, exit"
- exit
- }
- close $f
- # Logger:
- variable start [clock milliseconds]
- proc log {s} {
- variable start
- puts "+[format %04d [expr {[clock milliseconds] - $start}]] $s"
- }
- # Readable event from script, "waiting" for EOF (pipe closed):
- proc readfromscript {p} {
- # wait for end of p:
- variable done
- log "=== read, done:$done, gets:[gets $p], eof:[eof $p] ==="
- if {![eof $p]} return
- fileevent $p readable {}
- # Pipe closed - process exited, give few time (0.1s) to fulfill the end.
- variable x
- set x "process ended"
- log "======== EOF -> AFTER ======="
- after 100 [list set done 1]
- #close $p
- }
- set done 0
- log start
- set p [open "|[list [info nameofexecutable] $script]" w+]
- fconfigure $p -buffering none -blocking 0
- fileevent $p readable [list readfromscript $p]
- set x none
- if {$WITH_TIMEOUT} {
- set tmr [after 2000 {set x timeout; set done -1}]
- }
- if {$WITH_TICKS} {
- proc ticker {} {
- variable done
- variable p
- log "... tick: done:$done, eof:[eof $p]"
- after 50 ticker
- }
- ticker
- }
- vwait done
- log "done:$done, x:$x"
- if {$WITH_TIMEOUT} {
- after cancel $tmr
- }
- catch {close $p}
- log end.
- file delete $script
- file delete $script1
- return
- ## Results:
- ## without sub-process (works as expected):
- $ tclsh ~/test.tcl 0
- +0000 start
- +0002 === read, done:0, gets:testing start, eof:0 ===
- +0002 === read, done:0, gets:testing end, exit, eof:0 ===
- +0002 === read, done:0, gets:, eof:1 ===
- +0002 ======== EOF -> AFTER =======
- +0102 done:1, x:process ended
- +0102 end.
- ## with sub-process (no EOF on first process, the handle to pipe seems to be inherited from sub-child):
- $ tclsh ~/test.tcl 1
- +0000 start
- +0002 === read, done:0, gets:testing start, eof:0 ===
- +0002 === read, done:0, gets: sub-process ..., eof:0 ===
- +0002 === read, done:0, gets:testing end, exit, eof:0 ===
- +2000 done:-1, x:timeout
- +2000 end.
Comments
Posted by sebres at Wed Dec 05 17:06:24 GMT 2018 [text] [code]
if timeout disabled (WITH_TIMEOUT = 0), it will also signal EOF on pipe in main-process, but firstly when the child sub-process ends (so after 5 seconds): $ tclsh ~/test.tcl 1 0 +0000 start +0002 === read, done:0, gets:testing start, eof:0 === +0002 === read, done:0, gets: sub-process ..., eof:0 === +0002 === read, done:0, gets:testing end, exit, eof:0 === +5005 === read, done:0, gets:, eof:1 === +5005 ======== EOF -> AFTER ======= +5105 done:1, x:process ended +5105 end.