Forum: Ruby IO.popen hangs reading an empty pipe?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Payton S. (Guest)
on 2006-01-30 22:46
(Received via mailing list)
How does one check a pipe (created using IO.popen) to see if there is
input waiting without using IO#eof or reading from the pipe?  Doing
either of these seems to hang forever if the pipe is empty.

Here's an example:

require 'timeout'
IO.popen("cat", "r+") do |pipe|
#   pipe.puts "hello world" # Uncomment this to prevent hang below.
   Timeout::timeout(2) do
     if not pipe.eof? # This will hang if the pipe is empty.
       p pipe.getc
     end
   end
end

-Payton
unknown (Guest)
on 2006-01-30 22:46
(Received via mailing list)
On Tue, 31 Jan 2006, Payton S. wrote:

> How does one check a pipe (created using IO.popen) to see if there is input
> waiting without using IO#eof or reading from the pipe?  Doing either of these
> seems to hang forever if the pipe is empty.

     harp:~ > cat a.rb
     IO.popen("cat", "r+") do |pipe|
       pipe.puts 42
       pipe.close_write
       puts pipe.read
     end


     harp:~ > ruby a.rb
     42



consider that cat reads stdin until eof is found.

> Here's an example:
>
> require 'timeout'
> IO.popen("cat", "r+") do |pipe|
> #   pipe.puts "hello world" # Uncomment this to prevent hang below.

not really - only the first one.  continue to read an you'll still hang.
this
is because cat is still waiting on more stdin or eof.  so you must send
more or
close the write end of the pipe to send eof.

>  Timeout::timeout(2) do

never mix timeout with reads.  it fails on windoze - if you care.

>    if not pipe.eof? # This will hang if the pipe is empty.

because cat is waiting for stdin and is not finsihed - cat will only
close it's
stdout when it's done and it's only done when it's stdin has all been
read.
man 1 cat.

>      p pipe.getc
>    end
>  end
> end


if you are on *nix you'll find my session module much easier to use:

     harp:~ > gem install session
     Attempting local installation of 'session'
     Local gem file not found: session*.gem
     Attempting remote installation of 'session'
     Updating Gem source index for: http://gems.rubyforge.org
     Successfully installed session-2.4.0
     harp:~ > cat a.rb
     require "rubygems"
     require "session"
     require "stringio"


     sh = Session::new

     stdin = "42"
     stdout = StringIO::new
     stderr = StringIO::new

     sh.execute "cat", "stdin" => stdin, "stdout" => stdout, "stderr" =>
stderr

     puts stdout


     harp:~ > ruby a.rb
     42


session can also be made to be thread-safe (eg use with timeout) if
needed.  see docs for more.


kind regards.



-a
Payton S. (Guest)
on 2006-01-30 22:46
(Received via mailing list)
Ah. You're right, of course.  I could have sworn that I tried using
pipe.close_write before and the problem remained, but apparently I was
mistaken.

Notes:
   - "cat" was just to prove a point - the real issue was with
"sendmail", but it seems to have the same solution.  My brief overview
made me think session was not suited for sendmail, but perhaps I was
wrong about that too?   I'll check it out.
   - the use of timeout was just to allow the test to exit when the hang
occurred.  I didn't realize it fails on w32.  Is it Timeout that fails,
or just when timeout is combined with IO reads?

Thanks again!
-Payton
unknown (Guest)
on 2006-01-30 22:46
(Received via mailing list)
On Tue, 31 Jan 2006, Payton S. wrote:

> Ah. You're right, of course.  I could have sworn that I tried using
> pipe.close_write before and the problem remained, but apparently I was
> mistaken.
>
> Notes:
>  - "cat" was just to prove a point - the real issue was with "sendmail", but
> it seems to have the same solution.  My brief overview made me think session
> was not suited for sendmail, but perhaps I was wrong about that too?   I'll
> check it out.

you can do anything with session that bash can do - not sure if it'll
work for
sendmail or not.  should work anywhere you are dealing with
stdin/out/err.

>  - the use of timeout was just to allow the test to exit when the hang
> occurred.  I didn't realize it fails on w32.  Is it Timeout that fails, or
> just when timeout is combined with IO reads?

i may have mispoke - you may be able to use a thread and timeout - but
it very
easy to block an entire process with io and threads in win... fyi.

cheers.


-a
Joel VanderWerf (Guest)
on 2006-01-30 22:46
(Received via mailing list)
removed_email_address@domain.invalid wrote:
...
>>  - the use of timeout was just to allow the test to exit when the hang
>> occurred.  I didn't realize it fails on w32.  Is it Timeout that
>> fails, or just when timeout is combined with IO reads?
>
> i may have mispoke - you may be able to use a thread and timeout - but
> it very
> easy to block an entire process with io and threads in win... fyi.

I've mixed threads, timeout, and sockets on windows with no problems.
But I haven't done this with pipes...

ISTR that the problem on windows is with terminal io.
This topic is locked and can not be replied to.