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