"jonleighton (Jon Leighton)" <j / jonathanleighton.com> wrote:
> Issue #8080 has been updated by jonleighton (Jon Leighton).
> normalperson (Eric Wong) wrote:
> >  Looking at your workaround, I think a better one is "watcher.to_io"
> >  method needs to memoize its return value.
> >  
> >  I think Ruby expects the return value of obj.to_io to be persistent
> >  for the lifetime of obj.
> >  
> >  Making IO.select cache the value of to_io internally might be alright...
> 
> It seems that IO.select *does* cache the value of to_io internally. At least that seems to be the case from https://gist.github.com/jonleighton/5172263.
> 
> Running the script prints "to_io" once and then hangs.

That's because nothing else is running while IO.select is running.
IO.select does not cache, it accesses once the data once.
See comments below:

---------------------------------8<-------------------------------
class Foo
  def to_io
    puts "to_io"
    IO.pipe.first
   end
end
n = 0

trap(:USR1) { n += 1 }

# Generate garbage to trigger GC, and then EINTR for select()
Thread.new do
  loop do
    # make some garbage here
    (1..1000000).each { |z| z.to_s.dup }
    puts "KILL #{n}"
    Process.kill("USR1", $$)
  end
end

# This will now return empty arrays
# If you swap Foo.new for $stdin, this will never return (as expected)
p IO.select([Foo.new])
---------------------------------8<-------------------------------