Help with named pipes

I am having some trouble using named pipes in ruby, as illustrated
in the below example program. Can anyone tell me what I’m doing wrong?

The syntax here is:

% pipetest.rb [command] [mode]

The program creates a named pipe called /tmp/our_test_pipe
and then fills it with the following text:

STDERR.puts "hello"

It then executes an arbitrary command on the named pipe using popen3.
There are two different ways it can fill the pipe: mode 1 runs an echo
command, and mode 2 opens the pipe like a file and writes the string.

% pipetest.rb cat 1
STDERR.puts “hello”
% pipetest.rb cat 2
STDERR.puts “hello”

So far so good. However,

$ pipetest.rb ruby 1
hello
$ pipetest.rb ruby 2
(hangs indefinitely)

At this point ps shows two ruby threads, both of which are stopped:
15183 0.8 0.5 2644 1420 pts/0 S 22:51 0:00 ruby ./pipetest.rb ruby 2
15186 0.4 0.4 2556 1160 pts/0 S 22:51 0:00 ruby /tmp/our_test_pipe

My naive impression was that the command run by popen3 should see an EOF on
the pipe and exit properly, after fill2 stops writing and closes the pipe.
Why does it hang instead?

Thanks for any help,

-Greg

···

pipetest.rb begins here:

#!/usr/bin/env ruby

require ‘open3’

command = ARGV[0]
mode= ARGV[1].to_i

class NamedPipeTest

attr_reader :name

def initialize(name)
@name=name
File.delete(@name) if FileTest.exist?(@name)
mkfifo #{@name}
Kernel.at_exit { File.delete(@name) }
end
def fill1
echo_command='echo STDERR.puts “hello”'
IO.popen(echo_command + '>> ’ + @name)
end
def fill2
@f=File.open(@name,“w”)
@f.sync=true
@f.write ‘STDERR.puts “hello”’+"\n"
@f.close_write
# @f.close
end
end

pipe=NamedPipeTest.new("/tmp/our_test_pipe")

sin,sout,serr= Open3.popen3(command+ " " +pipe.name)
sin.sync=sout.sync=serr.sync=true
sin.close_write

Thread.start {
if mode==1 then pipe.fill1
else pipe.fill2 end
}

while line=sout.gets
STDERR.puts line
end
sout.close

while line=serr.gets
STDERR.puts line
end
serr.close