From: Robert Klemme Date: 2009-03-16T16:37:36+09:00 Subject: Re: does IO.read block? On 16.03.2009 00:17, Michael Malone wrote: > Robert Klemme wrote: >>> rescue Exception => error >>> ex_string = Marshal.dump(error) >>> ex_size = ex_string.bytesize >>> bytes_written = 0 >>> while bytes_written < ex_size >>> bytes_written += write_end.write(ex_string.slice!(bytes_written)) >>> end >>> ensure >>> write_end.close >> You do not seem to open the stream in this context, why do you close >> it here? Or do you have a pattern like > that code is inside the block passed to fork(), so the write_end needs > to be closed so the parent process reads an EOF. The pipe is opened > prior to the fork() call, so the fd should be copied to the child > process, thus the parent process would block indefinitely waiting for > the EOF. Ah, I see. >> IMHO you can simplify that do >> >> rescue Exception => error >> Marshal.dump(error, write_end) >> end >> >> Which should also be more efficient since the looping is done in C code. > Thanks, I've applied that. >> But again, I would just do >> >> obj = Marshal.read(read_end) >> >> Which, again is more efficient since you do not need the additional >> buffer and looping is done in C code. > I need the additional buffer because an exception is not always thrown > so attempting to unmarshal an empty string causes problems Well, you could just serialize nil or the result of the computation in the OK case. That simplifies handling in the calling process plus you can get the result as a Ruby object. You then only need to test whether what you got is an instance of Exception or not. > My problem still exists. :( I didn't get into the details of the > specifics because I haven't proved where it exists. I just got excited > when I saw that as a potential problem area and figured it needed fixing > because it would bite me sooner or later. One problem that could hit you is that you might not get the concurrency right: you need to make sure that stderr and stdout are read concurrently (if there can be output on both) because if the pipe on one of them fills up your child process is blocked. Maybe your issue lies in that area. > Back to the drawing board until I have a better question... :-) > Wait, I just re-read your email. The looping is done in C. So that > implies I do need to loop on the read_end.read() call? Efficiency is > not a massive concern for me - correctness is. No, you do not need to loop for IO#read since the docs say it will read all the way to the end of the stream when leaving out the length argument. Kind regards robert