RTXI  2.4
The Real-Time eXperiment Interface Documentation
rt.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, Weill Cornell Medical College
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  */
19 
20 #include <debug.h>
21 #include <event.h>
22 #include <mutex.h>
23 #include <rt.h>
24 
25 namespace
26 {
27 class SetThreadActive:public RT::Event
28 {
29 
30 public:
31  SetThreadActive(RT::Thread *,bool);
32  ~SetThreadActive(void);
33  int callback(void);
34 
35 private:
36  RT::Thread *thread;
37  bool active;
38 
39 }; // class SetThreadActive
40 
41 class SetDeviceActive : public RT::Event
42 {
43 
44 public:
45  SetDeviceActive(RT::Device *,bool);
46  ~SetDeviceActive(void);
47  int callback(void);
48 
49 private:
50  RT::Device *device;
51  bool active;
52 }; // class SetDeviceActive
53 
54 }; // namespace
55 
56 SetThreadActive::SetThreadActive(RT::Thread *t,bool a):thread(t), active(a) {}
57 
58 SetThreadActive::~SetThreadActive(void) {}
59 
60 int SetThreadActive::callback(void)
61 {
62  thread->setActive(active);
63  return 0;
64 }
65 
66 SetDeviceActive::SetDeviceActive(RT::Device *d,bool a):device(d), active(a) {}
67 
68 SetDeviceActive::~SetDeviceActive(void) {}
69 
70 int SetDeviceActive::callback(void)
71 {
72  device->setActive(active);
73  return 0;
74 }
75 
76 RT::System::SetPeriodEvent::SetPeriodEvent(long long p)
77  : period(p) {}
78 
79 RT::System::SetPeriodEvent::~SetPeriodEvent(void) {}
80 
81 int RT::System::SetPeriodEvent::callback(void)
82 {
83  int retval;
85 
86  if (!(retval = RT::OS::setPeriod(sys->task,period)))
87  {
88  sys->period = period;
89 
91  event.setParam("period",&period);
92  ::Event::Manager::getInstance()->postEventRT(&event);
93  }
94 
95  return retval;
96 }
97 
99 {
100  sem_init(&signal,0,0);
101 }
102 
104 {
105  sem_destroy(&signal);
106 }
107 
108 void RT::Event::execute(void)
109 {
110  retval = callback();
111  sem_post(&signal);
112 }
113 
114 void RT::Event::wait(void)
115 {
116  sem_wait(&signal);
117 }
118 
120  : active(false)
121 {
122  RT::System::getInstance()->insertDevice(this);
123 }
124 
126 {
127  RT::System::getInstance()->removeDevice(this);
128 }
129 
130 void RT::Device::setActive(bool state)
131 {
132  if (RT::OS::isRealtime())
133  active = state;
134  else
135  {
136  SetDeviceActive event(this,state);
138  }
139 }
140 
142  : active(false), priority(p)
143 {
144  RT::System::getInstance()->insertThread(this);
145 }
146 
148 {
149  RT::System::getInstance()->removeThread(this);
150 }
151 
152 void RT::Thread::setActive(bool state)
153 {
154  if (RT::OS::isRealtime())
155  active = state;
156  else
157  {
158  SetThreadActive event(this,state);
160  }
161 }
162 
163 RT::System::System(void)
164  : finished(false), eventFifo(100*sizeof(RT::Event *))
165 {
166  period = 1000000; // 1 kHz
167 
168  if (RT::OS::initiate())
169  {
170  ERROR_MSG("RT::System::System : failed to initialize the realtime system\n");
171  return;
172  }
173 
174  if (RT::OS::createTask(&task,&System::bounce,this))
175  {
176  ERROR_MSG("RT::System::System : failed to create realtime thread\n");
177  return;
178  }
179 }
180 
181 RT::System::~System(void)
182 {
183  finished = true;
184  RT::OS::deleteTask(task);
186 }
187 
188 int RT::System::setPeriod(long long period)
189 {
191  event_pre.setParam("period",&period);
193 
194  SetPeriodEvent event(period);
195  int retval = postEvent(&event);
196 
198  event_post.setParam("period",&period);
200 
201  return retval;
202 }
203 
204 void RT::System::foreachDevice(void (*callback)(RT::Device *,void *),void *param)
205 {
206  Mutex::Locker lock(&deviceMutex);
207  for (List<Device>::iterator i = devices.begin(); i != devices.end(); ++i)
208  callback(&*i,param);
209 }
210 
211 void RT::System::foreachThread(void (*callback)(RT::Thread *,void *),void *param)
212 {
213  Mutex::Locker lock(&threadMutex);
214  for (List<Thread>::iterator i = threadList.begin(); i != threadList.end(); ++i)
215  callback(&*i,param);
216 }
217 
218 int RT::System::postEvent(RT::Event *event,bool blocking)
219 {
220  eventFifo.write(&event,sizeof(RT::Event *));
221  if (blocking)
222  {
223  event->wait();
224  return event->retval;
225  }
226  return 0;
227 }
228 
229 void RT::System::insertDevice(RT::Device *device)
230 {
231  if (!device)
232  {
233  ERROR_MSG("RT::System::insertDevice : invalid device\n");
234  return;
235  }
236 
237  Mutex::Locker lock(&deviceMutex);
238 
240  event.setParam("device",device);
242 
243  devices.insert(devices.end(),*device);
244 }
245 
246 void RT::System::removeDevice(RT::Device *device)
247 {
248  if (!device)
249  {
250  ERROR_MSG("RT::System::removeDevice : invalid device\n");
251  return;
252  }
253 
254  Mutex::Locker lock(&deviceMutex);
255 
257  event.setParam("device",device);
259 
260  devices.remove(*device);
261 }
262 
263 void RT::System::insertThread(RT::Thread *thread)
264 {
265  if (!thread)
266  {
267  ERROR_MSG("RT::System::insertThread : invalid thread\n");
268  return;
269  }
270 
271  Mutex::Locker lock(&threadMutex);
272 
273  /*******************************************************************************
274  * Traverse the list of threads and find the first thread with lower priority. *
275  *******************************************************************************/
276 
277  List<Thread>::iterator i = threadList.begin();
278  for (; i != threadList.end() && i->getPriority() >= thread->getPriority(); ++i);
279 
281  event.setParam("thread",thread);
283 
284  threadList.insert(i,*thread);
285 }
286 
287 void RT::System::removeThread(RT::Thread *thread)
288 {
289  if (!thread)
290  {
291  ERROR_MSG("RT::System::removeThread : invalid thread\n");
292  return;
293  }
294 
295  Mutex::Locker lock(&threadMutex);
296 
298  event.setParam("thread",thread);
300 
301  threadList.remove(*thread);
302 }
303 
304 void *RT::System::bounce(void *param)
305 {
306 
307  RT::System *that = reinterpret_cast<RT::System *>(param);
308  if (that)
309  that->execute();
310  return 0;
311 }
312 
313 void RT::System::execute(void)
314 {
315 
316  Event *event = 0;
317  List<Device>::iterator iDevice;
318  List<Thread>::iterator iThread;
319  List<Device>::iterator devicesBegin = devices.begin();
320  List<Device>::iterator devicesEnd = devices.end();
321  List<Thread>::iterator threadListBegin = threadList.begin();
322  List<Thread>::iterator threadListEnd = threadList.end();
323 
324  if (RT::OS::setPeriod(task,period))
325  {
326  ERROR_MSG("RT::System::execute : failed to set the initial period of the realtime thread\n");
327  return;
328  }
329 
330  while (!finished)
331  {
332  RT::OS::sleepTimestep(task);
333 
334  for (iDevice = devicesBegin; iDevice != devicesEnd; ++iDevice)
335  if (iDevice->getActive()) iDevice->read();
336 
337  for (iThread = threadListBegin; iThread != threadListEnd; ++iThread)
338  if (iThread->getActive()) iThread->execute();
339 
340  for (iDevice = devicesBegin; iDevice != devicesEnd; ++iDevice)
341  if (iDevice->getActive()) iDevice->write();
342 
343  if (eventFifo.read(&event,sizeof(RT::Event *),false))
344  {
345  do
346  {
347  event->execute();
348  }
349  while (eventFifo.read(&event,sizeof(RT::Event *),false));
350 
351  event = 0;
352  devicesBegin = devices.begin();
353  threadListBegin = threadList.begin();
354  }
355  }
356 }
357 
358 static Mutex mutex;
359 RT::System *RT::System::instance = 0;
360 
362 {
363  if (instance)
364  return instance;
365 
366  /*************************************************************************
367  * Seems like alot of hoops to jump through, but static allocation isn't *
368  * thread-safe. So effort must be taken to ensure mutual exclusion. *
369  *************************************************************************/
370 
371  Mutex::Locker lock(&::mutex);
372  if (!instance)
373  {
374  static System system;
375  instance = &system;
376  }
377 
378  return instance;
379 }
Event::Manager::postEvent
void postEvent(const Object *event)
Definition: event.cpp:110
Event::RT_DEVICE_INSERT_EVENT
const char * RT_DEVICE_INSERT_EVENT
Definition: event.cpp:29
Event::RT_THREAD_REMOVE_EVENT
const char * RT_THREAD_REMOVE_EVENT
Definition: event.cpp:28
RT::Event
Definition: rt.h:82
Event::RT_POSTPERIOD_EVENT
const char * RT_POSTPERIOD_EVENT
Definition: event.cpp:26
RT::OS::createTask
int createTask(Task *, void *(*)(void *), void *, int=0)
ERROR_MSG
void ERROR_MSG(const std::string &errmsg,...)
Definition: debug.cpp:27
Event::Manager::getInstance
static Manager * getInstance(void)
Definition: event.cpp:149
RT::System
Definition: rt.h:383
Event::RT_DEVICE_REMOVE_EVENT
const char * RT_DEVICE_REMOVE_EVENT
Definition: event.cpp:30
RT::OS::deleteTask
void deleteTask(Task)
Definition: rt_os-posix.cpp:126
RT::System::foreachDevice
void foreachDevice(void(*callback)(Device *, void *), void *param)
Definition: rt.cpp:204
RT::System::postEvent
int postEvent(Event *event, bool blocking=true)
Definition: rt.cpp:218
RT::System::foreachThread
void foreachThread(void(*callback)(Thread *, void *), void *param)
Definition: rt.cpp:211
RT::Thread::setActive
void setActive(bool)
Definition: rt.cpp:152
RT
Realtime Oriented Classes.
Definition: rt.h:34
Event
Event Oriented Classes.
Definition: event.h:35
RT::Event::callback
virtual int callback(void)=0
Event::RT_THREAD_INSERT_EVENT
const char * RT_THREAD_INSERT_EVENT
Definition: event.cpp:27
RT::Thread::~Thread
virtual ~Thread(void)
Definition: rt.cpp:147
RT::Device
Definition: rt.h:517
RT::OS::isRealtime
bool isRealtime(void)
Definition: rt_os-posix.cpp:136
RT::Device::~Device
virtual ~Device(void)
Definition: rt.cpp:125
RT::System::getInstance
static System * getInstance(void)
Definition: rt.cpp:361
Mutex
Definition: mutex.h:28
RT::OS::sleepTimestep
void sleepTimestep(Task)
Definition: rt_os-posix.cpp:162
RT::Event::~Event
virtual ~Event(void)
Definition: rt.cpp:103
Event::RT_PERIOD_EVENT
const char * RT_PERIOD_EVENT
Definition: event.cpp:24
event.h
RT::Thread::Priority
unsigned long Priority
Definition: rt.h:566
RT::OS::setPeriod
int setPeriod(Task, long long)
Definition: rt_os-posix.cpp:152
RT::Device::Device
Device(void)
Definition: rt.cpp:119
rt.h
mutex.h
RT::Thread
Definition: rt.h:561
Mutex::Locker
Definition: mutex.h:36
RT::OS::shutdown
void shutdown(void)
Definition: rt_os-posix.cpp:71
RT::Thread::getPriority
Priority getPriority(void) const
Definition: rt.h:582
RT::Event::Event
Event(void)
Definition: rt.cpp:98
Event::RT_PREPERIOD_EVENT
const char * RT_PREPERIOD_EVENT
Definition: event.cpp:25
RT::OS::initiate
int initiate(void)
Definition: rt_os-posix.cpp:47
RT::System::setPeriod
int setPeriod(long long period)
Definition: rt.cpp:188
RT::List::iterator
Definition: rt.h:117
Event::Object
Definition: event.h:128
RT::Device::setActive
void setActive(bool)
Definition: rt.cpp:130
Event::Object::setParam
void setParam(const char *, void *)
Definition: event.cpp:89
debug.h
RT::Thread::Thread
Thread(Priority p=DefaultPriority)
Definition: rt.cpp:141