Posted to tcl by sebres at Wed Dec 05 16:47:49 GMT 2018view pretty
## ================================================================================ ## 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.