Module: Strelka::SignalHandling

Included in:
MultiRunner
Defined in:
lib/strelka/signal_handling.rb

Overview

A module containing signal-handling logic for the 'start' command line.

Instance Method Summary collapse

Instance Method Details

#ignore_signals(*signals) ⇒ Object

Set all signal handlers to ignore.



91
92
93
94
95
96
97
# File 'lib/strelka/signal_handling.rb', line 91

def ignore_signals( *signals )
	self.log.debug "Ignoring signals."
	signals.each do |sig|
		next if sig == :CHLD
		Signal.trap( sig, :IGNORE )
	end
end

#reset_signal_traps(*signals) ⇒ Object

Set the signal handlers back to their defaults.



101
102
103
104
105
106
# File 'lib/strelka/signal_handling.rb', line 101

def reset_signal_traps( *signals )
	self.log.debug "Restoring default signal handlers."
	signals.each do |sig|
		Signal.trap( sig, :DEFAULT )
	end
end

#set_signal_traps(*signals) ⇒ Object

Set up signal handlers for common signals that will shut down, restart, etc.



79
80
81
82
83
84
85
86
87
# File 'lib/strelka/signal_handling.rb', line 79

def set_signal_traps( *signals )
	self.log.debug "Setting up deferred signal handlers."
	signals.each do |sig|
		Signal.trap( sig ) do
			Thread.main[:signal_queue] << sig
			self.wake_up
		end
	end
end

#set_up_signal_handlingObject

Set up data structures for signal handling.



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/strelka/signal_handling.rb', line 26

def set_up_signal_handling
	# Self-pipe for deferred signal-handling (ala djb:
	# http://cr.yp.to/docs/selfpipe.html)
	reader, writer       = IO.pipe
	reader.close_on_exec = true
	writer.close_on_exec = true
	@selfpipe            = { reader: reader, writer: writer }

	# Set up a global signal queue
	Thread.main[:signal_queue] = []
end

#simulate_signal(signal) ⇒ Object

Simulate the receipt of the specified signal (probably only useful in testing).



111
112
113
114
# File 'lib/strelka/signal_handling.rb', line 111

def simulate_signal( signal )
	Thread.main[:signal_queue] << signal.to_sym
	self.wake_up
end

#wait_for_signals(timeout = nil) ⇒ Object

The body of the signal handler. Wait for at least one signal to arrive and handle it, or timeout and return if a timeout integer is provided. This should be called inside a loop, either in its own thread or in another loop that doesn't block anywhere else. Returns true if a signal was handled, or false if a timeout occurred.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/strelka/signal_handling.rb', line 44

def wait_for_signals( timeout=nil )

	# Wait on the selfpipe for signals
	# self.log.debug "  waiting for the selfpipe"
	fds = IO.select( [@selfpipe[:reader]], [], [], timeout )
	begin
		rval = @selfpipe[:reader].read_nonblock( 11 )
		self.log.debug "    read from the selfpipe: %p" % [ rval ]
	rescue Errno::EAGAIN, Errno::EINTR => err
		# ignore
	end

	# Look for any signals that arrived and handle them
	while sig = Thread.main[:signal_queue].shift
		self.log.debug "  got a queued signal: %p" % [ sig ]
		self.handle_signal( sig )
	end

	return fds ? true : false
end

#wake_upObject

Wake the main thread up through the self-pipe. Note: since this is a signal-handler method, it needs to be re-entrant.



68
69
70
71
72
73
74
75
# File 'lib/strelka/signal_handling.rb', line 68

def wake_up
	@selfpipe[:writer].write_nonblock('.')
rescue Errno::EAGAIN
	# Ignore.
rescue Errno::EINTR
	# Repeated signal. :TODO: Does this need a counter?
	retry
end

#with_signal_handler(*signals) ⇒ Object

Wrap a block in signal-handling.



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/strelka/signal_handling.rb', line 12

def with_signal_handler( *signals )
	self.set_up_signal_handling
	self.set_signal_traps( *signals )
	self.start_signal_handler

	return yield

ensure
	self.stop_signal_handler
	self.reset_signal_traps( *signals )
end