Class: OsVm::Machine::QemuReaper
- Inherits:
-
Object
- Object
- OsVm::Machine::QemuReaper
- Defined in:
- lib/osvm/machine.rb
Overview
Owns all wait and signal operations for one QEMU child. A nonblocking wait is always performed before pending signals are sent. If the child exits between that wait and Process.kill, it remains this process's unreaped zombie, so its PID cannot be reused for an unrelated process.
Constant Summary collapse
- POLL_INTERVAL =
0.01
Instance Attribute Summary collapse
-
#pid ⇒ Object
readonly
protected
Returns the value of attribute pid.
Instance Method Summary collapse
- #deliver_signals ⇒ Object protected
-
#initialize(pid, &on_exit) ⇒ QemuReaper
constructor
A new instance of QemuReaper.
- #join(timeout = nil) ⇒ Object
- #mark_reaped ⇒ Object protected
- #reap ⇒ Object protected
- #run ⇒ Object protected
-
#signal(signal) ⇒ Boolean
Request a signal from the sole child owner.
- #start ⇒ Object
Constructor Details
#initialize(pid, &on_exit) ⇒ QemuReaper
Returns a new instance of QemuReaper.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/osvm/machine.rb', line 30 def initialize(pid, &on_exit) @pid = pid @on_exit = on_exit @mutex = Mutex.new @condition = ConditionVariable.new @signals = [] @reaped = false @started = false @start = Queue.new @thread = Thread.new do @start.pop run end end |
Instance Attribute Details
#pid ⇒ Object (readonly, protected)
Returns the value of attribute pid.
84 85 86 |
# File 'lib/osvm/machine.rb', line 84 def pid @pid end |
Instance Method Details
#deliver_signals ⇒ Object (protected)
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/osvm/machine.rb', line 116 def deliver_signals pending = @mutex.synchronize do next [] if @reaped @signals.shift(@signals.length) end pending.each do |signal, response| result = begin Process.kill(signal, pid) true rescue Errno::ESRCH false rescue StandardError => e e end response << result end end |
#join(timeout = nil) ⇒ Object
77 78 79 80 |
# File 'lib/osvm/machine.rb', line 77 def join(timeout = nil) start @thread.join(timeout) && self end |
#mark_reaped ⇒ Object (protected)
136 137 138 139 140 141 142 |
# File 'lib/osvm/machine.rb', line 136 def mark_reaped pending = @mutex.synchronize do @reaped = true @signals.shift(@signals.length) end pending.each { |entry| entry.last << false } end |
#reap ⇒ Object (protected)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/osvm/machine.rb', line 92 def reap status = nil loop do waited = Process.waitpid2(pid, Process::WNOHANG) if waited status = waited.last mark_reaped break end deliver_signals @mutex.synchronize do @condition.wait(@mutex, POLL_INTERVAL) if @signals.empty? && !@reaped end end status rescue Errno::ECHILD # No signal may be sent once ownership can no longer be proven. mark_reaped nil end |
#run ⇒ Object (protected)
86 87 88 89 90 |
# File 'lib/osvm/machine.rb', line 86 def run @on_exit.call(reap) ensure mark_reaped end |
#signal(signal) ⇒ Boolean
Request a signal from the sole child owner.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/osvm/machine.rb', line 59 def signal(signal) start response = Queue.new queued = @mutex.synchronize do next false if @reaped @signals << [signal, response] @condition.signal true end return false unless queued result = response.pop raise result if result.is_a?(Exception) result end |
#start ⇒ Object
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/osvm/machine.rb', line 45 def start activate = @mutex.synchronize do next false if @started @started = true true end @start << true if activate self end |