Problem running pipeline

Hello,

I tried to write a run_pipeline method that would return the exit
status (and stderr) of every process in the pipe.

I am running ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

Inserting a method call by patching in

somename args
end
def somename args

produces lockup.

I guess I could construct the pipeline in a single method but why
would inserting a method call break otherwise working code is a
mystery.

Any insights welcome.

Thanks

Michal

Code (incomplete but working):

$ cat pipeline.rb
READSIZE = 1024 * 32
def gather_out io, str
begin
while true do
str << (io.readpartial READSIZE)
end
rescue EOFError
end
str
end

def waiton things
things.collect{|thing|
if thing.is_a? Thread then
thing.join
else
Process::waitpid thing
$?
end
}
end

def fork_process cmd, inp_chld, out_chld, err_chld, odd_ends
pid = fork {
odd_ends.each{|fd| fd.close}
STDIN.reopen inp_chld
STDOUT.reopen out_chld
STDERR.reopen err_chld
exec cmd
}
inp_chld.close
out_chld.close
err_chld.close
pid
end

def run_pipeline_w cmds
inp_chld, inp = IO.pipe
out, out_chld = IO.pipe
err, err_chld = IO.pipe
cmd, *cmds = cmds
if cmds.length == 0 then
outstr = “”
errstr = “”
pid = fork_process cmd, inp_chld, out_chld, err_chld, [inp, out,
err]
threads = [ Thread.new { yield inp ; inp.close},
Thread.new { gather_out out, outstr },
Thread.new { gather_out err, errstr } ]
ret, *_ = waiton [pid] + threads
else
raise “FIXME”
end
[outstr,errstr,ret]
end

$ cat tc_pipeline.rb
require ‘pipeline’
require ‘test/unit’
require ‘stringio’

class TestPipeline < Test::Unit::TestCase
def setup
# none
@data_lines = 1000
@data_text = “%i some data”
@inp = StringIO.new
output_data @inp
@inp.rewind
@inp = @inp.read
end
def output_data io
(1…@data_lines).each {|i| io.puts(@data_text % i) }
end
def teardown
# none
end

def test_cat
    out, err, ret = run_pipeline_w( ["cat"] ){|io| output_data io

rescue nil}
assert_equal ret, 0
assert_equal @inp, out
assert_equal err, “”
end

def test_doublecat
    out, err1, ret1, err2, ret2 = run_pipeline_w( ["cat","cat"]

){|io| output_data io rescue nil}
assert_equal ret1, ret2, 0
assert_equal @inp, out
assert_equal err1, err2, “”
end
end

Patch (in my eyes noop but breaking):
diff --git a/pipeline.rb b/pipeline.rb
index 73cb91b…9ef7630 100644
— a/pipeline.rb
+++ b/pipeline.rb
@@ -38,6 +38,9 @@ end
def run_pipeline_w cmds
inp_chld, inp = IO.pipe
out, out_chld = IO.pipe

  • run_pipeline_w_ios cmds, inp, out, inp_chld, out_chld, [inp, out],
    []
    +end
    +def run_pipeline_w_ios cmds, inp, out, inp_chld, out_chld, odd_ends,
    threads = []
    err, err_chld = IO.pipe
    cmd, *cmds = cmds
    if cmds.length == 0 then

2011/8/9 Michal S. [email protected]:

would inserting a method call break otherwise working code is a
mystery.

use -d.

% ruby-1.8.7p352 -d tc_pipeline.rb
Loaded suite tc_pipeline
Started
Exception LocalJumpError' at ./pipeline.rb:50 - no block given ./pipeline.rb:50:in run_pipeline_w_ios’: no block given
(LocalJumpError)
from ./pipeline.rb:50:in initialize' from ./pipeline.rb:50:in new’
from ./pipeline.rb:50:in run_pipeline_w_ios' from ./pipeline.rb:41:in run_pipeline_w’
from tc_pipeline.rb:23:in test_cat' from /home/ruby/187p352/lib/ruby/1.8/test/unit/testcase.rb:78:in send
from /home/ruby/187p352/lib/ruby/1.8/test/unit/testcase.rb:78:in
run' from /home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:34:in run’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:33:in each' from /home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:33:in run’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:34:in run' from /home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:33:in each’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/testsuite.rb:33:in run' from /home/ruby/187p352/lib/ruby/1.8/test/unit/ui/testrunnermediator.rb:46:in run_suite’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/ui/console/testrunner.rb:67:in
start_mediator' from /home/ruby/187p352/lib/ruby/1.8/test/unit/ui/console/testrunner.rb:41:in start’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/ui/testrunnerutilities.rb:29:in
run' from /home/ruby/187p352/lib/ruby/1.8/test/unit/autorunner.rb:216:in run’
from
/home/ruby/187p352/lib/ruby/1.8/test/unit/autorunner.rb:12:in `run’
from /home/ruby/187p352/lib/ruby/1.8/test/unit.rb:279
from tc_pipeline.rb:29

You don’t pass the block.

On 9 August 2011 16:00, Tanaka A. [email protected] wrote:

I guess I could construct the pipeline in a single method but why
would inserting a method call break otherwise working code is a
mystery.

You don’t pass the block.

Yes, that’s missing.

Thanks

Michal