RTXI  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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 <native/task.h>
26 #include <native/timer.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <getopt.h>
32 #include <execinfo.h>
33 #include <unistd.h>
34 
35 typedef struct
36 {
37  long long period;
38  long long next_t;
39  long long wakeup_t;
40  RT_TASK task;
42 
43 static bool init_rt = false;
44 static pthread_key_t is_rt_key;
45 
46 static const char *sigdebug_reasons[] =
47 {
48  [SIGDEBUG_UNDEFINED] = "latency: received SIGXCPU for unknown reason",
49  [SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
50  [SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
51  [SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
52  [SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
53  [SIGDEBUG_NOMLOCK] = "Xenomai: process memory not locked "
54  "(missing mlockall?)",
55  [SIGDEBUG_WATCHDOG] = "Xenomai: watchdog triggered "
56  "(period too short?)",
57 };
58 
59 void sigdebug_handler(int sig, siginfo_t *si, void *context)
60 {
61  const char fmt[] = "Mode switch (reason: %s), aborting. Backtrace:\n";
62  unsigned int reason = si->si_value.sival_int;
63  static char buffer[256];
64  static void *bt[200];
65  unsigned int n;
66 
67  if (reason > SIGDEBUG_WATCHDOG)
68  reason = SIGDEBUG_UNDEFINED;
69 
70  switch(reason)
71  {
72  case SIGDEBUG_UNDEFINED:
73  n = snprintf(buffer, sizeof(buffer),
74  "%s\n", sigdebug_reasons[reason]);
75  write(STDERR_FILENO, buffer, n);
76  case SIGDEBUG_MIGRATE_SIGNAL:
77  n = snprintf(buffer, sizeof(buffer),
78  "%s\n", sigdebug_reasons[reason]);
79  write(STDERR_FILENO, buffer, n);
80  case SIGDEBUG_WATCHDOG:
81  /* These errors are lethal, something went really wrong. */
82  n = snprintf(buffer, sizeof(buffer),
83  "%s\n", sigdebug_reasons[reason]);
84  write(STDERR_FILENO, buffer, n);
85  exit(EXIT_FAILURE);
86  }
87 
88  /* Retrieve the current backtrace, and decode it to stdout. */
89  n = snprintf(buffer, sizeof(buffer), fmt, sigdebug_reasons[reason]);
90  n = write(STDERR_FILENO, buffer, n);
91  n = backtrace(bt, sizeof(bt)/sizeof(bt[0]));
92  backtrace_symbols_fd(bt, n, STDERR_FILENO);
93 
94  signal(sig, SIG_DFL);
95  kill(getpid(), sig);
96 }
97 
98 int RT::OS::initiate(void)
99 {
100  rt_timer_set_mode(TM_ONESHOT);
101 
102  // Kernel limitations on memory lock are no longer present, however
103  // still a useful (for performance) method for preventing paging
104  // of active RTXI memory
105  struct rlimit rlim = { RLIM_INFINITY, RLIM_INFINITY };
106  setrlimit(RLIMIT_MEMLOCK,&rlim);
107 
108  if (mlockall(MCL_CURRENT | MCL_FUTURE))
109  {
110  ERROR_MSG("RTOS:Xenomai::initiate : failed to lock memory.\n");
111  return -EPERM;
112  }
113 
114  pthread_key_create(&is_rt_key,0);
115  init_rt = true;
116 
117  return 0;
118 }
119 
120 void RT::OS::shutdown(void)
121 {
122  pthread_key_delete(is_rt_key);
123 }
124 
125 int RT::OS::createTask(RT::OS::Task *task,void *(*entry)(void *),void *arg,int prio)
126 {
127  int retval = 0;
129  int priority = 99;
130 
131  // Assign signal handler
132  struct sigaction sa;
133  sigemptyset(&sa.sa_mask);
134  sa.sa_sigaction = sigdebug_handler;
135  sa.sa_flags = SA_SIGINFO;
136  sigaction(SIGDEBUG, &sa, NULL);
137 
138  // Tell Xenomai to report mode issues
139  rt_task_set_mode(0, T_WARNSW, NULL);
140 
141  // Invert priority, default prio=0 but max priority for xenomai task is 99
142  if ((prio >=0) && (prio <=99))
143  priority -= prio;
144 
145  if ((retval = rt_task_create(&t->task,"RTXI RT Thread",0,priority,T_FPU)))
146  {
147  ERROR_MSG("RT::OS::createTask : failed to create task\n");
148  return retval;
149  }
150 
151  t->period = -1;
152 
153  *task = t;
154  pthread_setspecific(is_rt_key,reinterpret_cast<const void *>(t));
155 
156  if ((retval = rt_task_start(&t->task,reinterpret_cast<void(*)(void *)>(entry),arg)))
157  {
158  ERROR_MSG("RT::OS::createTask : failed to start task\n");
159  return retval;
160  }
161 
162  return 0;
163 }
164 
166 {
167  xenomai_task_t *t = reinterpret_cast<xenomai_task_t *>(task);
168  rt_task_delete(&t->task);
169 }
170 
171 bool RT::OS::isRealtime(void)
172 {
173  if (init_rt && pthread_getspecific(is_rt_key))
174  return true;
175  return false;
176 }
177 
178 long long RT::OS::getTime(void)
179 {
180  return rt_timer_tsc2ns(rt_timer_tsc());
181 }
182 
183 int RT::OS::setPeriod(RT::OS::Task task,long long period)
184 {
185  // Retrieve task struct
186  xenomai_task_t *t = reinterpret_cast<xenomai_task_t *>(task);
187 
188  // Set wake up limits
189  if(period/10 > 50000ll)
190  t->wakeup_t = rt_timer_ns2ticks(50000ll);
191  else
192  t->wakeup_t = rt_timer_ns2ticks(period/10);
193 
194  // Setup timing bounds for oneshot operation
195  t->period = rt_timer_ns2ticks(period);
196  t->next_t = rt_timer_read() + t->period;
197 
198  return 0;
199 }
200 
202 {
203  xenomai_task_t *t = reinterpret_cast<xenomai_task_t *>(task);
204 
205  // Prevent significant early wake up from happening and drying the Linux system
206  rt_task_sleep_until(t->next_t - t->wakeup_t);
207 
208  // Busy sleep until ready for the next cycle
209  rt_timer_spin(rt_timer_ticks2ns(t->next_t - rt_timer_read()));
210 
211  // Update next interrupt time
212  t->next_t += t->period;
213 }
int initiate(void)
Definition: rt_os-posix.cpp:39
long long period
void deleteTask(Task)
int createTask(Task *, void *(*)(void *), void *, int=0)
long long wakeup_t
bool isRealtime(void)
double arg(const complex _z)
Definition: complex.h:133
void sleepTimestep(Task)
#define ERROR_MSG(fmt, args...)
Definition: debug.h:41
void * Task
Definition: rt.h:40
long long getTime(void)
void sigdebug_handler(int sig, siginfo_t *si, void *context)
long long next_t
int setPeriod(Task, long long)
void shutdown(void)
Definition: rt_os-posix.cpp:63