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)"
152 $signals(running
) set_state
0
153 invoke_handlers reaped
$res
154 $signals(finished
) set_state
1
159 $dominos(check_output_vwaits
) tip
161 invoke_handlers output stdout
$dat
165 body tlc
::Process::stderr_handler {subcmd channelId args
} { #<<<
169 if {$mode != "write"} {
170 error "Only writing is supported"
190 lappend buf
[list stderr
$data]
191 invoke_handlers output stderr
$data
193 $dominos(check_output_vwaits
) tip
195 return [string length
$data]
203 error "Unsupported subcommand: ($subcmd)"
209 body tlc
::Process::output {} { #<<<
212 lassign
$chunk channel data
219 body tlc
::Process::stdout {} { #<<<
222 lassign
$chunk channel data
223 if {$channel != "stdout"} continue
230 body tlc
::Process::stderr {} { #<<<
233 lassign
$chunk channel data
234 if {$channel != "stderr"} continue
241 body tlc
::Process::result {} { #<<<
242 if {![$signals(finished
) state
]} {
243 error "Child yet lives"
249 body tlc
::Process::waitfor_output {match
} { #<<<
250 if {[string match
"*$match*" $buf]} {
254 set output_matches
($myseq) $match
255 set output_vwaits
($myseq) ""
256 vwait [scope output_vwaits
($myseq)]
257 set result
$output_vwaits($myseq)
258 array unset output_vwaits
$myseq
260 switch -- [lindex $result 0] {
262 error {error [lindex $result 1] "" [lindex $result 2]}
267 body tlc
::Process::check_output_vwaits {} { #<<<
269 foreach {matchseq match
} [array get output_matches
] {
270 if {[string match
"*$match*" $plain]} {
271 array unset output_matches
$matchseq
272 set output_vwaits
($matchseq) [list ok
]
278 body tlc
::Process::abort_waits {} { #<<<
279 $dominos(check_output_vwaits
) force_if_pending
280 foreach {matchseq match
} [array get output_matches
] {
281 array unset output_matches
$matchseq
282 set output_vwaits
($matchseq) [list error "child died while waiting for \"$match\"" [list child_died
$match]]
287 body tlc
::Process::pids {} { #<<<