diff options
Diffstat (limited to 'lib/rainbows/rev')
-rw-r--r-- | lib/rainbows/rev/master.rb | 29 | ||||
-rw-r--r-- | lib/rainbows/rev/thread.rb | 53 |
2 files changed, 82 insertions, 0 deletions
diff --git a/lib/rainbows/rev/master.rb b/lib/rainbows/rev/master.rb new file mode 100644 index 0000000..5c112c6 --- /dev/null +++ b/lib/rainbows/rev/master.rb @@ -0,0 +1,29 @@ +# -*- encoding: binary -*- +require 'rainbows/rev' + +RUBY_VERSION =~ %r{\A1\.8} && ::Rev::VERSION < "0.3.2" and + warn "Rainbows::RevThreadSpawn + Rev (< 0.3.2)" \ + " does not work well under Ruby 1.8" + +module Rainbows + + module Rev + class Master < ::Rev::AsyncWatcher + + def initialize(queue) + super() + @queue = queue + end + + def <<(output) + @queue << output + signal + end + + def on_signal + client, response = @queue.pop + client.response_write(response) + end + end + end +end diff --git a/lib/rainbows/rev/thread.rb b/lib/rainbows/rev/thread.rb new file mode 100644 index 0000000..8fa43ac --- /dev/null +++ b/lib/rainbows/rev/thread.rb @@ -0,0 +1,53 @@ +# -*- encoding: binary -*- +require 'thread' +require 'rainbows/rev/master' + +module Rainbows + module Rev + + class ThreadClient < Client + + def app_call + KATO.delete(self) + disable + @env[RACK_INPUT] = @input + @input = nil # not sure why, @input seems to get closed otherwise... + app_dispatch # must be implemented by subclass + end + + # this is only called in the master thread + def response_write(response) + enable + alive = @hp.keepalive? && G.alive + out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if @hp.headers? + DeferredResponse.write(self, response, out) + return quit unless alive && G.alive + + @env.clear + @hp.reset + @state = :headers + # keepalive requests are always body-less, so @input is unchanged + if @hp.headers(@env, @buf) + @input = HttpRequest::NULL_IO + app_call + else + KATO[self] = Time.now + end + end + + # fails-safe application dispatch, we absolutely cannot + # afford to fail or raise an exception (killing the thread) + # here because that could cause a deadlock and we'd leak FDs + def app_response + begin + @env[REMOTE_ADDR] = @remote_addr + APP.call(@env.update(RACK_DEFAULTS)) + rescue => e + Error.app(e) # we guarantee this does not raise + [ 500, {}, [] ] + end + end + + end + end +end |