diff options
author | Eric Wong <normalperson@yhbt.net> | 2014-01-27 16:49:14 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2014-01-29 08:43:17 +0000 |
commit | 5ae77e8ce4c439cdfdf1cbaee6a74fcda0b468b1 (patch) | |
tree | 03d3838d2f20b5c35146f1ad6dba82bd165e2704 /lib | |
parent | b3181b132f7f1e5838271f0b20df6fcbba004246 (diff) | |
download | unicorn-5ae77e8ce4c439cdfdf1cbaee6a74fcda0b468b1.tar.gz |
This protects us from two problems: 1) we (or our app) somehow called IO#close on one of the sockets we listen on without removing it from the readers array. We'll ignore IOErrors from IO#close and assume we wanted to close it. 2) our SIGQUIT handler is interrupted by itself. This can happen as a fake signal from the master could be handled and a real signal from an outside user is sent to us (e.g. from unicorn-worker-killer) or if a user uses the killall(1) command.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/unicorn/http_server.rb | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb index ae8ad13..2052d53 100644 --- a/lib/unicorn/http_server.rb +++ b/lib/unicorn/http_server.rb @@ -591,6 +591,13 @@ class Unicorn::HttpServer EXIT_SIGS = [ :QUIT, :TERM, :INT ] WORKER_QUEUE_SIGS = QUEUE_SIGS - EXIT_SIGS + def nuke_listeners!(readers) + # only called from the worker, ordering is important here + tmp = readers.dup + readers.replace([false]) # ensure worker does not continue ASAP + tmp.each { |io| io.close rescue nil } # break out of IO.select + end + # gets rid of stuff the worker has no business keeping track of # to free some resources and drops all sig handlers. # traps for USR1, USR2, and HUP may be set in the after_fork Proc @@ -618,7 +625,7 @@ class Unicorn::HttpServer @after_fork = @listener_opts = @orig_app = nil readers = LISTENERS.dup readers << worker - trap(:QUIT) { readers.each { |io| io.close }.replace([false]) } + trap(:QUIT) { nuke_listeners!(readers) } readers end @@ -677,7 +684,7 @@ class Unicorn::HttpServer worker.tick = Time.now.to_i ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0] rescue => e - redo if nr < 0 + redo if nr < 0 && readers[0] Unicorn.log_error(@logger, "listen loop error", e) if readers[0] end while readers[0] end |