On 2005-05-21 12:25:09 -0700, wjposer@unagi.cis.upenn.edu (William J
Poser) said:
> I'm having trouble using fileevent to monitor the progress
> of a child process. The child periodically writes a line to a file
> containing the percentage that it has accomplished.
> What I've tried doing is opening a pipe to tail this file
> and using fileevent to read from the pipe each time it
> becomes readable. Here is the relevant fragment of the code:
>
> catch {open "|$cl" "r"} PipeID;
> fileevent $PipeID readable [list MinpairPipeEvent $PipeID $StartTime]
> set plogfd [open "|tail -f $::ProgressFile" r]
> fconfigure $plogfd -blocking 0 -buffering none
> fileevent $plogfd readable [list UpdateProgress $plogfd]
> tkwait variable ::ElapsedTime;
>
> The variable cl contains the command line that starts the child
> process. The reason for the first fileevent is so that I can
> time the execution of the daughter. That part has been working fine.
>
> Here is the handler for the fileevent:
>
> proc UpdateProgress {fd} {
> if {[eof $fd]} {
> dmsg "End of file on plogfd"
> fileevent $fd readable {}
> close $fd;
> return ;
> }
> if {[gets $fd Percent] > 0} {
> dmsg $Percent;
> SetProgress $::PBAR $Percent;
> } else {
> dmsg "Empty read from plogfd." }
> }
>
> This isn't working. What happens is that I get the first
> two lines from the ProgressFile. There are no further
> updates to the progress bar (and no calls to UpdateProgress
> as judged from the debugging messages), until the child
> exits, at which point I get all of the updates at once.
>
> This looks like a buffering problem, but two things seem
> to be inconsistent with that:
>
> (a) I've made everything unbuffered. In the daughter program
> I do an fflush after every write. In the Tcl program,
> as you can see, I set the read from tail to be unbuffered.
> (I've also tried line buffering, with the same result.)
>
> (b) If this is a buffering problem, why do I get the first
> two lines before it starts buffering everything up?
>
> I should add that the child process loads the CPU very heavily
> so to be sure that the problem isn't the CPU being tied up,
> I inserted a one second sleep after every write to the
> ProgressFile by the daughter. That didn't change anything.
>
> It also occurred to me that the tkwait might be interfering,
> but the documentation says that during a tkwait events are processed
> normally.
>
> Can anyone tell me what is wrong?
>
> Bill
Try setting PipeID to non-blocking, unbuffered also. I don't think this
is the problem, but it wouldn't hurt.
You also need to do multiple [gets] calls until you exaust the channel.
You're better off using [read], I think, which will fetch everything
in one go, but the program becomes a little more complicted. Try just
changing the [if] to [while]:
proc UpdateProgress {fd} {
if {[eof $fd]} {
dmsg "End of file on plogfd"
fileevent $fd readable {}
close $fd;
return ;
}
while {[gets $fd Percent] > 0} {
dmsg $Percent;
SetProgress $::PBAR $Percent;
}
}
I don't believe fileevent will make another callback unless the channel
goes empty and then new data arrives.
-Brian
Received on Thu Sep 29 14:18:47 2005