RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
rtos_xenomai.cpp
Go to the documentation of this file.
1 /*
2  The Real-Time eXperiment Interface (RTXI)
3  Copyright (C) 2011 Georgia Institute of Technology,
4  University of Utah, Weill Cornell Medical College
5 
6  This program is free software: you can redistribute it
7  and/or modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation, either version 3 of the License,
9  or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be
12  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14  the GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General
17  Public License along with this program. If not, see
18  <http://www.gnu.org/licenses/>.
19 
20 */
21 
22 #include <complex>
23 #include <iostream>
24 
25 #include "rtos.hpp"
26 
27 #include <alchemy/task.h>
28 #include <alchemy/timer.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/mman.h>
32 #include <sys/resource.h>
33 #include <unistd.h>
34 
35 #include "fifo.hpp"
36 
37 thread_local bool realtime_key = false;
38 thread_local int64_t* RT_PERIOD = nullptr;
39 
41 {
42  // Kernel limitations on memory lock are no longer present, however
43  // still a useful (for performance) method for preventing paging
44  // of active RTXI memory
45  struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY};
46  setrlimit(RLIMIT_MEMLOCK, &rlim);
47 
48  if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
49  ERROR_MSG("RTOS:Xenomai::initiate : failed to lock memory.\n");
50  return -EPERM;
51  }
52 
53  realtime_key = true;
55  RT_PERIOD = &(task->period);
56  return 0;
57 }
58 
60 {
61  realtime_key = false;
62  task->task_finished = true;
63  RT_PERIOD = nullptr;
64 }
65 
66 int RT::OS::createTask(RT::OS::Task* task, void (*func)(void*), void* arg)
67 {
68  int retval = 0;
69  RT_TASK xenomai_task;
70 
71  // Tell Xenomai to report mode issues
72  rt_task_set_mode(0, T_WARNSW, nullptr);
73  retval = rt_task_create(&xenomai_task, "Real-Time Task", 0, 50, 0);
74  if (retval != 0) {
75  ERROR_MSG("RT::OS::createTask : failed to create task\n");
76  return retval;
77  }
78 
79  // Xenomai 3 uses heavy C syntax, so this is dealing with void* shenanigans
80  struct wrapper_args_t
81  {
82  RT::OS::Task* tsk;
83  void (*fn)(void*);
84  void* args;
85  };
86 
87  // create a wrapper for task function
88  auto wrapper = [](void* args)
89  {
90  auto* transferred_args = reinterpret_cast<struct wrapper_args_t*>(args);
91  auto resval = RT::OS::initiate(transferred_args->tsk);
92  if (resval != 0) {
93  ERROR_MSG("RT::OS::createTask : RT::OS::initiate() : {}",
94  strerror(errno));
95  // In the event that we fail to initiate real-time environment let's just
96  // quit
97  return;
98  }
99  transferred_args->fn(transferred_args->args);
100  RT::OS::shutdown(transferred_args->tsk);
101  };
102 
103  // define what we are passing to the wrapper function
104  struct wrapper_args_t wrapper_args
105  {
106  task, func, arg
107  };
108 
109  // start task
110  retval = rt_task_start(&xenomai_task, wrapper, &wrapper_args);
111  if (retval < 0) {
112  ERROR_MSG("RT::OS::createTask : failed to start task\n");
113  return retval;
114  }
115 
116  task->thread_id = std::any(xenomai_task);
117  return 0;
118 }
119 
121 {
122  auto xenomai_task = std::any_cast<RT_TASK>(task->thread_id);
123  rt_task_delete(&xenomai_task);
124 }
125 
126 bool RT::OS::isRealtime()
127 {
128  return (realtime_key && rt_task_self() != nullptr);
129 }
130 
131 int64_t RT::OS::getTime()
132 {
133  return rt_timer_ticks2ns(rt_timer_read());
134 }
135 
136 int RT::OS::setPeriod(RT::OS::Task* task, int64_t period)
137 {
138  task->period = period;
139  return 0;
140 }
141 
142 int64_t RT::OS::getPeriod()
143 {
144  // This function should only ever be accessed withint a real-tim context
145  if (RT_PERIOD == nullptr || !RT::OS::isRealtime()) {
146  return -1;
147  };
148  return *(RT_PERIOD);
149 }
150 
152 {
153  auto wakeup_time = static_cast<SRTIME>(task->next_t);
154  task->next_t += task->period;
155  rt_task_sleep_until(rt_timer_ns2ticks(wakeup_time));
156 }
157 
158 void RT::OS::renameOSThread(std::thread& thread, const std::string& name)
159 {
160  if (RT::OS::isRealtime()) {
161  return;
162  }
163 
164  if (pthread_setname_np(thread.native_handle(), name.c_str()) != 0) {
165  ERROR_MSG("RT::OS::renameOSThread : unable to set name to thread");
166  }
167 }
168 
170 timespec last_proc_time;
172 
173 double RT::OS::getCpuUsage()
174 {
175  return 0;
177  // if (RT::OS::isRealtime()) {
178  // ERROR_MSG(
179  // "RT::OS::getCpuUsage : This function should only be run in user
180  // space. " "Aborting.");
181  // return 0.0;
182  // }
183 
184  // timespec clock_time;
185  // timespec proc_time;
186  // double cpu_rt_percent;
187  // double cpu_user_percent;
188  // long rt_time_elapsed;
189  // long proc_time_elapsed;
190  // long cpu_time_elapsed;
191  // RT_TASK_INFO task_info;
192 
194  // xenomai_task_t* task =
195  // reinterpret_cast<xenomai_task_t*>(RT::System::getInstance()->getTask());
196  // rt_task_inquire(&(task->task), &task_info);
197 
199  // clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &proc_time);
200  // clock_gettime(CLOCK_REALTIME, &clock_time);
201 
203  // cpu_time_elapsed = 1e9 * (clock_time.tv_sec - last_clock_read.tv_sec)
204  // + (clock_time.tv_nsec - last_clock_read.tv_nsec);
205  // if (cpu_time_elapsed <= 0)
206  // return 0.0;
207  // proc_time_elapsed = 1e9 * (proc_time.tv_sec - last_proc_time.tv_sec)
208  // + (proc_time.tv_nsec - last_proc_time.tv_nsec);
209  // cpu_user_percent = 100.0 * (proc_time_elapsed) / cpu_time_elapsed;
210 
212  // rt_time_elapsed = task_info.stat.xtime - last_rt_clock;
213  // cpu_rt_percent = 100.0 * rt_time_elapsed / cpu_time_elapsed;
214 
216  // last_proc_time = proc_time;
217  // last_clock_read = clock_time;
218  // last_rt_clock = task_info.stat.xtime;
219 
220  // return cpu_rt_percent + cpu_user_percent;
221 }
void ERROR_MSG(const std::string &errmsg, Args... args)
Definition: debug.hpp:36
int createTask(Task *task, void(*func)(void *), void *arg)
Definition: rtos_evl.cpp:86
int64_t getPeriod()
Definition: rtos_evl.cpp:150
int setPeriod(Task *task, int64_t period)
Definition: rtos_evl.cpp:144
void shutdown(RT::OS::Task *task)
Definition: rtos_evl.cpp:72
bool isRealtime()
void sleepTimestep(Task *task)
Definition: rtos_evl.cpp:159
void renameOSThread(std::thread &thread, const std::string &name)
Definition: rtos_evl.cpp:175
int64_t getTime()
int initiate(RT::OS::Task *task)
Definition: rtos_evl.cpp:39
void deleteTask(Task *task)
Definition: rtos_evl.cpp:117
const int64_t DEFAULT_PERIOD
Definition: rtos.hpp:19
double getCpuUsage()
ticks_t last_rt_clock
timespec last_clock_read
timespec last_proc_time
thread_local int64_t * RT_PERIOD
thread_local bool realtime_key
bool task_finished
Definition: rtos.hpp:34
std::any thread_id
Definition: rtos.hpp:36
int64_t next_t
Definition: rtos.hpp:33
int64_t period
Definition: rtos.hpp:32