Class: Smith::SelfPipe

Inherits:
Object
  • Object
show all
Includes:
Logger
Defined in:
lib/smith/self_pipe.rb

Instance Method Summary collapse

Methods included from Logger

included

Constructor Details

#initialize(agent) ⇒ SelfPipe

Returns a new instance of SelfPipe.



6
7
8
9
10
11
12
13
14
# File 'lib/smith/self_pipe.rb', line 6

def initialize(agent)
  @agent = agent

  @signal_handlers = Hash.new { |h,k| h[k] = Array.new }
  @signal_handler_queue = []
  @signal_handler_pipe_reader, @signal_handler_pipe_writer = IO.pipe

  setup_signal_handlers
end

Instance Method Details

#install_signal_handler(signal, position = :end, &blk) ⇒ Object

Adds a signal handler proc to the list of signal_handlers. When a signal is received all signal handlers are called in reverse order.

Parameters:

  • signal (Integer)

    the signal number.

  • position (Symbol) (defaults to: :end)
    :first|:last

    where on the signal handler stack

    to put the handler proc.

Raises:

  • (ArgumentError)

See Also:

  • for a full list of available signals on a system.


24
25
26
27
28
29
30
31
32
33
34
# File 'lib/smith/self_pipe.rb', line 24

def install_signal_handler(signal, position=:end, &blk)
  raise ArgumentError, "Unknown position: #{position}" if ![:beginning, :end].include?(position)
  logger.debug { "Installing signal handler for #{signal}" }

  @signal_handlers[signal].insert((position == :beginning) ? 0 : -1, blk)

  Signal.trap(signal) {
    @signal_handler_pipe_writer.write_nonblock('.')
    @signal_handler_queue << signal
  }
end

#setup_signal_handlersObject

Set up the mechanics required to implement the self pipe trick.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/smith/self_pipe.rb', line 37

def setup_signal_handlers
  # The Module declaration here will only close over local variables so we
  # need to assign self to a local variable to get access to the agent itself.
  clazz = self

  EM.attach(@signal_handler_pipe_reader, Module.new {
    define_method :receive_data do |_|

      handlers = clazz.instance_variable_get(:@signal_handlers)
      queue = clazz.instance_variable_get(:@signal_handler_queue)
      signal = queue.pop

      clazz.send(:logger).debug { "Running signal handlers for: #{signal}" }
      handlers[signal].each { |handler| handler.call(signal) }
    end
  })
end