00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #define OROBLD_OS_INTERNAL
00041 #include "os/ThreadInterface.hpp"
00042 #include "fosi.h"
00043 #include "../fosi_internal_interface.hpp"
00044 #include <cassert>
00045 #define INTERNAL_QUAL
00046
00047 #include "../../Logger.hpp"
00048 #include <signal.h>
00049 #include <execinfo.h>
00050
00051
00052 extern "C"
00053 void warn_upon_switch(int sig __attribute__((unused)))
00054 {
00055 void *bt[32];
00056 int nentries;
00057
00058
00059
00060 nentries = backtrace(bt,sizeof(bt) / sizeof(bt[0]));
00061 backtrace_symbols_fd(bt,nentries,fileno(stderr));
00062 }
00063
00064
00065 namespace RTT
00066 {
00067 namespace os {
00068
00069 INTERNAL_QUAL int rtos_task_create_main(RTOS_TASK* main)
00070 {
00071
00072 if ( geteuid() != 0 ) {
00073 #if ((CONFIG_XENO_VERSION_MAJOR*1000)+(CONFIG_XENO_VERSION_MINOR*100)+CONFIG_XENO_REVISION_LEVEL) >= 2302
00074 printf( "WARNING: You are not root. This program *may* require that you are root.\n");
00075
00076 #else
00077 printf( "You are not root. This program requires that you are root.\n");
00078 exit(1);
00079 #endif
00080 }
00081
00082
00083 int rv = mlockall(MCL_CURRENT | MCL_FUTURE);
00084 if ( rv != 0 ) {
00085 perror( "rtos_task_create_main: Could not lock memory using mlockall" );
00086 }
00087
00088 struct sched_param param;
00089
00090
00091 param.sched_priority = sched_get_priority_max(ORO_SCHED_OTHER);
00092 if (param.sched_priority != -1 )
00093 sched_setscheduler( 0, ORO_SCHED_OTHER, ¶m);
00094
00095 const char* mt_name = "MainThread";
00096 main->sched_type = SCHED_XENOMAI_SOFT;
00097 main->name = strncpy( (char*)malloc( (strlen(mt_name)+1)*sizeof(char) ), mt_name, strlen(mt_name)+1 );
00098
00099 int ret = -1;
00100 while( ret != 0) {
00101
00102 if ( (ret = rt_task_shadow( &(main->xenotask),mt_name, 10, 0)) != 0 ) {
00103 if ( ret == -ENOMEM ) {
00104
00105 printf( "Cannot rt_task_create() MainThread: Out of memory.\n");
00106 exit(1);
00107 }
00108 if ( ret == -EBUSY ) {
00109
00110 log(Info) << "MainThread already a Xenomai task." <<endlog();
00111 break;
00112 }
00113 if ( ret == -EEXIST ) {
00114
00115 mt_name = 0;
00116 continue;
00117 }
00118 if ( ret == -EPERM ) {
00119
00120 printf( "Can not rt_task_create() MainThread: No permission.\n");
00121 exit(1);
00122 }
00123
00124 printf( "Can not rt_task_create() MainThread: Error %d.\n",ret);
00125 exit(1);
00126 }
00127 }
00128
00129
00130 if ( mt_name == 0) {
00131 log(Warning) << "'MainThread' name was already in use. Registered empty name with Xenomai.\n" <<endlog();
00132 }
00133
00134
00135 main->xenoptr = rt_task_self();
00136
00137 #ifdef OROSEM_OS_XENO_PERIODIC
00138 # if CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR == 0
00139
00140 rt_timer_start( ORODAT_OS_XENO_PERIODIC_TICK*1000*1000*1000 );
00141 Logger::In in("Scheduler");
00142 Logger::log() << Logger::Info << "Xenomai Periodic Timer started using "<<ORODAT_OS_XENO_PERIODIC_TICK<<" seconds." << Logger::endl;
00143 # else
00144 Logger::In in("Scheduler");
00145 Logger::log() << Logger::Error << "Set Xenomai Periodic Timer using the Linux kernel configuration." << Logger::endl;
00146 # endif
00147 #else
00148 # if CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR == 0
00149 rt_timer_start( TM_ONESHOT );
00150 Logger::log() << Logger::Info << "Xenomai Periodic Timer runs in preemptive 'one-shot' mode." << Logger::endl;
00151 # else
00152 # if CONFIG_XENO_OPT_TIMING_PERIODIC
00153 Logger::log() << Logger::Info << "Xenomai Periodic Timer configured in 'periodic' mode." << Logger::endl;
00154 # else
00155 Logger::log() << Logger::Info << "Xenomai Periodic Timer runs in preemptive 'one-shot' mode." << Logger::endl;
00156 # endif
00157 # endif
00158 #endif
00159 log(Info) << "Installing SIGXCPU handler." <<endlog();
00160
00161 struct sigaction sa;
00162 sa.sa_handler = warn_upon_switch;
00163 sigemptyset( &sa.sa_mask );
00164 sa.sa_flags = 0;
00165 sigaction(SIGXCPU, &sa, 0);
00166
00167 Logger::log() << Logger::Debug << "Xenomai Timer and Main Task Created" << Logger::endl;
00168 return 0;
00169 }
00170
00171 INTERNAL_QUAL int rtos_task_delete_main(RTOS_TASK* main_task)
00172 {
00173
00174 free (main_task->name);
00175 munlockall();
00176 return 0;
00177 }
00178
00179
00180 struct XenoCookie {
00181 void* data;
00182 void* (*wrapper)(void*);
00183 };
00184
00185 INTERNAL_QUAL void rtos_xeno_thread_wrapper( void* cookie )
00186 {
00187
00188 RTOS_TASK* task = ((ThreadInterface*)((XenoCookie*)cookie)->data)->getTask();
00189 task->xenoptr = rt_task_self();
00190 assert( task->xenoptr );
00191
00192
00193 ((XenoCookie*)cookie)->wrapper( ((XenoCookie*)cookie)->data );
00194 free(cookie);
00195 }
00196
00197 INTERNAL_QUAL int rtos_task_create(RTOS_TASK* task,
00198 int priority,
00199 unsigned cpu_affinity,
00200 const char* name,
00201 int sched_type,
00202 size_t stack_size,
00203 void * (*start_routine)(void *),
00204 ThreadInterface* obj)
00205 {
00206 rtos_task_check_priority(&sched_type, &priority);
00207 XenoCookie* xcookie = (XenoCookie*)malloc( sizeof(XenoCookie) );
00208 xcookie->data = obj;
00209 xcookie->wrapper = start_routine;
00210 if ( name == 0 || strlen(name) == 0)
00211 name = "XenoThread";
00212 task->name = strncpy( (char*)malloc( (strlen(name)+1)*sizeof(char) ), name, strlen(name)+1 );
00213 task->sched_type = sched_type;
00214 int rv;
00215
00216
00217 rv = rt_task_spawn(&(task->xenotask), name, stack_size, priority, T_JOINABLE, rtos_xeno_thread_wrapper, xcookie);
00218 if ( rv == -EEXIST ) {
00219 free( task->name );
00220 task->name = strncpy( (char*)malloc( (strlen(name)+2)*sizeof(char) ), name, strlen(name)+1 );
00221 task->name[ strlen(name) ] = '0';
00222 task->name[ strlen(name)+1 ] = 0;
00223 while ( rv == -EEXIST && task->name[ strlen(name) ] != '9') {
00224 task->name[ strlen(name) ] += 1;
00225 rv = rt_task_spawn(&(task->xenotask), task->name, stack_size, priority, T_JOINABLE, rtos_xeno_thread_wrapper, xcookie);
00226 }
00227 }
00228 if ( rv == -EEXIST ) {
00229 log(Warning) << name << ": an object with that name is already existing in Xenomai." << endlog();
00230 rv = rt_task_spawn(&(task->xenotask), 0, stack_size, priority, T_JOINABLE, rtos_xeno_thread_wrapper, xcookie);
00231 }
00232 if ( rv != 0) {
00233 log(Error) << name << " : CANNOT INIT Xeno TASK " << task->name <<" error code: "<< rv << endlog();
00234 }
00235 rt_task_yield();
00236 return rv;
00237 }
00238
00239 INTERNAL_QUAL void rtos_task_yield(RTOS_TASK*) {
00240 rt_task_yield();
00241 }
00242
00243 INTERNAL_QUAL int rtos_task_is_self(const RTOS_TASK* task) {
00244 RT_TASK* self = rt_task_self();
00245 if (self == 0 || task == 0)
00246 return -1;
00247 #if ((CONFIG_XENO_VERSION_MAJOR*1000)+(CONFIG_XENO_VERSION_MINOR*100)+CONFIG_XENO_REVISION_LEVEL) >= 2500
00248 if ( rt_task_same( self, task->xenoptr ) != 0 )
00249 return 1;
00250 #else
00251
00252 if ( self == task->xenoptr )
00253 return 1;
00254 #endif
00255 return 0;
00256 }
00257
00258
00259 INTERNAL_QUAL int rtos_task_check_scheduler(int* scheduler)
00260 {
00261 if (*scheduler != SCHED_XENOMAI_HARD && *scheduler != SCHED_XENOMAI_SOFT ) {
00262 log(Error) << "Unknown scheduler type." <<endlog();
00263 *scheduler = SCHED_XENOMAI_SOFT;
00264 return -1;
00265 }
00266 return 0;
00267 }
00268
00269 INTERNAL_QUAL int rtos_task_check_priority(int* scheduler, int* priority)
00270 {
00271 int ret = 0;
00272
00273 ret = rtos_task_check_scheduler(scheduler);
00274
00275
00276
00277 #if ((CONFIG_XENO_VERSION_MAJOR*10000)+(CONFIG_XENO_VERSION_MINOR*100)+CONFIG_XENO_REVISION_LEVEL) >= 20500
00278 const int minprio = 0;
00279 #else
00280 const int minprio = 1;
00281 #endif
00282 if (*priority < minprio){
00283 log(Warning) << "Forcing priority ("<<*priority<<") of thread to " << minprio <<"." <<endlog();
00284 *priority = minprio;
00285 ret = -1;
00286 }
00287 if (*priority > 99){
00288 log(Warning) << "Forcing priority ("<<*priority<<") of thread to 99." <<endlog();
00289 *priority = 99;
00290 ret = -1;
00291 }
00292 return ret;
00293 }
00294
00295
00296
00297 INTERNAL_QUAL int rtos_task_set_scheduler(RTOS_TASK* t, int sched_type) {
00298
00299 if (t->xenoptr != rt_task_self() ) {
00300 return -1;
00301 }
00302
00303 if ( rtos_task_check_scheduler( &sched_type ) == -1)
00304 return -1;
00305
00306 if (sched_type == SCHED_XENOMAI_HARD) {
00307 if ( rt_task_set_mode( 0, T_PRIMARY, 0 ) == 0 ) {
00308 t->sched_type = SCHED_XENOMAI_HARD;
00309 return 0;
00310 } else {
00311 return -1;
00312 }
00313 } else {
00314 if ( sched_type == SCHED_XENOMAI_SOFT) {
00315
00316 if (rt_task_set_mode( T_PRIMARY, 0, 0 ) == 0 ) {
00317 t->sched_type = SCHED_XENOMAI_SOFT;
00318 return 0;
00319 } else {
00320 return -1;
00321 }
00322 }
00323 }
00324 assert(false);
00325 return -1;
00326 }
00327
00328 INTERNAL_QUAL int rtos_task_get_scheduler(const RTOS_TASK* mytask) {
00329 #if 0
00330
00331 RT_TASK* tt = mytask->xenoptr;
00332 RT_TASK_INFO info;
00333 if ( tt )
00334 if ( rt_task_inquire( tt, &info) == 0 )
00335 if ( info.status & XNRELAX )
00336 return SCHED_XENOMAI_SOFT;
00337 else
00338 return SCHED_XENOMAI_HARD;
00339 return -1;
00340 #else
00341 return mytask->sched_type;
00342 #endif
00343 }
00344
00345 INTERNAL_QUAL void rtos_task_make_periodic(RTOS_TASK* mytask, NANO_TIME nanosecs )
00346 {
00347 if (nanosecs == 0) {
00348 rt_task_set_periodic( &(mytask->xenotask), TM_NOW, TM_INFINITE);
00349 }
00350 else {
00351 rt_task_set_periodic( &(mytask->xenotask), TM_NOW, rt_timer_ns2ticks(nanosecs) );
00352 }
00353 }
00354
00355 INTERNAL_QUAL void rtos_task_set_period( RTOS_TASK* mytask, NANO_TIME nanosecs )
00356 {
00357 rtos_task_make_periodic( mytask, nanosecs);
00358
00359 }
00360
00361 INTERNAL_QUAL void rtos_task_set_wait_period_policy( RTOS_TASK* task, int policy )
00362 {
00363
00364 }
00365
00366 INTERNAL_QUAL int rtos_task_wait_period( RTOS_TASK* mytask )
00367 {
00368
00369 #if CONFIG_XENO_VERSION_MAJOR == 2 && CONFIG_XENO_VERSION_MINOR == 0
00370 if ( rt_task_wait_period() == -ETIMEDOUT)
00371 return 1;
00372 #else // 2.1, 2.2, 2.3, 2.4,...
00373 long unsigned int overrun = 0;
00374 rt_task_wait_period(&overrun);
00375
00376
00377 if ( mytask->sched_type == SCHED_XENOMAI_SOFT )
00378 rt_task_set_mode(T_PRIMARY, 0, 0 );
00379
00380 if ( overrun != 0)
00381 return 1;
00382 #endif
00383 return 0;
00384 }
00385
00386 INTERNAL_QUAL int rtos_task_set_cpu_affinity(RTOS_TASK * task, unsigned cpu_affinity)
00387 {
00388 return -1;
00389 }
00390
00391 INTERNAL_QUAL unsigned rtos_task_get_cpu_affinity(const RTOS_TASK *task)
00392 {
00393 return ~0;
00394 }
00395
00396 INTERNAL_QUAL const char* rtos_task_get_name(const RTOS_TASK* mytask) {
00397 return mytask->name;
00398 }
00399
00400 INTERNAL_QUAL int rtos_task_get_priority(const RTOS_TASK* mytask) {
00401 RT_TASK_INFO info;
00402
00403 RT_TASK* tt = mytask->xenoptr;
00404 if ( tt )
00405 if ( rt_task_inquire ( tt, &info) == 0 )
00406 return info.bprio;
00407 return -1;
00408 }
00409
00410 INTERNAL_QUAL void rtos_task_delete(RTOS_TASK* mytask) {
00411 if ( rt_task_join(&(mytask->xenotask)) != 0 ) {
00412 log(Error) << "Failed to join with thread " << mytask->name << endlog();
00413 }
00414 rt_task_delete(&(mytask->xenotask));
00415 }
00416
00417 INTERNAL_QUAL int rtos_task_set_priority(RTOS_TASK * mytask, int priority)
00418 {
00419
00420 RT_TASK* tt = mytask->xenoptr;
00421 if ( tt )
00422 return rt_task_set_priority( tt, priority);
00423 return -1;
00424 }
00425 }
00426 }
00427 #undef INTERNAL_QUAL
00428