in lib/puma/reactor.rb [129:293]
def run_internal
monitors = @monitors
selector = @selector
while true
begin
ready = selector.select @sleep_for
rescue IOError => e
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
if monitors.any? { |mon| mon.value.closed? }
STDERR.puts "Error in select: #{e.message} (#{e.class})"
STDERR.puts e.backtrace
monitors.reject! do |mon|
if mon.value.closed?
selector.deregister mon.value
true
end
end
retry
else
raise
end
end
if ready
ready.each do |mon|
if mon.value == @ready
@mutex.synchronize do
case @ready.read(1)
when "*"
@input.each do |c|
mon = nil
begin
begin
mon = selector.register(c, :r)
rescue ArgumentError
monitors.delete_if { |submon| submon.value.to_io == c.to_io }
selector.deregister(c)
mon = selector.register(c, :r)
end
rescue IOError
else
mon.value = c
@timeouts << mon if c.timeout_at
monitors << mon
end
end
@input.clear
@timeouts.sort! { |a,b| a.value.timeout_at <=> b.value.timeout_at }
calculate_sleep
when "c"
monitors.reject! do |submon|
if submon.value == @ready
false
else
submon.value.close
begin
selector.deregister submon.value
rescue IOError
end
true
end
end
when "!"
return
end
end
else
c = mon.value
if c.timeout_at
@mutex.synchronize do
@timeouts.delete mon
end
end
begin
if c.try_to_finish
@app_pool << c
clear_monitor mon
end
rescue ConnectionError
c.write_error(500)
c.close
clear_monitor mon
rescue MiniSSL::SSLError => e
@server.lowlevel_error(e, c.env)
ssl_socket = c.io
begin
addr = ssl_socket.peeraddr.last
rescue IOError, Errno::EINVAL
addr = "<unknown>"
end
cert = ssl_socket.peercert
c.close
clear_monitor mon
@events.ssl_error @server, addr, cert, e
rescue HttpParserError => e
@server.lowlevel_error(e, c.env)
c.write_error(400)
c.close
clear_monitor mon
@events.parse_error @server, c.env, e
rescue StandardError => e
@server.lowlevel_error(e, c.env)
c.write_error(500)
c.close
clear_monitor mon
end
end
end
end
unless @timeouts.empty?
@mutex.synchronize do
now = Time.now
while @timeouts.first.value.timeout_at < now
mon = @timeouts.shift
c = mon.value
c.write_error(408) if c.in_data_phase
c.close
clear_monitor mon
break if @timeouts.empty?
end
calculate_sleep
end
end
end
end