60 lines
2.1 KiB
Ruby
60 lines
2.1 KiB
Ruby
module Vagrant
|
|
module Util
|
|
# Utility class which allows blocks of code to be marked as "busy"
|
|
# with a specified interrupt handler. During busy areas of code, it
|
|
# is often undesirable for SIGINTs to immediately kill the application.
|
|
# This class is a helper to cleanly register callbacks to handle this
|
|
# situation.
|
|
class Busy
|
|
@@registered = []
|
|
@@mutex = Mutex.new
|
|
|
|
class << self
|
|
# Mark a given block of code as a "busy" block of code, which will
|
|
# register a SIGINT handler for the duration of the block. When a
|
|
# SIGINT occurs, the `sig_callback` proc will be called. It is up
|
|
# to the callback to behave properly and exit the application.
|
|
def busy(sig_callback)
|
|
register(sig_callback)
|
|
return yield
|
|
ensure
|
|
unregister(sig_callback)
|
|
end
|
|
|
|
# Registers a SIGINT handler. This typically is called from {busy}.
|
|
# Callbacks are only registered once, so calling this multiple times
|
|
# with the same callback has no consequence.
|
|
def register(sig_callback)
|
|
@@mutex.synchronize do
|
|
registered << sig_callback
|
|
registered.uniq!
|
|
|
|
# Register the handler if this is our first callback.
|
|
Signal.trap("INT") { fire_callbacks } if registered.length == 1
|
|
end
|
|
end
|
|
|
|
# Unregisters a SIGINT handler.
|
|
def unregister(sig_callback)
|
|
@@mutex.synchronize do
|
|
registered.delete(sig_callback)
|
|
|
|
# Remove the signal trap if no more registered callbacks exist
|
|
Signal.trap("INT", "DEFAULT") if registered.empty?
|
|
end
|
|
end
|
|
|
|
# Fires all the registered callbacks.
|
|
def fire_callbacks
|
|
registered.reverse.each { |r| r.call }
|
|
end
|
|
|
|
# Helper method to get access to the class variable. This is mostly
|
|
# exposed for tests. This shouldn't be mucked with directly, since it's
|
|
# structure may change at any time.
|
|
def registered; @@registered; end
|
|
end
|
|
end
|
|
end
|
|
end
|