RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
event.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology, University of Utah,
4  Will Cornell Medical College
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 #include <algorithm>
22 #include <future>
23 #include <mutex>
24 
25 #include "event.hpp"
26 
27 #include "debug.hpp"
28 #include "logger.hpp"
29 
30 std::string Event::type_to_string(Event::Type event_type)
31 {
32  std::string return_string;
33  switch (event_type) {
35  return_string = "SYSTEM : period";
36  break;
38  return_string = "SYSTEM : pre period";
39  break;
41  return_string = "SYSTEM : post period";
42  break;
44  return_string = "SYSTEM : Period value requested";
45  break;
47  return_string = "SYSTEM : thread insert";
48  break;
50  return_string = "SYSTEM : thread remove";
51  break;
53  return_string = "SYSTEM : device insert";
54  break;
56  return_string = "SYSTEM : shutdown";
57  break;
59  return_string = "SYSTEM : device remove";
60  break;
62  return_string = "SYSTEM : Thread paused";
63  break;
65  return_string = "SYSTEM : Thread unpaused";
66  break;
68  return_string = "SYSTEM : Device paused";
69  break;
71  return_string = "SYSTEM : Device unpaused";
72  break;
74  return_string = "SYSTEM : parameter change";
75  break;
77  return_string = "SYSTEM : Widget State change";
78  break;
80  return_string = "CONNECTOR : Blocks Connected";
81  break;
83  return_string = "CONNECTOR : Blocks Disconnected";
84  break;
86  return_string = "CONNECTOR : Block list requested";
87  break;
89  return_string = "CONNECTOR : Request for connection info";
90  break;
92  return_string = "CONNECTOR : Request for all connections";
93  break;
95  return_string = "CONNECTOR : Request for block output info";
96  break;
98  return_string = "WIDGET : plugin insert";
99  break;
101  return_string = "WIDGET : plugin remove";
102  break;
104  return_string = "MANAGER : daq query event";
105  break;
107  return_string = "SYSTEM : settings object insert";
108  break;
110  return_string = "SYSTEM : settings object remove";
111  break;
113  return_string = "SYSTEM : open file";
114  break;
116  return_string = "SYSTEM : start recording";
117  break;
119  return_string = "SYSTEM : stop recording";
120  break;
122  return_string = "SYSTEM : async data";
123  break;
125  return_string = "SYSTEM : threshold crossing event";
126  break;
128  return_string = "SYSTEM : start genicam recording";
129  break;
131  return_string = "SYSTEM : pause genicam recording";
132  break;
134  return_string = "SYSTEM : stop genicam recording";
135  break;
137  return_string = "SYSTEM : genicam snap";
138  break;
140  return_string = "WIDGET : Generic Widget Event";
141  break;
143  return_string = "EVENT MANAGER : UI Manager shutdown event";
144  break;
145  case Event::Type::NOOP:
146  return_string = "SYSTEM : no operation";
147  break;
148  default:
149  return_string = "UNKNOWN EVENT!";
150  }
151  return return_string;
152 }
153 
155  : event_type(et)
156 {
157 }
158 
160  : params(obj.params)
161  , event_type(obj.event_type)
162 {
163 }
164 
166 {
167  return Event::type_to_string(this->event_type);
168 }
169 
170 std::any Event::Object::getParam(const std::string& param_name) const
171 {
172  for (const auto& parameter : params) {
173  if (parameter.name == param_name) {
174  return parameter.value;
175  }
176  }
177  return std::any {};
178 }
179 
180 bool Event::Object::paramExists(const std::string& param_name)
181 {
182  bool result = false;
183  for (auto& parameter : params) {
184  if (parameter.name == param_name) {
185  result = true;
186  }
187  }
188  return result;
189 }
190 
191 void Event::Object::setParam(const std::string& param_name,
192  const std::any& param_value)
193 {
194  for (auto& parameter : params) {
195  if (parameter.name == param_name) {
196  parameter.value = param_value;
197  return;
198  }
199  }
200 
201  param temp = {};
202  temp.name = param_name;
203  temp.value = param_value;
204  params.push_back(temp);
205 }
206 
208 {
209  std::unique_lock<std::mutex> done_lock(this->processing_done_mut);
210  this->processing_done_cond.wait(done_lock,
211  [this]() { return this->processed; });
212  // done_lock.unlock();
213 }
214 
216 {
217  std::unique_lock<std::mutex> done_lock(this->processing_done_mut);
218  this->processed = true;
219  done_lock.unlock();
220  this->processing_done_cond.notify_one();
221 }
222 
224 {
225  return this->processed;
226 }
227 
229 {
230  return this->event_type;
231 }
232 
234 {
235  // initialize logger before creating event processing workers
236  this->logger = std::make_unique<eventLogger>();
237 
238  auto task = [this]
239  {
240  Event::Object* event = nullptr;
241  while (this->running) {
242  {
243  // check if there are available events
244  std::unique_lock<std::mutex> event_lock(this->event_mut);
245  this->available_event_cond.wait(
246  event_lock,
247  [this] { return !(this->event_q.empty()) || !this->running; });
248  // Avoid undefined behavior by checking whether queue is empty first
249  if (this->event_q.empty()) {
250  continue;
251  }
252  event = this->event_q.front();
253  this->event_q.pop();
254  }
255 
256  // we should log this before letting others know we are done
257  this->logger->log(event);
258  // route the event to all handlers
259  {
260  std::shared_lock<std::shared_mutex> handlerlist_lock(
261  this->handlerlist_mut);
262  for (auto* handler : this->handlerList) {
263  handler->receiveEvent(event);
264  }
265  handlerlist_lock.unlock();
266 
267  // mark event as processed
268  event->done();
269  }
270  }
271  };
272 
273  // create event processing workers in the thread pool
274  for (size_t count = 0; count < 2; count++) {
275  this->thread_pool.emplace_back(task);
276  }
277  for (auto& thread : this->thread_pool) {
278  RT::OS::renameOSThread(thread, std::string("RTXIEventWorker"));
279  }
280 }
281 
283 {
285  this->postEvent(&event);
286  this->running.store(false);
287  this->available_event_cond.notify_all();
288  for (auto& thread : this->thread_pool) {
289  if (thread.joinable()) {
290  thread.join();
291  }
292  }
293  while (!this->event_q.empty()) {
294  event_q.front()->done();
295  event_q.pop();
296  }
297 }
298 
300 {
301  // Make sure the event processor is running
302  if (!this->running) {
303  return;
304  }
305 
306  std::unique_lock<std::mutex> lk(this->event_mut);
307  this->event_q.push(event);
308  this->available_event_cond.notify_one();
309  lk.unlock();
310  if (!event->isdone()) {
311  event->wait();
312  }
313 }
314 
315 void Event::Manager::postEvent(std::vector<Event::Object>& events)
316 {
317  // Make sure the event processor is running
318  if (!this->running) {
319  return;
320  }
321 
322  // For performance provide postEvent that accepts multiple events
323  std::unique_lock<std::mutex> lk(this->event_mut);
324  for (auto& event : events) {
325  this->event_q.push(&event);
326  }
327  lk.unlock();
328  this->available_event_cond.notify_all();
329  for (auto& event : events) {
330  if (!event.isdone()) {
331  event.wait();
332  }
333  }
334 }
335 
337 {
338  std::unique_lock<std::shared_mutex> write_lock(this->handlerlist_mut);
339  auto location = std::find(handlerList.begin(), handlerList.end(), handler);
340  if (location == handlerList.end()) {
341  handlerList.push_back(handler);
342  }
343  write_lock.unlock();
344 }
345 
347 {
348  std::unique_lock<std::shared_mutex> write_lock(this->handlerlist_mut);
349  auto location = std::find(handlerList.begin(), handlerList.end(), handler);
350  if (location != handlerList.end()) {
351  handlerList.erase(location);
352  }
353  write_lock.unlock();
354 }
355 
357 {
358  const std::shared_lock<std::shared_mutex> read_lock(this->handlerlist_mut);
359  auto location = std::find(handlerList.begin(), handlerList.end(), handler);
360  return location != handlerList.end();
361 }
bool isRegistered(Handler *handler)
Definition: event.cpp:356
void unregisterHandler(Handler *handler)
Definition: event.cpp:346
void registerHandler(Handler *handler)
Definition: event.cpp:336
void postEvent(Object *event)
Definition: event.cpp:299
void setParam(const std::string &param_name, const std::any &param_value)
Definition: event.cpp:191
Object(Event::Type et)
Definition: event.cpp:154
std::string getName()
Definition: event.cpp:165
void done()
Definition: event.cpp:215
bool paramExists(const std::string &param_name)
Definition: event.cpp:180
Event::Type getType() const
Definition: event.cpp:228
std::any getParam(const std::string &param_name) const
Definition: event.cpp:170
bool isdone() const
Definition: event.cpp:223
void wait()
Definition: event.cpp:207
std::string type_to_string(Type event_type)
Definition: event.cpp:30
Type
Definition: event.hpp:55
@ RT_WIDGET_PARAMETER_CHANGE_EVENT
Definition: event.hpp:68
@ RT_THREAD_PAUSE_EVENT
Definition: event.hpp:62
@ RT_GET_PERIOD_EVENT
Definition: event.hpp:59
@ THRESHOLD_CROSSING_EVENT
Definition: event.hpp:86
@ PLUGIN_INSERT_EVENT
Definition: event.hpp:77
@ STOP_RECORDING_EVENT
Definition: event.hpp:84
@ START_RECORDING_EVENT
Definition: event.hpp:83
@ RT_PERIOD_EVENT
Definition: event.hpp:56
@ RT_DEVICE_UNPAUSE_EVENT
Definition: event.hpp:67
@ SETTINGS_OBJECT_REMOVE_EVENT
Definition: event.hpp:81
@ DAQ_DEVICE_QUERY_EVENT
Definition: event.hpp:79
@ RT_PREPERIOD_EVENT
Definition: event.hpp:57
@ START_GENICAM_RECORDING_EVENT
Definition: event.hpp:87
@ RT_THREAD_UNPAUSE_EVENT
Definition: event.hpp:63
@ RT_WIDGET_STATE_CHANGE_EVENT
Definition: event.hpp:69
@ IO_LINK_INSERT_EVENT
Definition: event.hpp:71
@ ASYNC_DATA_EVENT
Definition: event.hpp:85
@ PLUGIN_REMOVE_EVENT
Definition: event.hpp:78
@ SETTINGS_OBJECT_INSERT_EVENT
Definition: event.hpp:80
@ GENICAM_SNAPSHOT_EVENT
Definition: event.hpp:90
@ IO_LINK_REMOVE_EVENT
Definition: event.hpp:72
@ RT_THREAD_INSERT_EVENT
Definition: event.hpp:60
@ NOOP
Definition: event.hpp:93
@ RT_DEVICE_PAUSE_EVENT
Definition: event.hpp:66
@ OPEN_FILE_EVENT
Definition: event.hpp:82
@ RT_DEVICE_INSERT_EVENT
Definition: event.hpp:64
@ RT_THREAD_REMOVE_EVENT
Definition: event.hpp:61
@ IO_BLOCK_QUERY_EVENT
Definition: event.hpp:73
@ IO_ALL_CONNECTIONS_QUERY_EVENT
Definition: event.hpp:76
@ IO_CONNECTION_QUERY_EVENT
Definition: event.hpp:75
@ RT_SHUTDOWN_EVENT
Definition: event.hpp:70
@ PAUSE_GENICAM_RECORDING_EVENT
Definition: event.hpp:88
@ GENERIC_WIDGET_EVENT
Definition: event.hpp:91
@ IO_BLOCK_OUTPUTS_QUERY_EVENT
Definition: event.hpp:74
@ RT_POSTPERIOD_EVENT
Definition: event.hpp:58
@ RT_DEVICE_REMOVE_EVENT
Definition: event.hpp:65
@ STOP_GENICAM_RECORDING_EVENT
Definition: event.hpp:89
@ MANAGER_SHUTDOWN_EVENT
Definition: event.hpp:92
void renameOSThread(std::thread &thread, const std::string &name)
Definition: rtos_evl.cpp:175