Background process readling lines and responding

Greetings -- I'm debugging a way to call a command-line executable as a
server. In normal life it behaves like grep, reading lines from stdin
and printing responses to stdout. So I'm debugging the Ruby wrapper on
grep, as the original takes a long time to load (thus the whole
exercise). Here's what I got -- but it swallows the first line of input
and doesn't respond! Why?

#!/usr/bin/env ruby

require 'optparse'
require 'ostruct'

class Server

  def initialize(cmd_line)
    puts "starting server with the following command line:"
    puts cmd_line
    @pipe = IO.popen cmd_line, "r+"
  end

  def process(sent)
    return nil if sent.nil? or sent =~ /^\s+$/

    puts "sending: [#{sent}]"
    @pipe.write(sent)

    @pipe.readlines
  end
end # class

def main
  o = OpenStruct.new
  files = OptionParser.new do |opt|
    opt.on("-e", "--exe EXE", "server executable basename") { |val|
o.exe = val }
  end.parse(*ARGV)

  ps = Server.new(o.exe)

  STDIN.each_line do |line|
    out = ps.process(line)
    puts out
  end
end

main if $0 == __FILE__

-- Here's what happens when I try to use it:

$ aha-grep-server.rb -e "grep abra"
starting server with the following command line:
grep abra
abracadabra
sending: [abracadabra
]

-- then it just hangs there, @pipe.readlines returning nothing. What's
the right IO semantics here?

Cheers,
Alexy

···

--
Posted via http://www.ruby-forum.com/.

Alexy,

The first thing that comes to mind is that you are writing the sent
text to the pipe and then immediately calling readlines; is that
enough time for grep to process its work and write the result back to
the pipe?

Also, by "but it swallows the first line of input and doesn't
respond!", do you mean that you are not able to write anymore text
(indicating that readlines might be blocking) or just that it never
shows grep's result?

-Szymon

···

On Nov 9, 6:45 am, Alexy Khrabrov <delivera...@gmail.com> wrote:

Greetings -- I'm debugging a way to call a command-line executable as a
server. In normal life it behaves like grep, reading lines from stdin
and printing responses to stdout. So I'm debugging the Ruby wrapper on
grep, as the original takes a long time to load (thus the whole
exercise). Here's what I got -- but it swallows the first line of input
and doesn't respond! Why?

#!/usr/bin/env ruby

require 'optparse'
require 'ostruct'

class Server

  def initialize(cmd_line)
    puts "starting server with the following command line:"
    puts cmd_line
    @pipe = IO.popen cmd_line, "r+"
  end

  def process(sent)
    return nil if sent.nil? or sent =~ /^\s+$/

    puts "sending: [#{sent}]"
    @pipe.write(sent)

    @pipe.readlines
  end
end # class

def main
  o = OpenStruct.new
  files = OptionParser.new do |opt|
    opt.on("-e", "--exe EXE", "server executable basename") { |val|
o.exe = val }
  end.parse(*ARGV)

  ps = Server.new(o.exe)

  STDIN.each_line do |line|
    out = ps.process(line)
    puts out
  end
end

main if $0 == __FILE__

-- Here's what happens when I try to use it:

$ aha-grep-server.rb -e "grep abra"
starting server with the following command line:
grep abra
abracadabra
sending: [abracadabra
]

-- then it just hangs there, @pipe.readlines returning nothing. What's
the right IO semantics here?

Cheers,
Alexy
--
Posted viahttp://www.ruby-forum.com/.

Hey Szymon -- good to see you here! If, instead of "grep something", I
give it a Ruby program which reads and writes lines, it works OK. I
wonder what's different between these:

-- a.rb:
IO.popen("ruby b.rb", "r+") do |f|
  STDIN.each_line do |x|
    @write = f.puts x.to_s
    @read = f.gets
    puts "back: #{@read}"
  end
end

-- b.rb:
STDOUT.sync = true

def readWrite
  while @string = gets
    @string.chomp!
    puts "received => #{@string}"
  end
end

readWrite

$ ruby a.rb
/z/aha/ru/popen ruby a.rb
abra
back: received => abra
cadabra
back: received => cadabra
...
-- can enter strings, they're echoed back.

Now, let's call "grep abra" instead of b.rb:
-- call-grep.rb:
IO.popen("grep abra", "r+") do |f|
  STDIN.each_line do |x|
    puts "sending: #{x}"
    @write = f.puts x.to_s
    @read = f.gets
    puts "back: #{@read}"
  end
end

$ ruby call-grep.rb:
/z/aha/ru/popen ruby call-grep.rb
abra
sending: abra
cadabra
-- already unresponsive.

···

--
Posted via http://www.ruby-forum.com/.

I guess you should make sure to flush the pipe caches before trying to
get output from the background process. If the data you sent in the
first place is still sitting there, you won't get anything back...

Anyway, I had better luck with using two separate threads for writing
and reading to/from the pipe. This one below just hangs because the
buffers fill up and it can't send more data before reading from the
output. Note that this is on Cygwin on WinXP SP2 - the amount of data
which triggers the deadlock may wary on other systems.

open('|tr [a-z] [A-Z]', 'w+') do |tr|
  30000.times{tr.puts 'hehe'}
  tr.close_write
  puts tr.read
end

But this one echoes back the HEHE's just as expected:

open('|tr [a-z] [A-Z]', 'w+') do |tr|
  Thread.new do
    30000.times{tr.puts 'hehe'}
    tr.close_write
  end
  puts tr.read
end

Alexy Khrabrov wrote:

···

Hey Szymon -- good to see you here! If, instead of "grep something", I
give it a Ruby program which reads and writes lines, it works OK. I
wonder what's different between these: