KaiLoi has asked for the wisdom of the Perl Monks concerning the following question:

Hey all, long time user, first time poster. I'm writing a program in libPOE to grab some input from a command line program and then do some stuff with it. I've grabbed a pretty generic sample from the POE cookbook site and it works GREAT with clearly terminating output like the output from an "ls" or something. But the min I make the input the equivilent of a pipe (so the input is coming in line by line but the source program doesn't terminate) the Filter seems to "buffer" the input and doesn't hand it back to my stdio catch until about 35 lines have gone by.

I'm mostly ttying to cpature the line by line output of "udevadm monitor" on a Ubuntu 16 box. I want to do various things based on the output of the UDEV lines. But it just won't hand it back for a period of input and I can't figure out why. It basically doesn't display anything to terminal until I plug and unplug a USB key multiple times and get about 35 lines of output from udevadm. Any help would be greatly appreciated. Code below.

#!/usr/bin/perl use warnings; use strict; use POE qw( Wheel::Run Filter::Line ); # Start the session. Spawn a simple program, and describe the events # it will generate as it does things. sub _start { my ($kernel, $heap) = @_[KERNEL, HEAP]; $heap->{child} = POE::Wheel::Run->new( Program => ["udevadm monitor"], # Program to run. StdioFilter => POE::Filter::Line->new(), # Child speaks in lin +es. StderrFilter => POE::Filter::Line->new(), # Child speaks in lin +es. StdoutEvent => "got_child_stdout", # Child wrote to STDO +UT. StderrEvent => "got_child_stderr", # Child wrote to STDE +RR. CloseEvent => "got_child_close", # Child stopped writi +ng. ); $kernel->sig_child($heap->{child}->PID, "got_sigchld"); } # Deal with information the child wrote to its STDOUT. sub got_child_stdout { my $stdout = $_[ARG0]; print "STDOUT: $stdout\n"; } # Deal with information the child wrote to its STDERR. These are # warnings and possibly error messages. sub got_child_stderr { my $stderr = $_[ARG0]; $stderr =~ tr[ -~][]cd; print "STDERR: $stderr\n"; } # The child has closed its output filehandles. It will not be sending # us any more information, so destroy it. sub got_child_close { my $heap = $_[HEAP]; print "child closed.\n"; delete $heap->{child}; } # Handle SIGCHLD, otherwise the child process will not be reaped. # Don't do anything significant, but do catch the signal so the child # process is reaped. sub got_sigchld { print "SIGCHLD reaped.\n"; } # A list of functions that will handle the events they're named after. my @handlers = qw( _start got_child_stdout got_child_stderr got_child_close got_sigchld ); # Start a session where each event is handled by a function with the # same name. Run POE's Kernel (and thus all its sessions) until done. POE::Session->create(package_states => [main => \@handlers]); POE::Kernel->run(); exit 0;
  • Comment on POE::Filter::Line seems to be buffering ??? input from some command line programs but not others?
  • Download Code

Replies are listed 'Best First'.
Re: POE::Filter::Line seems to be buffering ?
by haukex (Archbishop) on Oct 02, 2017 at 06:50 UTC

    So it turns out that this can be easily reproduced by comparing the output of udevadm and udevadm | cat on the command line - udevadm is behaving exactly as Perl would when it is Suffering from Buffering (i.e. it's not entirely your program's fault). One fix appears to be adding the option Conduit => 'pty' or Conduit => 'pty-pipe' to the POE::Wheel::Run constructor, I've tested this with your code and it works. From the POE::Wheel::Run documentation: "The "pty" conduit type runs the child process under a pseudo-tty, which is created by IO::Pty. Pseudo-ttys (ptys) convince child processes that they are interacting with terminals rather than pipes", thus disabling the buffering in udevadm.

      Oh thank god! This fixed it perfectly. Thank you SO much! I was bashing my head against this. I had been pouring through the documentation on POE::Filter::Line figuring it must be something to do with the terminating character on the output from udevadm. Never occurred to me to look right up at Wheel::Run. I stared at this trying various things for hours last night. I figured it had to be something to do with the particular output of udevadm. I'm glad I wasn't insane. I shall be naming my firstborn after you now.