1 # -*- encoding: binary -*-
2 require 'rainbows/fiber/io'
7 # blocked readers (key: Rainbows::Fiber::IO object, value is irrelevant)
10 # blocked writers (key: Rainbows::Fiber::IO object, value is irrelevant)
13 # sleeping fibers go here (key: Fiber object, value: wakeup time)
16 # puts the current Fiber into uninterruptible sleep for at least
17 # +seconds+. Unlike Kernel#sleep, this it is not possible to sleep
18 # indefinitely to be woken up (nobody wants that in a web server,
20 def self.sleep(seconds)
21 ZZ[::Fiber.current] = Time.now + seconds
25 # base module used by FiberSpawn and FiberPool
27 include Rainbows::Base
29 # the scheduler method that powers both FiberSpawn and FiberPool
30 # concurrency models. It times out idle clients and attempts to
31 # schedules ones that were blocked on I/O. At most it'll sleep
32 # for one second (returned by the schedule_sleepers method) which
37 RD.keys.each { |c| c.f.resume } # attempt to time out idle clients
39 Kernel.select(RD.keys.concat(LISTENERS), WR.keys, nil, t) or return
42 rescue Errno::EBADF, TypeError
47 # active writers first, then _all_ readers for keepalive timeout
48 ret[1].concat(RD.keys).each { |c| c.f.resume }
50 # accept is an expensive syscall, filter out listeners we don't want
51 (ret.first & LISTENERS).each(&block)
54 # wakes up any sleepers that need to be woken and
55 # returns an interval to IO.select on
59 ZZ.delete_if { |fib, time|
68 max.nil? || max > (now + 1) ? 1 : max - now
71 def process_client(client)
74 buf = client.read_timeout or return
78 remote_addr = TCPSocket === io ? io.peeraddr.last : LOCALHOST
81 while ! hp.headers(env, buf)
82 buf << (client.read_timeout or return)
85 env[CLIENT_IO] = client
86 env[RACK_INPUT] = 0 == hp.content_length ?
87 HttpRequest::NULL_IO : TeeInput.new(client, env, hp, buf)
88 env[REMOTE_ADDR] = remote_addr
89 response = APP.call(env.update(RACK_DEFAULTS))
91 if 100 == response.first.to_i
92 client.write(EXPECT_100_RESPONSE)
93 env.delete(HTTP_EXPECT)
94 response = APP.call(env)
97 alive = hp.keepalive? && G.alive
98 out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if hp.headers?
99 HttpResponse.write(client, response, out)
100 end while alive and hp.reset.nil? and env.clear
108 io.close unless io.closed?