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 #include "../ThreadInterface.hpp"
00039 #include "fosi.h"
00040 #include "../fosi_internal_interface.hpp"
00041 #include "../../Logger.hpp"
00042 #include <cassert>
00043 #include <sys/time.h>
00044 #include <sys/resource.h>
00045 #ifdef ORO_OS_LINUX_CAP_NG
00046 #include <cap-ng.h>
00047 #endif
00048 #include <iostream>
00049 #include <cstdlib>
00050 #include <sys/types.h>
00051 #include <unistd.h>
00052 #include <sys/syscall.h>
00053
00054 using namespace std;
00055
00056 #define INTERNAL_QUAL
00057
00058 namespace RTT
00059 { namespace os {
00060
00061 INTERNAL_QUAL int rtos_task_create_main(RTOS_TASK* main_task)
00062 {
00063 const char* name = "main";
00064 main_task->wait_policy = ORO_WAIT_ABS;
00065 main_task->name = strcpy( (char*)malloc( (strlen(name) + 1) * sizeof(char)), name);
00066 main_task->thread = pthread_self();
00067 pthread_attr_init( &(main_task->attr) );
00068 struct sched_param sp;
00069 sp.sched_priority=0;
00070
00071
00072 pthread_attr_setschedparam(&(main_task->attr), &sp);
00073 main_task->priority = sp.sched_priority;
00074 main_task->pid = getpid();
00075 return 0;
00076 }
00077
00078 INTERNAL_QUAL int rtos_task_delete_main(RTOS_TASK* main_task)
00079 {
00080 pthread_attr_destroy( &(main_task->attr) );
00081 free(main_task->name);
00082 return 0;
00083 }
00084
00085 struct PosixCookie {
00086 void* data;
00087 void* (*wrapper)(void*);
00088 };
00089
00090 INTERNAL_QUAL void* rtos_posix_thread_wrapper( void* cookie )
00091 {
00092
00093 RTOS_TASK* task = ((ThreadInterface*)((PosixCookie*)cookie)->data)->getTask();
00094 task->pid = syscall(SYS_gettid);
00095 assert( task->pid );
00096
00097
00098 ((PosixCookie*)cookie)->wrapper( ((PosixCookie*)cookie)->data );
00099 free(cookie);
00100 return 0;
00101 }
00102
00103
00104
00105 INTERNAL_QUAL int rtos_task_create(RTOS_TASK* task,
00106 int priority,
00107 unsigned cpu_affinity,
00108 const char * name,
00109 int sched_type,
00110 size_t stack_size,
00111 void * (*start_routine)(void *),
00112 ThreadInterface* obj)
00113 {
00114 int rv;
00115 task->wait_policy = ORO_WAIT_ABS;
00116 rtos_task_check_priority( &sched_type, &priority );
00117
00118
00119 task->priority = priority;
00120
00121 PosixCookie* xcookie = (PosixCookie*)malloc( sizeof(PosixCookie) );
00122 xcookie->data = obj;
00123 xcookie->wrapper = start_routine;
00124
00125
00126 if ( strlen(name) == 0 )
00127 name = "Thread";
00128 task->name = strcpy( (char*)malloc( (strlen(name) + 1) * sizeof(char)), name);
00129
00130 if ( (rv = pthread_attr_init(&(task->attr))) != 0 ){
00131 return rv;
00132 }
00133
00134 if ( (rv = pthread_attr_setschedpolicy(&(task->attr), sched_type)) != 0){
00135 return rv;
00136 }
00137
00138 if (stack_size )
00139 if ( (rv = pthread_attr_setstacksize(&(task->attr), stack_size)) != 0){
00140 return rv;
00141 }
00142 pthread_attr_getschedpolicy(&(task->attr), &rv );
00143 assert( rv == sched_type );
00144
00145
00146
00147 struct sched_param sp;
00148 if (sched_type != SCHED_OTHER){
00149 sp.sched_priority=priority;
00150
00151 if ( (rv = pthread_attr_setschedparam(&(task->attr), &sp)) != 0 ){
00152 return rv;
00153 }
00154 }
00155 rv = pthread_create(&(task->thread), &(task->attr),
00156 rtos_posix_thread_wrapper, xcookie);
00157 if (rv != 0) {
00158 log(Error) << "Failed to create thread " << task->name << ": "
00159 << strerror(rv) << endlog();
00160 return rv;
00161 }
00162
00163
00164 {
00165
00166
00167 static const int MAX_THREAD_NAME_SIZE = 15;
00168 const char *thread_name = task->name;
00169 std::size_t thread_name_len = strlen(thread_name);
00170 if (thread_name_len > MAX_THREAD_NAME_SIZE) {
00171 thread_name += thread_name_len - MAX_THREAD_NAME_SIZE;
00172 }
00173 int result = pthread_setname_np(task->thread, thread_name);
00174 if (result != 0) {
00175 log(Error) << "Failed to set thread name for " << task->name << ": "
00176 << strerror(result) << endlog();
00177 }
00178 }
00179
00180 if ( cpu_affinity != (unsigned)~0 ) {
00181 log(Debug) << "Setting CPU affinity to " << cpu_affinity << endlog();
00182 int result = rtos_task_set_cpu_affinity(task, cpu_affinity);
00183 if (result != 0) {
00184 log(Error) << "Failed to set CPU affinity to " << cpu_affinity << " for " << task->name << ": "
00185 << strerror(result) << endlog();
00186 }
00187 }
00188
00189 return rv;
00190 }
00191
00192 INTERNAL_QUAL void rtos_task_yield(RTOS_TASK* t) {
00193 #if 0
00194
00195
00196 NANO_TIME timeRemaining = 1000;
00197 TIME_SPEC ts( ticks2timespec( timeRemaining ) );
00198 rtos_nanosleep( &ts , NULL );
00199 #else
00200 int ret = sched_yield();
00201 if ( ret != 0)
00202 perror("rtos_task_yield");
00203 #endif
00204 }
00205
00206 INTERNAL_QUAL unsigned int rtos_task_get_pid(const RTOS_TASK* task)
00207 {
00208 if (task)
00209 return task->pid;
00210 return 0;
00211 }
00212
00213 INTERNAL_QUAL int rtos_task_is_self(const RTOS_TASK* task) {
00214 pthread_t self = pthread_self();
00215 if ( pthread_equal(self, task->thread) == 0 )
00216 return 0;
00217 return 1;
00218 }
00219
00220 INTERNAL_QUAL int rtos_task_set_scheduler(RTOS_TASK* task, int sched_type) {
00221 int policy = -1;
00222 struct sched_param param;
00223
00224 if ( task && task->thread != 0 && rtos_task_check_scheduler( &sched_type) == -1 )
00225 return -1;
00226
00227 if (pthread_getschedparam(task->thread, &policy, ¶m) == 0) {
00228
00229 param.sched_priority = task->priority;
00230 rtos_task_check_priority( &sched_type, ¶m.sched_priority );
00231
00232 return pthread_setschedparam( task->thread, sched_type, ¶m);
00233 }
00234 return -1;
00235 }
00236
00237 INTERNAL_QUAL int rtos_task_get_scheduler(const RTOS_TASK* task) {
00238 int policy = -1;
00239 struct sched_param param;
00240
00241 if ( task && task->thread != 0 && pthread_getschedparam(task->thread, &policy, ¶m) == 0)
00242 return policy;
00243 return -1;
00244 }
00245
00246 INTERNAL_QUAL void rtos_task_make_periodic(RTOS_TASK* mytask, NANO_TIME nanosecs )
00247 {
00248
00249 mytask->period = nanosecs;
00250
00251 mytask->periodMark = ticks2timespec( nano2ticks( rtos_get_time_ns() + nanosecs ) );
00252 }
00253
00254 INTERNAL_QUAL void rtos_task_set_period( RTOS_TASK* mytask, NANO_TIME nanosecs )
00255 {
00256 rtos_task_make_periodic(mytask, nanosecs);
00257 }
00258
00259 INTERNAL_QUAL void rtos_task_set_wait_period_policy( RTOS_TASK* task, int policy )
00260 {
00261 task->wait_policy = policy;
00262 }
00263
00264 INTERNAL_QUAL int rtos_task_wait_period( RTOS_TASK* task )
00265 {
00266 if ( task->period == 0 )
00267 return 0;
00268
00269
00270 NANO_TIME now = rtos_get_time_ns();
00271 NANO_TIME wake= task->periodMark.tv_sec * 1000000000LL + task->periodMark.tv_nsec;
00272
00273
00274 while ( clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &(task->periodMark), NULL) != 0 && errno == EINTR ) {
00275 errno = 0;
00276 }
00277
00278 if (task->wait_policy == ORO_WAIT_ABS)
00279 {
00280
00281
00282 int maxDelayInPeriods = 4;
00283 NANO_TIME period = task->period;
00284 if (now - wake > maxDelayInPeriods*period) {
00285 period = period * ((now - wake) / period);
00286 }
00287
00288
00289 TIME_SPEC ts = ticks2timespec( nano2ticks(period) );
00290
00291 NANO_TIME tn = (task->periodMark.tv_nsec + ts.tv_nsec);
00292 task->periodMark.tv_nsec = tn % 1000000000LL;
00293 task->periodMark.tv_sec += ts.tv_sec + tn / 1000000000LL;
00294 }
00295 else
00296 {
00297 TIME_SPEC ts = ticks2timespec( nano2ticks( task->period) );
00298 TIME_SPEC now = ticks2timespec( rtos_get_time_ns() );
00299 NANO_TIME tn = (now.tv_nsec + ts.tv_nsec);
00300 task->periodMark.tv_nsec = tn % 1000000000LL;
00301 task->periodMark.tv_sec = ts.tv_sec + now.tv_sec + tn / 1000000000LL;
00302 }
00303
00304 return now > wake ? -1 : 0;
00305 }
00306
00307 INTERNAL_QUAL void rtos_task_delete(RTOS_TASK* mytask) {
00308 pthread_join( mytask->thread, 0);
00309 pthread_attr_destroy( &(mytask->attr) );
00310 free(mytask->name);
00311 }
00312
00313 INTERNAL_QUAL int rtos_task_check_scheduler(int* scheduler)
00314 {
00315 #ifdef ORO_OS_LINUX_CAP_NG
00316 if(capng_get_caps_process()) {
00317 log(Error) << "Failed to retrieve capabilities (lowering to SCHED_OTHER)." <<endlog();
00318 *scheduler = SCHED_OTHER;
00319 return -1;
00320 }
00321 #endif
00322
00323 if (*scheduler != SCHED_OTHER && geteuid() != 0
00324 #ifdef ORO_OS_LINUX_CAP_NG
00325 && capng_have_capability(CAPNG_EFFECTIVE, CAP_SYS_NICE)==0
00326 #endif
00327 ) {
00328
00329
00330
00331 struct rlimit r;
00332 if ((0 != getrlimit(RLIMIT_RTPRIO, &r)) || (0 == r.rlim_cur))
00333 {
00334 log(Warning) << "Lowering scheduler type to SCHED_OTHER for non-privileged users.." <<endlog();
00335 *scheduler = SCHED_OTHER;
00336 return -1;
00337 }
00338 }
00339
00340 if (*scheduler != SCHED_OTHER && *scheduler != SCHED_FIFO && *scheduler != SCHED_RR ) {
00341 log(Error) << "Unknown scheduler type." <<endlog();
00342 *scheduler = SCHED_OTHER;
00343 return -1;
00344 }
00345 return 0;
00346 }
00347
00348 INTERNAL_QUAL int rtos_task_check_priority(int* scheduler, int* priority)
00349 {
00350 int ret = 0;
00351
00352 ret = rtos_task_check_scheduler(scheduler);
00353
00354
00355 if (*scheduler == SCHED_OTHER) {
00356 if ( *priority != 0 ) {
00357 if (*priority != LowestPriority)
00358 log(Warning) << "Forcing priority ("<<*priority<<") of thread with SCHED_OTHER policy to 0." <<endlog();
00359 *priority = 0;
00360 ret = -1;
00361 }
00362 } else {
00363
00364 if (*priority <= 0){
00365 log(Warning) << "Forcing priority ("<<*priority<<") of thread with !SCHED_OTHER policy to 1." <<endlog();
00366 *priority = 1;
00367 ret = -1;
00368 }
00369 if (*priority > 99){
00370 log(Warning) << "Forcing priority ("<<*priority<<") of thread with !SCHED_OTHER policy to 99." <<endlog();
00371 *priority = 99;
00372 ret = -1;
00373 }
00374
00375 if ( geteuid() != 0
00376 #ifdef ORO_OS_LINUX_CAP_NG
00377 && !capng_have_capability(CAPNG_EFFECTIVE, CAP_SYS_NICE)
00378 #endif
00379 )
00380 {
00381 struct rlimit r;
00382 if (0 == getrlimit(RLIMIT_RTPRIO, &r))
00383 {
00384 if (*priority > (int)r.rlim_cur)
00385 {
00386 log(Warning) << "Forcing priority ("<<*priority<<") of thread with !SCHED_OTHER policy to the pam_limit of " << r.rlim_cur <<endlog();
00387 *priority = r.rlim_cur;
00388 ret = -1;
00389 }
00390 }
00391 else
00392 {
00393
00394 *priority = 1;
00395 ret = -1;
00396 }
00397 }
00398 }
00399 return ret;
00400 }
00401
00402 INTERNAL_QUAL int rtos_task_set_priority(RTOS_TASK * task, int priority)
00403 {
00404 int policy = 0;
00405 struct sched_param param;
00406
00407 if( task && task->thread != 0 && pthread_getschedparam(task->thread, &policy, ¶m) == 0) {
00408 if ( rtos_task_check_priority( &policy, &priority ) != 0 )
00409 return -1;
00410 param.sched_priority = priority;
00411 task->priority = priority;
00412
00413 return pthread_setschedparam( task->thread, policy, ¶m);
00414 }
00415 return -1;
00416 }
00417
00418 INTERNAL_QUAL int rtos_task_get_priority(const RTOS_TASK *task)
00419 {
00420
00421 int policy = 0;
00422 struct sched_param param;
00423
00424 if ( task == 0 )
00425 return -1;
00426 if ( task->thread == 0 || pthread_getschedparam(task->thread, &policy, ¶m) != 0)
00427 return task->priority;
00428 return param.sched_priority;
00429 }
00430
00431 INTERNAL_QUAL int rtos_task_set_cpu_affinity(RTOS_TASK * task, unsigned cpu_affinity)
00432 {
00433 if ( cpu_affinity == 0 )
00434 cpu_affinity = ~0;
00435 if( task && task->thread != 0 ) {
00436 cpu_set_t cs;
00437 CPU_ZERO(&cs);
00438 for(unsigned i = 0; i < 8*sizeof(cpu_affinity); i++)
00439 {
00440 if(cpu_affinity & (1 << i)) { CPU_SET(i, &cs); }
00441 }
00442 return pthread_setaffinity_np(task->thread, sizeof(cs), &cs);
00443 }
00444 return -1;
00445 }
00446
00447 INTERNAL_QUAL unsigned rtos_task_get_cpu_affinity(const RTOS_TASK *task)
00448 {
00449 if( task && task->thread != 0) {
00450 unsigned cpu_affinity = 0;
00451 cpu_set_t cs;
00452 pthread_getaffinity_np(task->thread, sizeof(cs), &cs);
00453 for(unsigned i = 0; i < 8*sizeof(cpu_affinity); i++)
00454 {
00455 if(CPU_ISSET(i, &cs)) { cpu_affinity |= (1 << i); }
00456 }
00457 return cpu_affinity;
00458 }
00459 return ~0;
00460 }
00461
00462 INTERNAL_QUAL const char * rtos_task_get_name(const RTOS_TASK* task)
00463 {
00464 return task->name;
00465 }
00466
00467 }
00468 }
00469 #undef INTERNAL_QUAL