Issue #6154 has been updated by Charles Nutter. I should have mentioned that JRuby has been running this way for a while (on master) and we have had no reports of incompatibility. The concrete subclass is_a EAGAIN and is_a WaitReadable, so all typical exception-handling patterns work correctly. The only cases that break are cases that check e.class == EAGAIN, which is probably not a good pattern anyway. ---------------------------------------- Bug #6154: Eliminate extending WaitReadable/Writable at runtime https://bugs.ruby-lang.org/issues/6154#change-24631 Author: Charles Nutter Status: Open Priority: Normal Assignee: Category: Target version: ruby -v: 2.0.0dev The nonblocking IO operations started extending WaitReadable or WaitWritable into the Errno::EAGAIN instance some time during the 1.9 series. This has a rather high cost, since a singleton class must be created and the global method cache must be flushed. The attached patch instead creates two new classes of the following form, and raises them rather than raising a singleton EAGAIN: class IO::EAGAINReadable < Errno::EAGAIN include WaitReadable end class IO::EAGAINWritable < Errno::EAGAIN include WaitWritable end The performance of repeatedly doing unsuccessful nonblocking reads improves by about 20%: BEFORE: system ~/projects/ruby $ ./ruby2.0.0 -rbenchmark -rsocket -e "sock = TCPSocket.new('localhost', 22); 10.times { puts Benchmark.measure { 100_000.times { begin; sock.read_nonblock(10); rescue IO::WaitReadable; end } } }" 1.210000 0.110000 1.320000 ( 1.328921) 1.220000 0.120000 1.340000 ( 1.326136) 1.220000 0.110000 1.330000 ( 1.334026) 1.230000 0.110000 1.340000 ( 1.349927) 1.310000 0.130000 1.440000 ( 1.426608) 1.210000 0.110000 1.320000 ( 1.333530) 1.220000 0.120000 1.340000 ( 1.330352) 1.230000 0.110000 1.340000 ( 1.350455) 1.220000 0.120000 1.340000 ( 1.327550) 1.220000 0.110000 1.330000 ( 1.337785) AFTER: system ~/projects/ruby $ ./ruby2.0.0 -rbenchmark -rsocket -e "sock = TCPSocket.new('localhost', 22); 10.times { puts Benchmark.measure { 100_000.times { begin; sock.read_nonblock(10); rescue IO::WaitReadable; end } } }" 0.980000 0.110000 1.090000 ( 1.092166) 1.010000 0.120000 1.130000 ( 1.129877) 1.090000 0.120000 1.210000 ( 1.202066) 0.960000 0.110000 1.070000 ( 1.076274) 0.970000 0.100000 1.070000 ( 1.078000) 0.970000 0.110000 1.080000 ( 1.078156) 0.970000 0.110000 1.080000 ( 1.078005) 0.970000 0.110000 1.080000 ( 1.078266) 0.980000 0.110000 1.090000 ( 1.093039) 1.000000 0.110000 1.110000 ( 1.112519) This benchmark does not show the hidden cost of constantly invalidating the global method cache. I also modified a similar case in OpenSSL, where it previously created an SSLError and extended WaitReadable into it. -- http://bugs.ruby-lang.org/