SPUG: shell script event loops + wrapping shell utilities

Doug Beaver doug at beaver.net
Fri Apr 19 19:25:37 CDT 2002


On Thu, Apr 18, 2002 at 11:42:24PM -0700, dancerboy wrote:

> #!/usr/bin/perl
> 
> use strict;
> use Fcntl;
> use IPC::Open3;
> 
> $| = 1;
> 
> my $from_term;
> my $from_shell;
> my $pipe_error;
> 
> open(TTY, "+</dev/tty") or die "no tty: $!";
> fcntl( TTY, F_SETFL, O_NONBLOCK );
> 
> my $pid = open3( \*TO_SHELL, \*FROM_SHELL, \*SHELL_ERR,
>          'ftp -v strangelight.com'
> );
> 
> fcntl( FROM_SHELL, F_SETFL, O_NONBLOCK );
> fcntl( SHELL_ERR, F_SETFL, O_NONBLOCK );
> 
> my $oldfh = select(FROM_SHELL); $| = 1; select($oldfh);
> $oldfh = select(SHELL_ERR); $| = 1; select($oldfh);
> $oldfh = select(TTY); $| = 1; select($oldfh);
> 
> $SIG{PIPE} = sub { ++$pipe_error; };
> 
> while ( not $pipe_error ) {
>                  while( defined( $from_term = getc(TTY) ) ) {
>                          print TO_SHELL $from_term;
>                  }
>                  while( defined( $from_shell = getc(FROM_SHELL) ) ) {
>                          print $from_shell;
>                  }
>                  while( defined( $from_shell = getc(SHELL_ERR) ) ) {
>                          print $from_shell;
>                  }
> }
> 
> __END__
> 
> Now, I have two questions.
> 
> My first question is, admittedly, one of those "I could probably
> figure it out on my own but I'm lazy so I'll ask the folks on SPUG
> instead" questions:
> 
> While my script works fairly well as-is, it's a real processor hog, 
> as you can probably guess.  All of those getc() calls are 
> non-blocking, so even when there's no input or output to process, the 
> main while() loop still keeps executing over and over again, doing 
> absolutely nothing as fast as it possibly can.  What's the 
> best/simplest way to tell Perl to "go to sleep, but wake up as soon 
> as something interesting happens"?

You want to use either select() or IO::Select.  Check out your system
manpage for select(2) to get a general idea of what it does and then
check out the perldoc -f for select, it has an example of selecting on
multiple filehandles.  If it looks too daunting, you could use
IO::Select's OO api too.  select has a timeout option, so you can make
it block forever or timeout after a given number of seconds.  I bet the
perl cookbook even has an example or two of select on filehandles, it's
a common idiom.  I don't have a copy handy, otherwise I would give you a
pointer.  The perldoc says you shouldn't mix select with buffered i/o,
so maybe you want to use select & sysread instead.

> My second question is one I've banged my head on for a while and 
> haven't been able to figure out at all:
> 
> Even with setting $|=1 on all the open pipes, I still don't always 
> get my I/O flushed promptly -- in particular, the responses I read 
> back from FROM_SHELL seem often to be one or two lines behind what I 
> should be getting. (My work-around has been to send a no-op command 
> like 'pwd', the response to which usually forces the lines that I 
> want to see out of the buffer.)  What else can I do to get my pipes 
> "piping hot" (as the perldocs say)?

Sorry, I don't know about this.  Maybe it has something to do with
buffered i/o.  You could try using sysread instead of <> for the i/o and
see if that solves your problem.  That combined with the select just
might do the trick...  Just be careful not to mix sysread with buffered
reads (like read() or <>).

Doug

-- 
Space Ghost: Moltar, I have a giant brain that is able to reduce any
             complex machine into a simple yes or no answer.
     Moltar: Okay, but that's not the cd burner...
Space Ghost: Moltar! <pause> Yes!

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
      Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
  Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
 For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
     Seattle Perl Users Group (SPUG) Home Page: http://seattleperl.org




More information about the spug-list mailing list