I have a file testin
with arbitrary data. I fork, connect stdout
to a pipe to the parent, and exec a dd
to read the file and push it down the pipe. Then two more children are similarly executed with their stdin
s from pipes from the parent. The parent then reads bytes from the first process and writes them to the other two children.
My problem is that the until loop never ends. If I send #closed?
to the pipe from the first process as the condition, it gets stuck in the next #read
waiting for more data after the process has already finished. If I send #eof?
it gets stuck in #eof?
.
Why don't I get an EOF or why isn't the pipe closed? How should I detect that there's no more data?
pipe1r, pipe1w = IO.pipe
pid1 = fork do
$stdout.reopen(pipe1w)
exec 'dd', 'if=testin'
end
pipe2r, pipe2w = IO.pipe
pid2 = fork do
$stdin.reopen(pipe2r)
exec 'dd', 'of=testout1'
end
pipe3r, pipe3w = IO.pipe
pid3 = fork do
$stdin.reopen(pipe3r)
exec 'dd', 'of=testout2'
end
until pipe1r.closed?
byte = pipe1r.read(1)
pipe2w.write(byte)
pipe3w.write(byte)
end
pipe2w.close
pipe3w.close
pid, status = Process.wait2(pid1)
puts 'Process 1 was a ' + (status.success? ? 'success' : 'failure')
pid, status = Process.wait2(pid2)
puts 'Process 2 was a ' + (status.success? ? 'success' : 'failure')
pid, status = Process.wait2(pid3)
puts 'Process 3 was a ' + (status.success? ? 'success' : 'failure')
Solved: From matthewd's answer, pipe1w.close
after forking the first process and using until pipe1r.eof?
as the loop condition fixes it--EOF is received and the loop ends.
You haven't closed pipe1w
in the parent process.
You need a pipe1w.close
before your loop, otherwise the pipe will never be empty: the forked process has stopped writing (and closed its copy), but the parent process could still write to it.