Class: FFI::Libfuse::Ackbar
- Inherits:
-
Object
- Object
- FFI::Libfuse::Ackbar
- Defined in:
- lib/ffi/libfuse/ackbar.rb
Overview
Its a trap!
Implements the self-pipe trick for handling signals in multi-threaded ruby programs
Instance Attribute Summary collapse
-
#pr ⇒ IO
readonly
Read side of the self-pipe.
Class Method Summary collapse
-
.trap(traps, force: false) {|signals| ... } ⇒ Object
Run a block with the given traps, restoring the original traps on completion.
Instance Method Summary collapse
-
#initialize(traps, force: false, signal: Signal) ⇒ Ackbar
constructor
A new instance of Ackbar.
-
#monitor(name: 'SignalMonitor') ⇒ Thread
Start a thread to monitor for signals optionally yields between signals.
-
#next ⇒ Boolean, Array<String,Object>
Handle the next available signal on the pipe (without blocking).
-
#restore ⇒ Object
(also: #close)
Restore traps as they were at #new and close the write side of the pipe.
Constructor Details
#initialize(traps, force: false, signal: Signal) ⇒ Ackbar
Returns a new instance of Ackbar.
35 36 37 38 39 40 41 |
# File 'lib/ffi/libfuse/ackbar.rb', line 35 def initialize(traps, force: false, signal: Signal) @signal = signal @traps = traps.transform_keys { |k| signame(k) } @pr, @pw = ::IO.pipe @monitor = nil @restore = @traps.to_h { |sig, handler| [sig, trap(sig, handler, force: force)] } end |
Instance Attribute Details
#pr ⇒ IO (readonly)
Read side of the self-pipe
16 17 18 |
# File 'lib/ffi/libfuse/ackbar.rb', line 16 def pr @pr end |
Class Method Details
.trap(traps, force: false) {|signals| ... } ⇒ Object
Run a block with the given traps, restoring the original traps on completion
23 24 25 26 27 28 |
# File 'lib/ffi/libfuse/ackbar.rb', line 23 def trap(traps, force: false) signals = new(traps, force: force) yield signals ensure signals&.restore end |
Instance Method Details
#monitor(name: 'SignalMonitor') ⇒ Thread
Start a thread to monitor for signals optionally yields between signals
72 73 74 75 76 77 78 79 80 |
# File 'lib/ffi/libfuse/ackbar.rb', line 72 def monitor(name: 'SignalMonitor') @monitor ||= Thread.new do Thread.current.name = name loop do @pr.wait_readable(block_given? ? yield : nil) break unless self.next end end end |
#next ⇒ Boolean, Array<String,Object>
Handle the next available signal on the pipe (without blocking)
46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/ffi/libfuse/ackbar.rb', line 46 def next signame = signal.signame(@pr.read_nonblock(1).unpack1('c')) t = @traps[signame] [signame, t.arity.zero? ? t.call : t.call(signame)] rescue EOFError # the signal pipe writer is closed - we are exiting. @pr.close false rescue Errno::EWOULDBLOCK, Errno::EAGAIN # oh well... true end |
#restore ⇒ Object Also known as: close
Restore traps as they were at #new and close the write side of the pipe
60 61 62 63 64 65 |
# File 'lib/ffi/libfuse/ackbar.rb', line 60 def restore @restore.each_pair { |signame, handler| signal.trap(signame, handler) } @restore = nil @pw.close @monitor&.join end |