From: Jesse Merriman Date: 2007-06-24T07:10:26+09:00 Subject: Non-blocking IO & Maxima Ok, here's something that seems wierd. While writing some code to call Maxima (http://maxima.sourceforge.net/) from Ruby, I wrote the following: class IO # Read a line without blocking. If there isn't a line to be read, return # nil. def readline_nonblock line = '' begin char = read_nonblock 1 # A larger read would surely be more efficient. while char != "\n" line += char char = read_nonblock 1 end rescue Errno::EAGAIN $stderr.puts '*** rescued EAGAIN' line.reverse.each_byte { |c| ungetc(c) } # Replace partial line. line = nil rescue EOFError line = nil end line end # Yield once for every line recieved from readline_nonblocking, until it # returns nil. def each_nonblock line = readline_nonblock while not line.nil? yield line line = readline_nonblock end end end The wierdness is that this code behaves differently depending on whether its called from IRB's toplevel or within a method. Here's some expected results: irb(main):001:0> MaximaString = "maxima --batch-string='1+1;'" => "maxima --batch-string='1+1;'" irb(main):002:0> ios = IO.popen MaximaString => # irb(main):003:0> ios.each_nonblock { |line| puts line } i i i i i i i ooooo o ooooooo ooooo ooooo I I I I I I I 8 8 8 8 8 o 8 8 I \ `+' / I 8 8 8 8 8 8 \ `-+-' / 8 8 8 ooooo 8oooo `-__|__-' 8 8 8 8 8 | 8 o 8 8 o 8 8 ------+------ ooooo 8oooooo ooo8ooo ooooo 8 Copyright (c) Bruno Haible, Michael Stoll 1992, 1993 Copyright (c) Bruno Haible, Marcus Daniels 1994-1997 Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998 Copyright (c) Bruno Haible, Sam Steingold 1999-2003 -------------------------------------------------------------- Maxima 5.9.1 http://maxima.sourceforge.net Using Lisp CLISP 2.38 (2006-01-24) Distributed under the GNU Public License. See the file COPYING. Dedicated to the memory of William Schelter. This is a development version of Maxima. The function bug_report() provides bug reporting information. (%i1) 1 + 1 (%o1) 2 => nil And now the unexpected: irb(main):004:0> def foo irb(main):005:1> ios = IO.popen MaximaString irb(main):006:1> ios.each_nonblock { |line| puts line } irb(main):007:1> end => nil irb(main):008:0> foo *** rescued EAGAIN => nil WTF? If I use "ls" instead of "maxima --batch-string='1+1;'" then it works it both cases. So is this a problem with Maxima, Ruby, or my code? (Oh, and I know that non-blocking IO isn't required for the specific example above, but I'd still like it to work to be more general in code I haven't posted. And to understand why this is happening.) -- Jesse Merriman jessemerriman@warpmail.net http://www.jessemerriman.com/