RTXI  3.0.0
The Real-Time eXperiment Interface Reference Manual
rt_os-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, Will 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 <debug.h>
23 #include <execinfo.h>
24 #include <getopt.h>
25 #include <pthread.h>
26 #include <rt.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <studio.h>
31 #include <sys/mman.h>
32 #include <sys/resource.h>
33 #include <unistd.h>
34 
35 #if CONFIG_XENO_VERSION_MAJOR >= 3
36 # include <alchemy/task.h>
37 # include <alchemy/timer.h>
38 #else
39 # include <native/task.h>
40 # include <native/timer.h>
41 #endif
42 
43 typedef struct
44 {
45  long long period;
46  long long next_t;
47  long long wakeup_t;
48  RT_TASK task;
50 
51 static bool init_rt = false;
52 static pthread_key_t is_rt_key;
53 static char* RT_TASK_NAME = "RTXI RT Thread";
54 
55 static const char* sigdebug_reasons[] = {
56  [SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
57  [SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
58  [SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
59  [SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
60  [SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
61  [SIGDEBUG_NOMLOCK] =
62  "Xenomai: process memory not locked "
63  "(missing mlockall?)",
64  [SIGDEBUG_WATCHDOG] =
65  "Xenomai: watchdog triggered "
66  "(period too short?)",
67 };
68 
69 void sigdebug_handler(int sig, siginfo_t* si, void*)
70 {
71  const char fmt[] = "Mode switch (reason: %s), aborting. Backtrace:\n";
72  unsigned int reason = si->si_value.sival_int;
73  static char buffer[256];
74  static void* bt[200];
75  unsigned int n;
76 
77  if (reason > SIGDEBUG_WATCHDOG)
78  reason = SIGDEBUG_UNDEFINED;
79 
80  switch (reason) {
81  case SIGDEBUG_UNDEFINED:
82  n = snprintf(buffer, sizeof(buffer), "%s\n", sigdebug_reasons[reason]);
83  write(STDERR_FILENO, buffer, n);
84  break;
85  case SIGDEBUG_MIGRATE_SIGNAL:
86  n = snprintf(buffer, sizeof(buffer), "%s\n", sigdebug_reasons[reason]);
87  write(STDERR_FILENO, buffer, n);
88  break;
89  case SIGDEBUG_WATCHDOG:
90  /* These errors are lethal, something went really wrong. */
91  n = snprintf(buffer, sizeof(buffer), "%s\n", sigdebug_reasons[reason]);
92  write(STDERR_FILENO, buffer, n);
93  exit(EXIT_FAILURE);
94  }
95 
96  /* Retrieve the current backtrace, and decode it to stdout. */
97  n = snprintf(buffer, sizeof(buffer), fmt, sigdebug_reasons[reason]);
98  n = write(STDERR_FILENO, buffer, n);
99  n = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
100  backtrace_symbols_fd(bt, n, STDERR_FILENO);
101 
102  signal(sig, SIG_DFL);
103  kill(getpid(), sig);
104 }
105 
106 int RT::OS::initiate(void)
107 {
108  // Kernel limitations on memory lock are no longer present, however
109  // still a useful (for performance) method for preventing paging
110  // of active RTXI memory
111  struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY};
112  setrlimit(RLIMIT_MEMLOCK, &rlim);
113 
114  if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
115  ERROR_MSG("RTOS:Xenomai::initiate : failed to lock memory.\n");
116  return -EPERM;
117  }
118 
119  pthread_key_create(&is_rt_key, 0);
120  init_rt = true;
121 
122  return 0;
123 }
124 
125 void RT::OS::shutdown(void)
126 {
127  pthread_key_delete(is_rt_key);
128 }
129 
131  void* (*entry)(void*),
132  void* arg,
133  int prio)
134 {
135  int retval = 0;
137  int priority = 99;
138 
139  // Assign signal handler
140  struct sigaction sa;
141  sigemptyset(&sa.sa_mask);
142  sa.sa_sigaction = sigdebug_handler;
143  sa.sa_flags = SA_SIGINFO;
144  sigaction(SIGDEBUG, &sa, NULL);
145 
146  // Tell Xenomai to report mode issues
147  rt_task_set_mode(0, T_WARNSW, NULL);
148 
149  // Invert priority, default prio=0 but max priority for xenomai task is 99
150  if ((prio >= 0) && (prio <= 99))
151  priority -= prio;
152 
153  if ((retval = rt_task_create(&t->task, RT_TASK_NAME, 0, priority, 0))) {
154  ERROR_MSG("RT::OS::createTask : failed to create task\n");
155  return retval;
156  }
157 
158  t->period = -1;
159 
160  *task = t;
161  pthread_setspecific(is_rt_key, reinterpret_cast<const void*>(t));
162 
163  if ((retval = rt_task_start(
164  &t->task, reinterpret_cast<void (*)(void*)>(entry), arg)))
165  {
166  ERROR_MSG("RT::OS::createTask : failed to start task\n");
167  return retval;
168  }
169 
170  return 0;
171 }
172 
174 {
175  xenomai_task_t* t = reinterpret_cast<xenomai_task_t*>(task);
176  rt_task_delete(&t->task);
177 }
178 
180 {
181  if (init_rt && rt_task_self() != NULL)
182  return true;
183  return false;
184 }
185 
186 long long RT::OS::getTime(void)
187 {
188 #if CONFIG_XENO_VERSION_MAJOR >= 3
189  return rt_timer_read();
190 #else
191  return rt_timer_tsc2ns(rt_timer_tsc());
192 #endif
193 }
194 
195 int RT::OS::setPeriod(RT::OS::Task task, long long period)
196 {
197  // Retrieve task struct
198  xenomai_task_t* t = reinterpret_cast<xenomai_task_t*>(task);
199 
200  // Set wake up limits
201  if (period / 10 > 50000ll)
202  t->wakeup_t = rt_timer_ns2ticks(50000ll);
203  else
204  t->wakeup_t = rt_timer_ns2ticks(period / 10);
205 
206  // Setup timing bounds for oneshot operation
207  t->period = rt_timer_ns2ticks(period);
208  t->next_t = rt_timer_read() + t->period;
209 
210  return 0;
211 }
212 
214 {
215  xenomai_task_t* t = reinterpret_cast<xenomai_task_t*>(task);
216 
217  // Prevent significant early wake up from happening and drying the Linux
218  // system
219  rt_task_sleep_until(t->next_t - t->wakeup_t);
220 
221  // Busy sleep until ready for the next cycle
222  rt_timer_spin(rt_timer_ticks2ns(t->next_t - rt_timer_read()));
223 
224  // Update next interrupt time
225  t->next_t += t->period;
226 }
227 
229 timespec last_proc_time;
231 
233 {
234  // Should not attempt this in the real-time thread
235  if (RT::OS::isRealtime()) {
236  ERROR_MSG(
237  "RT::OS::getCpuUsage : This function should only be run in user space. "
238  "Aborting.");
239  return 0.0;
240  }
241 
242  timespec clock_time;
243  timespec proc_time;
244  double cpu_rt_percent;
245  double cpu_user_percent;
246  long rt_time_elapsed;
247  long proc_time_elapsed;
248  long cpu_time_elapsed;
249  RT_TASK_INFO task_info;
250 
251  // First get task information
252  xenomai_task_t* task =
253  reinterpret_cast<xenomai_task_t*>(RT::System::getInstance()->getTask());
254  rt_task_inquire(&(task->task), &task_info);
255 
256  // get ticks from normal system
257  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &proc_time);
258  clock_gettime(CLOCK_REALTIME, &clock_time);
259 
260  // calculate cpu usage in user space
261  cpu_time_elapsed = 1e9 * (clock_time.tv_sec - last_clock_read.tv_sec)
262  + (clock_time.tv_nsec - last_clock_read.tv_nsec);
263  if (cpu_time_elapsed <= 0)
264  return 0.0;
265  proc_time_elapsed = 1e9 * (proc_time.tv_sec - last_proc_time.tv_sec)
266  + (proc_time.tv_nsec - last_proc_time.tv_nsec);
267  cpu_user_percent = 100.0 * (proc_time_elapsed) / cpu_time_elapsed;
268 
269  // calculate cpu usage by real-time therad
270  rt_time_elapsed = task_info.stat.xtime - last_rt_clock;
271  cpu_rt_percent = 100.0 * rt_time_elapsed / cpu_time_elapsed;
272 
273  // keep track of last clock reads
274  last_proc_time = proc_time;
275  last_clock_read = clock_time;
276  last_rt_clock = task_info.stat.xtime;
277 
278  return cpu_rt_percent + cpu_user_percent;
279 }
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
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
int64_t getTime()
int initiate(RT::OS::Task *task)
Definition: rtos_evl.cpp:39
void deleteTask(Task *task)
Definition: rtos_evl.cpp:117
double getCpuUsage()
ticks_t last_rt_clock
timespec last_clock_read
timespec last_proc_time
void sigdebug_handler(int sig, siginfo_t *si, void *)
long long next_t
long long wakeup_t
long long period