On Fri, Jun 04, 2004 at 11:31:27 -0400, muppet wrote:
On Friday, June 4, 2004, at 04:14 AM, Syed Imran wrote:It shows only the first line of output produced by the external program. I am having difficulty locating the problem. I've added the code to this mail.your test program exits almost immediately after printing a couple of lines of output. the watch handler reads one line of input at a time. fork child. install handler. child prints three lines of output and exits. your io watch fires with the condition [ 'in', 'hup' ] you read and process one line of input. you close the handle. this is something of a race condition. i could make your code print all the lines that come back by adding some pauses after each line of input. in a Real Program, you wouldn't be able to do that, and you'd want to read everything that comes back.
It's not a race-condition. It's just plain old bug. You must not exit until read returned 0, meaning no more characters to read.
there are two ways to slurp in all data in Perl (of which *i* know -- there may be others. all you mongers listening, please feel free to correct me): 1) set $/ to undef, to read till end of file. this is undesirable, because your watch handler will hang (since the stream is not yet finished). 2) find out how many bytes are actually waiting, and read exactly that many. this requires the use of ioctl and sysread, and is immediately non-portable. since you're using fdisk, you probably don't care about that.
3) Force the file to non-blocking mode and use 1. Fcntl should be sufficiently portable. 4) Use sysread. Sysread does not clear the 'in' condition, so your callback will be called again. Just you must not exist on 'hup' until sysread has really returned 0. Without nonblock mode, you must only call sysread once per invocation. 5) Use 3 with 4, just to stay on the safe side.
i got option 2 to work by replacing these lines: my $data = <$fh>; with these: #require "sys/ioctl.ph"; # my perl headers appear to be broken, so here it is, hardcoded. sub FIONREAD { 0x541B } my $count; my $ret = ioctl $fh, &FIONREAD, $count; $count = unpack "i", $count; my $data; sysread $fh, $data, $count; this no longer works by lines, but that's ok, because the data on the input handle may include incomplete lines, anyway.
Unfortunately perlio is not ready for non-blocking descriptors. However, I can imagine IO layer supporting line oriented io on non-blocking descriptors, including poll/select support etc. I really wish perl IO descriptors had a 'buffer' method. It would return the internal buffer as a (read-only) string. Then we could have Glib::IO watchers properly generating 'in' event when the perlio descriptor (not the underlying file) have some data to read! ------------------------------------------------------------------------------- Jan 'Bulb' Hudec <bulb ucw cz>
Attachment:
signature.asc
Description: Digital signature