diff options
-rw-r--r-- | lib/unicorn.rb | 23 | ||||
-rw-r--r-- | lib/unicorn/app/exec_cgi.rb | 9 | ||||
-rw-r--r-- | lib/unicorn/util.rb | 17 |
3 files changed, 29 insertions, 20 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb index aac530b..49435d8 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -54,8 +54,7 @@ module Unicorn 0 => $0.dup, } - Worker = Struct.new(:nr, :tempfile) unless defined?(Worker) - class Worker + class Worker < Struct.new(:nr, :tmp) # worker objects may be compared to just plain numbers def ==(other_nr) self.nr == other_nr @@ -323,7 +322,7 @@ module Unicorn self.pid = @pid.chomp('.oldbin') if @pid proc_name 'master' else - worker = WORKERS.delete(pid) and worker.tempfile.close rescue nil + worker = WORKERS.delete(pid) and worker.tmp.close rescue nil logger.info "reaped #{status.inspect} " \ "worker=#{worker.nr rescue 'unknown'}" end @@ -383,16 +382,16 @@ module Unicorn end # forcibly terminate all workers that haven't checked in in @timeout - # seconds. The timeout is implemented using an unlinked tempfile + # seconds. The timeout is implemented using an unlinked File # shared between the parent process and each worker. The worker - # runs File#chmod to modify the ctime of the tempfile. If the ctime + # runs File#chmod to modify the ctime of the File. If the ctime # is stale for >@timeout seconds, then we'll kill the corresponding # worker. def murder_lazy_workers diff = stat = nil WORKERS.dup.each_pair do |pid, worker| stat = begin - worker.tempfile.stat + worker.tmp.stat rescue => e logger.warn "worker=#{worker.nr} PID:#{pid} stat error: #{e.inspect}" kill_worker(:QUIT, pid) @@ -416,9 +415,7 @@ module Unicorn SIG_QUEUE << :QUIT # forcibly emulate SIGQUIT return end - tempfile = Tempfile.new(nil) # as short as possible to save dir space - tempfile.unlink # don't allow other processes to find or see it - worker = Worker.new(worker_nr, tempfile) + worker = Worker.new(worker_nr, Unicorn::Util.tmpio) @before_fork.call(self, worker) pid = fork { worker_loop(worker) } WORKERS[pid] = worker @@ -466,10 +463,10 @@ module Unicorn proc_name "worker[#{worker.nr}]" START_CTX.clear init_self_pipe! - WORKERS.values.each { |other| other.tempfile.close! rescue nil } + WORKERS.values.each { |other| other.tmp.close rescue nil } WORKERS.clear LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) } - worker.tempfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + worker.tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) @after_fork.call(self, worker) # can drop perms @timeout /= 2.0 # halve it for select() build_app! unless @preload_app @@ -489,7 +486,7 @@ module Unicorn master_pid = Process.ppid # slightly racy, but less memory usage init_worker_process(worker) nr = 0 # this becomes negative if we need to reopen logs - alive = worker.tempfile # tempfile is our lifeline to the master process + alive = worker.tmp # tmp is our lifeline to the master process ready = LISTENERS t = ti = 0 @@ -555,7 +552,7 @@ module Unicorn begin Process.kill(signal, pid) rescue Errno::ESRCH - worker = WORKERS.delete(pid) and worker.tempfile.close rescue nil + worker = WORKERS.delete(pid) and worker.tmp.close rescue nil end end diff --git a/lib/unicorn/app/exec_cgi.rb b/lib/unicorn/app/exec_cgi.rb index 8f81d78..b0fbedc 100644 --- a/lib/unicorn/app/exec_cgi.rb +++ b/lib/unicorn/app/exec_cgi.rb @@ -42,11 +42,8 @@ module Unicorn::App # Calls the app def call(env) - out, err = Tempfile.new(''), Tempfile.new('') - out.unlink - err.unlink + out, err = Unicorn::Util.tmpio, Unicorn::Util.tmpio inp = force_file_input(env) - inp.sync = out.sync = err.sync = true pid = fork { run_child(inp, out, err, env) } inp.close pid, status = Process.waitpid2(pid) @@ -126,9 +123,7 @@ module Unicorn::App elsif inp.size == 0 # inp could be a StringIO or StringIO-like object ::File.open('/dev/null') else - tmp = Tempfile.new('') - tmp.unlink - tmp.binmode + tmp = Unicorn::Util.tmpio # Rack::Lint::InputWrapper doesn't allow sysread :( buf = '' diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb index 2d3f827..d2214b7 100644 --- a/lib/unicorn/util.rb +++ b/lib/unicorn/util.rb @@ -1,4 +1,5 @@ require 'fcntl' +require 'tmpdir' module Unicorn class Util @@ -39,6 +40,22 @@ module Unicorn nr end + # creates and returns a new File object. The File is unlinked + # immediately, switched to binary mode, and userspace output + # buffering is disabled + def tmpio + fp = begin + File.open("#{Dir::tmpdir}/#{rand}", + File::RDWR|File::CREAT|File::EXCL, 0600) + rescue Errno::EEXIST + retry + end + File.unlink(fp.path) + fp.binmode + fp.sync = true + fp + end + end end |