about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-08-31 07:54:25 +0000
committerEric Wong <normalperson@yhbt.net>2011-08-31 07:54:25 +0000
commit30ab37594677c12a4884d7199d808a8a28832549 (patch)
tree8aacde5d461a4335a96cbb58ef543276f45c6f8f
parent8c3916bfe76224b69e0f20827c4230c4e71cdc86 (diff)
downloadzbatery-30ab37594677c12a4884d7199d808a8a28832549.tar.gz
avoid potential Logger deadlocks in signal handling
If any combination of signals are sent to Zbatery in a short
period of time, the Mutex used by the default Logger
implementation may deadlock since Mutex synchronization is not
reentrant-safe.

By spawning a thread, we can take advantage of the thread-safety
and avoid the reentrancy-safety issue of acquiring a mutex
inside a signal handler.

Users of alternative logger implementations (or monkey-patched
ones) are possibly not affected.  Users of the logger_mp_safe.rb
monkey-patch distributed[1] with unicorn are not affected.

[1] http://unicorn.bogomips.org/examples/logger_mp_safe.rb
-rw-r--r--lib/zbatery.rb16
1 files changed, 9 insertions, 7 deletions
diff --git a/lib/zbatery.rb b/lib/zbatery.rb
index 174ded0..8783fd4 100644
--- a/lib/zbatery.rb
+++ b/lib/zbatery.rb
@@ -75,16 +75,18 @@ module Rainbows
     end
 
     def join
-      trap(:INT) { stop(false) }
-      trap(:TERM) { stop(false) }
-      trap(:QUIT) { stop }
-      trap(:USR1) { reopen_logs }
-      trap(:USR2) { reexec }
-      trap(:HUP) { reexec; stop }
+      trap(:INT) { exit!(0) }
+      trap(:TERM) { exit!(0) }
+      trap(:QUIT) { Thread.new { stop } }
+      trap(:USR1) { Thread.new { reopen_logs } }
+      trap(:USR2) { Thread.new { reexec } }
+      trap(:HUP) { Thread.new { reexec; stop } }
 
       # technically feasible in some cases, just not sanely supportable:
       %w(TTIN TTOU WINCH).each do |sig|
-        trap(sig) { logger.info "SIG#{sig} is not handled by Zbatery" }
+        trap(sig) do
+          Thread.new { logger.info("SIG#{sig} is not handled by Zbatery") }
+        end
       end
 
       if ready_pipe