diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-07-03 22:30:48 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-07-04 01:13:42 -0700 |
commit | ff0fc020fe30798e52d96cc11b445c76d9822422 (patch) | |
tree | 986dfb9b874de6801646e86ea4ba7654b61bd59b /lib/unicorn/app/inetd.rb | |
parent | 672befaa67ace119c07ee346124526c1e0c4a1f1 (diff) | |
download | unicorn-ff0fc020fe30798e52d96cc11b445c76d9822422.tar.gz |
There's a small memory reduction to be had when forking oodles of processes and the Perl hacker in me still gets confused into thinking those are arrays...
Diffstat (limited to 'lib/unicorn/app/inetd.rb')
-rw-r--r-- | lib/unicorn/app/inetd.rb | 58 |
1 files changed, 28 insertions, 30 deletions
diff --git a/lib/unicorn/app/inetd.rb b/lib/unicorn/app/inetd.rb index e22b308..580b456 100644 --- a/lib/unicorn/app/inetd.rb +++ b/lib/unicorn/app/inetd.rb @@ -4,65 +4,66 @@ # this class *must* be used with Rack::Chunked module Unicorn::App - class Inetd + class Inetd < Struct.new(:cmd) - class CatBody + class CatBody < Struct.new(:errors, :err_rd, :out_rd, :pid_map) def initialize(env, cmd) - @cmd = cmd - @input, @errors = env['rack.input'], env['rack.errors'] + self.errors = env['rack.errors'] in_rd, in_wr = IO.pipe - @err_rd, err_wr = IO.pipe - @out_rd, out_wr = IO.pipe + self.err_rd, err_wr = IO.pipe + self.out_rd, out_wr = IO.pipe - @cmd_pid = fork { + cmd_pid = fork { inp, out, err = (0..2).map { |i| IO.new(i) } inp.reopen(in_rd) out.reopen(out_wr) err.reopen(err_wr) - [ in_rd, in_wr, @err_rd, err_wr, @out_rd, out_wr ].each { |io| - io.close - } + [ in_rd, in_wr, err_rd, err_wr, out_rd, out_wr ].each { |i| i.close } exec(*cmd) } [ in_rd, err_wr, out_wr ].each { |io| io.close } - [ in_wr, @err_rd, @out_rd ].each { |io| io.binmode } + [ in_wr, err_rd, out_rd ].each { |io| io.binmode } in_wr.sync = true # Unfortunately, input here must be processed inside a seperate # thread/process using blocking I/O since env['rack.input'] is not # IO.select-able and attempting to make it so would trip Rack::Lint - @inp_pid = fork { - [ @err_rd, @out_rd ].each { |io| io.close } + inp_pid = fork { + input = env['rack.input'] + [ err_rd, out_rd ].each { |io| io.close } buf = Unicorn::Z.dup - # this is dependent on @input.read having readpartial semantics: - while @input.read(16384, buf) + # this is dependent on input.read having readpartial semantics: + while input.read(16384, buf) in_wr.write(buf) end in_wr.close } in_wr.close + self.pid_map = { + inp_pid => 'input streamer', + cmd_pid => cmd.inspect, + } end def each(&block) - buf = Unicorn::Z.dup begin - rd, = IO.select([@err_rd, @out_rd]) + rd, = IO.select([err_rd, out_rd]) rd && rd.first or next - if rd.include?(@err_rd) + if rd.include?(err_rd) begin - @errors.write(@err_rd.read_nonblock(16384, buf)) + errors.write(err_rd.read_nonblock(16384)) rescue Errno::EINTR rescue Errno::EAGAIN break end while true end - rd.include?(@out_rd) or next + rd.include?(out_rd) or next begin - yield @out_rd.read_nonblock(16384, buf) + yield out_rd.read_nonblock(16384) rescue Errno::EINTR rescue Errno::EAGAIN break @@ -75,15 +76,13 @@ module Unicorn::App end def close - @input = nil - [ [ @cmd.inspect, @cmd_pid ], [ 'input streamer', @inp_pid ] - ].each { |str, pid| + pid_map.each { |pid, str| begin pid, status = Process.waitpid2(pid) status.success? or - @errors.write("#{str}: #{status.inspect} (PID:#{pid})\n") + errors.write("#{str}: #{status.inspect} (PID:#{pid})\n") rescue Errno::ECHILD - @errors.write("Failed to reap #{str} (PID:#{pid})\n") + errors.write("Failed to reap #{str} (PID:#{pid})\n") end } end @@ -91,16 +90,15 @@ module Unicorn::App end def initialize(*cmd) - @cmd = cmd + self.cmd = cmd end def call(env) - expect = env[Unicorn::Const::HTTP_EXPECT] and - /\A100-continue\z/i =~ expect and + /\A100-continue\z/i =~ env[Unicorn::Const::HTTP_EXPECT] and return [ 100, {} , [] ] [ 200, { 'Content-Type' => 'application/octet-stream' }, - CatBody.new(env, @cmd) ] + CatBody.new(env, cmd) ] end end |