1 # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
4 # output(channel, data) - When output arrives from the child, channel is
5 # one of {stdout, stderr}
6 # reaped(result) - When the child dies and has been reaped. result
7 # is the numeric result from the child.
8 # death_by_signal(childpid, sigal_name, msg)
9 # - When a child is killed by a signal. signame
10 # is something like SIGTERM, msg is something
11 # like "software termination signal"
14 inherit tlc
::Baselog tlc
::Signalsource tlc
::Handlers
27 method waitfor_output
{match
}
34 variable stderr_handle
36 variable output_matches
37 variable output_vwaits
42 method stderr_handler
{subcmd channelId args
}
43 method check_output_vwaits
{}
49 body tlc
::Process::constructor {args
} { #<<<
50 package require
Tcl 8.5
52 array set output_matches
{}
53 array set output_vwaits
{}
56 tlc
::Signal ::#auto signals(running) -name "$this running"
57 tlc
::Signal ::#auto signals(finished) -name "$this finished"
58 tlc
::Domino ::#auto dominos(check_output_vwaits) -name "$this check_output_vwaits"
64 error "Must specify -$reqf"
68 set stderr_handle
[chan create write
[code
$this stderr_handler
]]
70 #set cmdline [list {*}$cmd 2>@ $stderr_handle]
71 #set cmdline [list {*}$cmd >@ $stderr_handle]
72 #set cmdline [list {*}$cmd 2>@ stdout]
73 set cmdline
[list {*}$cmd 2>@1]
74 #set cmdline [list {*}$cmd]
75 #puts $stderr_handle "hello, world"; flush $stderr_handle
76 set handle
[open |
$cmdline r
]
77 chan configure
$handle \
82 set pids
[pid $handle]
83 chan
event $handle readable
[code
$this readable
]
84 $signals(running
) set_state
1
86 $dominos(check_output_vwaits
) attach_output
[code
$this check_output_vwaits
]
90 body tlc
::Process::destructor {} { #<<<
92 $signals(running
) set_state
0
96 if {[info exists handle
]} {
104 if {[info exists stderr_handle
]} {
106 chan
close $stderr_handle
113 if {$::tcl_platform(platform
) == "unix"} {
115 catch {exec kill
-15 $pid}
123 body tlc
::Process::readable {} { #<<<
124 set dat
[read $handle]
126 lappend buf
[list stdout
$dat]
128 if {[chan
eof $handle]} {
130 chan configure
$handle -blocking 1
134 lassign
$::errorCode code childpid res
138 lassign
$::errorCode code childpid sig msg
139 invoke_handlers death_by_signal
$childpid $sig $msg
144 log
error "Child died in an interesting way: $errmsg ($::errorCode)"
153 $dominos(check_output_vwaits
) tip
154 invoke_handlers output stdout
$dat
156 $signals(running
) set_state
0
157 invoke_handlers reaped
$res
158 $signals(finished
) set_state
1
163 $dominos(check_output_vwaits
) tip
165 invoke_handlers output stdout
$dat
169 body tlc
::Process::stderr_handler {subcmd channelId args
} { #<<<
173 if {$mode != "write"} {
174 error "Only writing is supported"
194 lappend buf
[list stderr
$data]
195 invoke_handlers output stderr
$data
197 $dominos(check_output_vwaits
) tip
199 return [string length
$data]
207 error "Unsupported subcommand: ($subcmd)"
213 body tlc
::Process::output {} { #<<<
216 lassign
$chunk channel data
223 body tlc
::Process::stdout {} { #<<<
226 lassign
$chunk channel data
227 if {$channel != "stdout"} continue
234 body tlc
::Process::stderr {} { #<<<
237 lassign
$chunk channel data
238 if {$channel != "stderr"} continue
245 body tlc
::Process::result {} { #<<<
246 if {![$signals(finished
) state
]} {
247 error "Child yet lives"
253 body tlc
::Process::waitfor_output {match
} { #<<<
254 if {[string match
"*$match*" $buf]} {
258 set output_matches
($myseq) $match
259 set output_vwaits
($myseq) ""
260 vwait [scope output_vwaits
($myseq)]
261 set result
$output_vwaits($myseq)
262 array unset output_vwaits
$myseq
264 switch -- [lindex $result 0] {
266 error {error [lindex $result 1] "" [lindex $result 2]}
271 body tlc
::Process::check_output_vwaits {} { #<<<
273 foreach {matchseq match
} [array get output_matches
] {
274 if {[string match
"*$match*" $plain]} {
275 array unset output_matches
$matchseq
276 set output_vwaits
($matchseq) [list ok
]
282 body tlc
::Process::abort_waits {} { #<<<
283 $dominos(check_output_vwaits
) force_if_pending
284 foreach {matchseq match
} [array get output_matches
] {
285 array unset output_matches
$matchseq
286 set output_vwaits
($matchseq) [list error "child died while waiting for \"$match\"" [list child_died
$match]]
291 body tlc
::Process::pids {} { #<<<