Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re^3: Testing for a background process waiting for input (use a thread)

by Eliya (Vicar)
on Apr 14, 2012 at 22:02 UTC ( #965098=note: print w/ replies, xml ) Need Help??


in reply to Re^2: Testing for a background process waiting for input (use a thread)
in thread Testing for a background process waiting for input

Just for the record, a "unixish" implementation of BrowserUk's idea could look something like this:

#!/usr/bin/perl -slw use strict; our $N //= 12; our $I //= 0; my $cmd = qq[exec $^X -E'sleep $N; \$_=<STDIN> if $I; sleep 2; printf +"Kid done (read %d bytes)\\n", length']; my $inInputState = 1; my $timedOut = 0; $SIG{PIPE} = sub { $inInputState = 0; }; $SIG{ALRM} = sub { $inInputState = 0; $timedOut = 1; die }; $SIG{CHLD} = 'IGNORE'; my $pid = open CMD, '|-', $cmd or die $!; alarm 10; eval { syswrite CMD, " \b"x(2**15+1) }; alarm 0; if( $timedOut ) { print "Command timed out"; kill 15, $pid; } if( $inInputState ) { print "Child waiting for input"; } else { print "Kid never entered input state"; } print 'Parent done'; __END__ $ ./detectChildInputState -I=0 -N=2 Kid done (read 0 bytes) Kid never entered input state Parent done $ ./detectChildInputState -I=1 -N=2 Child waiting for input Parent done $ Kid done (read 65538 bytes) $ ./detectChildInputState -I=1 -N=12 Command timed out Kid never entered input state Parent done $ ./detectChildInputState -I=1 -N=9 Child waiting for input Parent done $ Kid done (read 65538 bytes) $ ./detectChildInputState -I=0 -N=9 Command timed out Kid never entered input state Parent done

The main difference revolves around the SIGPIPE signal which on Unix would be delivered to a process if it attempts to write to a broken pipe (this is the case when the child terminates before having read anything).

By default, this signal would terminate the writing process, so it would have to be handled one way or another, anyway (e.g. $SIG{PIPE} = 'IGNORE'). OTOH, we can take advantage of this error notification, in which case we don't need an extra thread (or process) doing the blocking write.  The logic is kind of reversed now: we assume things went ok, unless we know otherwise, which is when

  • the child terminated before it went into an input state (in which case we get a SIGPIPE)
  • a timeout occurred before the child went into an input state

in those cases, $inInputState is set to zero in the respective signal handler.

A couple of more notes:

  • the timeout is implemented via the usual alarm mechanism (instead of status polling in a loop)
  • I'm using syswrite to circumvent Perl's own buffering without having to fiddle with autoflush
  • Unix pipes typically use a rather large buffer (64k in my case), so the chunk written needs to be significantly larger than on Windows, in order to get the write operation to block
  • the backspace cancellation trick would only work under rare circumstances (AFAICT) — simply reading from stdin would, for example, not treat the backspaces in any special way.
  • last but not least, as a consequnce of the above, the tested program should be able to handle 64k of junk in case it puts up an innocent prompt (whether this is in fact an issue, of course depends on the type of program...)


Comment on Re^3: Testing for a background process waiting for input (use a thread)
Select or Download Code
Re^4: Testing for a background process waiting for input (use a thread)
by BrowserUk (Pope) on Apr 15, 2012 at 01:33 UTC
    a "unixish" implementation of BrowserUk's idea

    Nice!++

    the backspace cancellation trick would only work under rare circumstances (AFAICT) simply reading from stdin would, for example, not treat the backspaces in any special way.

    I added a little extra diagnostics. a) When the parent detects that the child entered an input state, it sends it a string "hello\n"; b) when the child enters an input state, it prints out what it receives:

    The upshot shows that on Windows at least, even though the child (perl in this case) only uses a standard read from stdin scalar <STDIN>, the CRT provides line-editing that allows the backspace cancellation to work:

    C:\test>detectChildInputState -I=0 -N=2 Kid done Kid never entered input state Parent done C:\test>detectChildInputState -I=1 -N=2 Child waiting for input Parent done Kid got hello Kid done C:\test>detectChildInputState -I=0 -N=10 Command timed out Kid never entered input state Parent done C:\test>detectChildInputState -I=1 -N=10 Child waiting for input Parent done Kid got hello Kid done C:\test>detectChildInputState -I=0 -N=12 Command timed out Kid never entered input state Parent done C:\test>detectChildInputState -I=1 -N=12 Command timed out Kid never entered input state Parent done

    But I guess what you are saying is that under *nix, the standard CRT input routines don't provided line editing facilities, unless the program in question uses a readline(3) library or similar.

    Would nulls be an workable alternative? Or DC1/DC3 (XON/XOFF)?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      But I guess what you are saying is that under *nix, the standard CRT input routines don't provided line editing facilities, unless the program in question uses a readline(3) library or similar.

      Essentially yes.   stdin is just a file handle like any other, which by itself is unfiltered / binary-clean. Any other behavior you may observe (typically with interactive sessions) is the result of other layers that sit in between stdin and the user/keyboard, most prominently a tty and (optionally) some readline library.

      When stdin is connected to a regular pipe for non-interactive communication, those layers are not involved, unless things have explicitly been programmed that way (as with tools like Expect or similar) — this of course can be done, but usually isn't.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://965098]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (9)
As of 2014-07-22 12:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (112 votes), past polls