Class: Syskit::RemoteStateGetter Private
- Defined in:
- lib/syskit/remote_state_getter.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Adapter that reads the synchronous state of a remote node asynchronously
It is started in a paused state, waiting for #resume to be called to start polling the remote state
Instance Attribute Summary collapse
-
#current_state ⇒ Object
readonly
private
The newest known state.
-
#exit_condition ⇒ Object
readonly
private
The condition used to make the polling thread quit.
-
#last_read_state ⇒ Object
readonly
private
The last read state.
-
#orocos_task ⇒ Object
readonly
private
The task we're polling.
-
#period ⇒ Object
readonly
private
The polling period in seconds.
-
#poll_thread ⇒ Object
readonly
private
The thread that polls #rtt_state.
-
#poll_thread_error ⇒ Object
readonly
private
The exception that terminated #poll_thread.
-
#poll_thread_exit_sync ⇒ Object
readonly
private
To avoid deadlocking in #wait if the thread quits.
-
#run_event ⇒ Object
readonly
private
Control for pause/resume.
-
#state_queue ⇒ Object
readonly
private
The queue of values read by #poll_thread.
-
#sync_latch ⇒ Object
readonly
private
Holder for the latch that is used by #wait for synchronization.
Instance Method Summary collapse
- #clear ⇒ Object private
-
#connected? ⇒ Boolean
private
Whether the polling thread is alive.
-
#disconnect ⇒ Object
private
Stop polling completely.
-
#initialize(orocos_task, initial_state: nil, period: 0.02) ⇒ RemoteStateGetter
constructor
private
A new instance of RemoteStateGetter.
-
#join ⇒ Object
private
Wait for the poll thread to finish after a #disconnect.
-
#pause ⇒ Object
private
Pause polling until #resume or #disconnect are called.
-
#poll_loop ⇒ Object
private
The internal polling loop.
-
#read ⇒ Object
private
Read either a new or the last read state.
-
#read_new ⇒ Object
private
Read a new state change.
-
#ready? ⇒ Boolean
private
Whether the state reader has read at least one state.
-
#resume ⇒ Object
private
Resume polling after a #pause.
-
#wait ⇒ Object
private
Wait for the current state to be read and return it.
Constructor Details
#initialize(orocos_task, initial_state: nil, period: 0.02) ⇒ RemoteStateGetter
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of RemoteStateGetter
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/syskit/remote_state_getter.rb', line 32 def initialize(orocos_task, initial_state: nil, period: 0.02) @orocos_task = orocos_task @period = period @exit_condition = Concurrent::Event.new @run_event = Concurrent::Event.new @current_state = Concurrent::Atom.new(initial_state) @state_queue = Queue.new @sync_latch = Concurrent::Atom.new(nil) @poll_thread_error = Concurrent::Atom.new(nil) @poll_thread_exit_sync = Mutex.new @last_read_state = nil if initial_state state_queue.push(initial_state) end period = self.period exit_condition.reset @poll_thread = Thread.new do poll_loop end end |
Instance Attribute Details
#current_state ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The newest known state
24 25 26 |
# File 'lib/syskit/remote_state_getter.rb', line 24 def current_state @current_state end |
#exit_condition ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The condition used to make the polling thread quit
14 15 16 |
# File 'lib/syskit/remote_state_getter.rb', line 14 def exit_condition @exit_condition end |
#last_read_state ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The last read state
26 27 28 |
# File 'lib/syskit/remote_state_getter.rb', line 26 def last_read_state @last_read_state end |
#orocos_task ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The task we're polling
10 11 12 |
# File 'lib/syskit/remote_state_getter.rb', line 10 def orocos_task @orocos_task end |
#period ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The polling period in seconds
12 13 14 |
# File 'lib/syskit/remote_state_getter.rb', line 12 def period @period end |
#poll_thread ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The thread that polls #rtt_state
16 17 18 |
# File 'lib/syskit/remote_state_getter.rb', line 16 def poll_thread @poll_thread end |
#poll_thread_error ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The exception that terminated #poll_thread
18 19 20 |
# File 'lib/syskit/remote_state_getter.rb', line 18 def poll_thread_error @poll_thread_error end |
#poll_thread_exit_sync ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
To avoid deadlocking in #wait if the thread quits
30 31 32 |
# File 'lib/syskit/remote_state_getter.rb', line 30 def poll_thread_exit_sync @poll_thread_exit_sync end |
#run_event ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Control for pause/resume
28 29 30 |
# File 'lib/syskit/remote_state_getter.rb', line 28 def run_event @run_event end |
#state_queue ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The queue of values read by #poll_thread
20 21 22 |
# File 'lib/syskit/remote_state_getter.rb', line 20 def state_queue @state_queue end |
#sync_latch ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Holder for the latch that is used by #wait for synchronization
22 23 24 |
# File 'lib/syskit/remote_state_getter.rb', line 22 def sync_latch @sync_latch end |
Instance Method Details
#clear ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
143 144 145 146 147 |
# File 'lib/syskit/remote_state_getter.rb', line 143 def clear state_queue.clear current_state.reset(nil) @last_read_state = nil end |
#connected? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Whether the polling thread is alive
150 151 152 |
# File 'lib/syskit/remote_state_getter.rb', line 150 def connected? !exit_condition.set? end |
#disconnect ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Stop polling completely
After calling #disconnect, the reader cannot be connected again. Use #pause and #resume to temporarily stop polling
170 171 172 173 174 175 |
# File 'lib/syskit/remote_state_getter.rb', line 170 def disconnect # This order ensures that {#poll_thread} will quit immediately if it # was paused exit_condition.set run_event.set end |
#join ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Wait for the poll thread to finish after a #disconnect
178 179 180 |
# File 'lib/syskit/remote_state_getter.rb', line 178 def join poll_thread.join end |
#pause ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Pause polling until #resume or #disconnect are called
155 156 157 |
# File 'lib/syskit/remote_state_getter.rb', line 155 def pause run_event.reset end |
#poll_loop ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
The internal polling loop
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/syskit/remote_state_getter.rb', line 55 def poll_loop # Analysis to avoid deadlocking in {#wait} # # In the ensure block: # - we've had an exception and poll_thread_error is set # - the loop quit because exit_condition was set # # We synchronize the latch (from wait) and we set exit_condition in # the synchronization section to ensure that {#wait} can check for # exit_condition being set and set the latch only if it is not last_state = nil while !exit_condition.set? if latch = sync_latch.value latch.count_down end time = Time.now state = orocos_task.rtt_state if (state != last_state) || !current_state.value current_state.reset(state) state_queue.push(state) last_state = state end if latch latch.count_down sync_latch.reset(nil) end spent = (Time.now - time) if spent < period exit_condition.wait(period - spent) end run_event.wait end rescue Exception => e poll_thread_error.reset(e) ensure poll_thread_exit_sync.synchronize do exit_condition.set if latch = sync_latch.value latch.count_down latch.count_down end end end |
#read ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Read either a new or the last read state
131 132 133 |
# File 'lib/syskit/remote_state_getter.rb', line 131 def read read_new || last_read_state end |
#read_new ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Read a new state change
136 137 138 139 140 141 |
# File 'lib/syskit/remote_state_getter.rb', line 136 def read_new if new_state = state_queue.pop(true) @last_read_state = new_state end rescue ThreadError end |
#ready? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Whether the state reader has read at least one state
126 127 128 |
# File 'lib/syskit/remote_state_getter.rb', line 126 def ready? last_read_state || (state_queue.size > 0) end |
#resume ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resume polling after a #pause
It is safe to call even if the polling is currently active
162 163 164 |
# File 'lib/syskit/remote_state_getter.rb', line 162 def resume run_event.set end |
#wait ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Wait for the current state to be read and return it
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/syskit/remote_state_getter.rb', line 102 def wait latch = poll_thread_exit_sync.synchronize do if !run_event.set? raise ThreadError, "#{self} is paused, cannot call #wait" elsif error = poll_thread_error.value raise error, "#{self}'s poll thread quit with #{error.}, cannot call #wait", (error.backtrace + caller) elsif exit_condition.set? raise ThreadError, "#{self} is quitting, cannot call #wait" end sync_latch.reset(latch = Concurrent::CountDownLatch.new(2)) latch end latch.wait if error = poll_thread_error.value raise error, "#{self}'s poll thread quit with #{error.} during #wait", (error.backtrace + caller) elsif exit_condition.set? raise ThreadError, "#{self}#disconnect called within #wait" else current_state.value end end |