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 "fosi_internal_interface.hpp"
00039 #include "Thread.hpp"
00040 #include "../Time.hpp"
00041 #include "threads.hpp"
00042 #include "../Logger.hpp"
00043 #include "MutexLock.hpp"
00044
00045 #include "../rtt-config.h"
00046
00047 #ifdef OROPKG_OS_THREAD_SCOPE
00048 # include "../extras/dev/DigitalOutInterface.hpp"
00049 #define SCOPE_ON if ( task->d ) task->d->switchOn( bit );
00050 #define SCOPE_OFF if ( task->d ) task->d->switchOff( bit );
00051 #else
00052 #define SCOPE_ON
00053 #define SCOPE_OFF
00054 #endif
00055
00056 #ifndef ORO_EMBEDDED
00057 #define TRY try
00058 #define CATCH(a) catch(a)
00059 #define CATCH_ALL catch(...)
00060 #else
00061 #define TRY
00062 #define CATCH(a) if (false)
00063 #define CATCH_ALL if (false)
00064 #endif
00065
00066 namespace RTT {
00067 namespace os
00068 {
00069 using RTT::Logger;
00070
00071 unsigned int Thread::default_stack_size = 0;
00072
00073 void Thread::setStackSize(unsigned int ssize) { default_stack_size = ssize; }
00074
00075 void *thread_function(void* t)
00076 {
00080 Thread* task = static_cast<os::Thread*> (t);
00081 Logger::In in(task->getName());
00082
00083 task->configure();
00084
00085
00086 rtos_sem_signal(&(task->sem));
00087
00088
00089 { MutexLock lock(task->breaker); }
00090 #ifdef OROPKG_OS_THREAD_SCOPE
00091
00092 unsigned int bit = task->threadNumber();
00093 #endif
00094 SCOPE_OFF
00095
00096 int overruns = 0, cur_sched = task->msched_type;
00097 NANO_TIME cur_period = task->period;
00098
00099 while (!task->prepareForExit)
00100 {
00101 TRY
00102 {
00106 while (1)
00107 {
00108 if (!task->active || (task->active && task->period == 0) || !task->running )
00109 {
00110
00111 if (task->period != 0) {
00112 overruns = 0;
00113
00114 rtos_task_set_period(task->getTask(), 0);
00115 }
00116 rtos_sem_wait(&(task->sem));
00117 task->configure();
00118 if (task->prepareForExit)
00119 {
00120 break;
00121 }
00122
00123 }
00124
00125 if ( task->running )
00126 {
00127 if (task->period != 0)
00128 {
00129 MutexLock lock(task->breaker);
00130 while(task->running && !task->prepareForExit )
00131 {
00132 try
00133 {
00134 SCOPE_ON
00135 task->step();
00136 SCOPE_OFF
00137 }
00138 catch(...)
00139 {
00140 SCOPE_OFF
00141 throw;
00142 }
00143
00144
00145 if ( cur_period != task->period) {
00146
00147 rtos_task_set_period(task->getTask(), task->period);
00148 cur_period = task->period;
00149 if (cur_period == 0)
00150 break;
00151 }
00152
00153
00154 if ( cur_sched != task->msched_type) {
00155 rtos_task_set_scheduler(task->getTask(), task->msched_type);
00156 cur_sched = task->msched_type;
00157 }
00158
00159
00160
00161 if (rtos_task_wait_period(task->getTask()) != 0)
00162 {
00163 ++overruns;
00164 if (overruns == task->maxOverRun)
00165 break;
00166 }
00167 else if (overruns != 0)
00168 --overruns;
00169 }
00170 if (overruns == task->maxOverRun || task->prepareForExit)
00171 break;
00172 }
00173 else
00174 try
00175 {
00176
00177
00178 MutexLock lock(task->breaker);
00179
00180 task->inloop = true;
00181 SCOPE_ON
00182 task->loop();
00183 SCOPE_OFF
00184 task->inloop = false;
00185 }
00186 catch(...) {
00187 SCOPE_OFF
00188 task->inloop = false;
00189 throw;
00190 }
00191 }
00192 }
00193 if (overruns == task->maxOverRun)
00194 {
00195 task->emergencyStop();
00196 Logger::In in(rtos_task_get_name(task->getTask()));
00197 log(Critical) << rtos_task_get_name(task->getTask())
00198 << " got too many periodic overruns in step() ("
00199 << overruns << " times), stopped Thread !"
00200 << endlog();
00201 log() << " See Thread::setMaxOverrun() for info."
00202 << endlog();
00203 }
00204 } CATCH(std::exception const& e)
00205 {
00206 SCOPE_OFF
00207 task->emergencyStop();
00208 Logger::In in(rtos_task_get_name(task->getTask()));
00209 log(Critical) << rtos_task_get_name(task->getTask())
00210 << " caught a C++ exception, stopped thread !"
00211 << endlog();
00212 log(Critical) << "exception was: "
00213 << e.what() << endlog();
00214 } CATCH_ALL
00215 {
00216 SCOPE_OFF
00217 task->emergencyStop();
00218 Logger::In in(rtos_task_get_name(task->getTask()));
00219 log(Critical) << rtos_task_get_name(task->getTask())
00220 << " caught an unknown C++ exception, stopped thread !"
00221 << endlog();
00222 }
00223 }
00224
00225 return 0;
00226 }
00227
00228 void Thread::emergencyStop()
00229 {
00230
00231 this->running = false;
00232 this->inloop = false;
00233 this->active = false;
00234
00235 this->finalize();
00236 }
00237
00238 Thread::Thread(int scheduler, int _priority,
00239 Seconds periods, unsigned cpu_affinity, const std::string & name) :
00240 msched_type(scheduler), active(false), prepareForExit(false),
00241 inloop(false),running(false),
00242 maxOverRun(OROSEM_OS_PERIODIC_THREADS_MAX_OVERRUN),
00243 period(Seconds_to_nsecs(periods))
00244 #ifdef OROPKG_OS_THREAD_SCOPE
00245 ,d(NULL)
00246 #endif
00247 {
00248 this->setup(_priority, cpu_affinity, name);
00249 }
00250
00251 void Thread::setup(int _priority, unsigned cpu_affinity, const std::string& name)
00252 {
00253 Logger::In in("Thread");
00254 int ret;
00255
00256
00257 MutexLock lock(breaker);
00258
00259 log(Info) << "Creating Thread for scheduler: " << msched_type << endlog();
00260 ret = rtos_sem_init(&sem, 0);
00261 if (ret != 0)
00262 {
00263 log(Critical)
00264 << "Could not allocate configuration semaphore 'sem' for "
00265 << rtos_task_get_name(&rtos_task)
00266 << ". Throwing std::bad_alloc." << endlog();
00267 rtos_sem_destroy(&sem);
00268 #ifndef ORO_EMBEDDED
00269 throw std::bad_alloc();
00270 #else
00271 return;
00272 #endif
00273 }
00274
00275 #ifdef OROPKG_OS_THREAD_SCOPE
00276
00277
00278 {
00279 if ( DigitalOutInterface::nameserver.getObject("ThreadScope") )
00280 {
00281 d = DigitalOutInterface::nameserver.getObject("ThreadScope");
00282 }
00283 else
00284 {
00285 log(Warning) << "Failed to find 'ThreadScope' object in DigitalOutInterface::nameserver." << endlog();
00286 }
00287 }
00288 #endif
00289 int rv = rtos_task_create(&rtos_task, _priority, cpu_affinity, name.c_str(),
00290 msched_type, default_stack_size, thread_function, this);
00291 if (rv != 0)
00292 {
00293 log(Critical) << "Could not create thread "
00294 << rtos_task_get_name(&rtos_task) << "."
00295 << endlog();
00296 rtos_sem_destroy(&sem);
00297 #ifndef ORO_EMBEDDED
00298 throw std::bad_alloc();
00299 #else
00300 return;
00301 #endif
00302 }
00303
00304
00305 rtos_sem_wait( &sem );
00306
00307 const char* modname = getName();
00308 Logger::In in2(modname);
00309 log(Info) << "Thread created with scheduler type '"
00310 << getScheduler() << "', priority " << getPriority()
00311 << ", cpu affinity " << getCpuAffinity()
00312 << " and period " << getPeriod() << "." << endlog();
00313 #ifdef OROPKG_OS_THREAD_SCOPE
00314 if (d)
00315 {
00316 unsigned int bit = threadNumber();
00317 log(Info) << "ThreadScope :"<< modname <<" toggles bit "<< bit << endlog();
00318 }
00319 #endif
00320 }
00321
00322 Thread::~Thread()
00323 {
00324 Logger::In in("~Thread");
00325 if (this->isRunning())
00326 this->stop();
00327
00328 log(Debug) << "Terminating " << this->getName() << endlog();
00329 terminate();
00330 log(Debug) << " done" << endlog();
00331 rtos_sem_destroy(&sem);
00332
00333 }
00334
00335 bool Thread::start()
00336 {
00337 if ( period == 0)
00338 {
00339
00340 if ( isActive() ) {
00341 #ifndef OROPKG_OS_MACOSX
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 if ( rtos_sem_value(&sem) > 0 )
00353 return true;
00354 #endif
00355 rtos_sem_signal(&sem);
00356 return true;
00357 }
00358
00359 active=true;
00360 if ( this->initialize() == false || active == false ) {
00361 active = false;
00362 return false;
00363 }
00364
00365 running = true;
00366 rtos_sem_signal(&sem);
00367
00368 return true;
00369 }
00370 else {
00371
00372 if ( active )
00373 return false;
00374 active = true;
00375
00376 bool result;
00377 result = this->initialize();
00378
00379 if (result == false || active == false)
00380 {
00381 active = false;
00382 return false;
00383 }
00384
00385 running = true;
00386
00387
00388 rtos_task_make_periodic(&rtos_task, period);
00389 int ret = rtos_sem_signal(&sem);
00390 if (ret != 0)
00391 log(Critical)
00392 << "Thread::start(): sem_signal returns " << ret
00393 << endlog();
00394
00395
00396 return true;
00397 }
00398 }
00399
00400 bool Thread::stop()
00401 {
00402 if (!active)
00403 return false;
00404
00405 running = false;
00406
00407 if ( period == 0)
00408 {
00409 if ( inloop ) {
00410 if ( !this->breakLoop() ) {
00411 log(Warning) << "Failed to stop thread " << this->getName() << ": breakLoop() returned false."<<endlog();
00412 running = true;
00413 return false;
00414 }
00415
00416 }
00417
00418 MutexTimedLock lock(breaker, 1.0);
00419 if ( !lock.isSuccessful() ) {
00420 log(Error) << "Failed to stop thread " << this->getName() << ": breakLoop() returned true, but loop() function did not return after 1 second."<<endlog();
00421 running = true;
00422 return false;
00423 }
00424 } else {
00425
00426 MutexTimedLock lock(breaker, 10*getPeriod() );
00427 if ( lock.isSuccessful() ) {
00428
00429 rtos_task_make_periodic(&rtos_task, 0);
00430 } else {
00431 log(Error) << "Failed to stop thread " << this->getName() << ": step() function did not return after "<< 5*getPeriod() <<" seconds."<<endlog();
00432 running = true;
00433 return false;
00434 }
00435 }
00436
00437 this->finalize();
00438 active = false;
00439 return true;
00440 }
00441
00442 bool Thread::isRunning() const
00443 {
00444 return period == 0 ? inloop : running;
00445 }
00446
00447 bool Thread::isActive() const
00448 {
00449 return active;
00450 }
00451
00452 bool Thread::setScheduler(int sched_type)
00453 {
00454 Logger::In in("Thread::setScheduler");
00455 if (os::CheckScheduler(sched_type) == false)
00456 return false;
00457 if (this->getScheduler() == sched_type)
00458 {
00459 return true;
00460 }
00461
00462 log(Info) << "Setting scheduler type for Thread '"
00463 << rtos_task_get_name(&rtos_task) << "' to "
00464 << sched_type << endlog();
00465 rtos_task_set_scheduler(&rtos_task, sched_type);
00466 msched_type = sched_type;
00467 rtos_sem_signal(&sem);
00468 return true;
00469 }
00470
00471 int Thread::getScheduler() const
00472 {
00473 return rtos_task_get_scheduler(&rtos_task);
00474 }
00475
00476 void Thread::configure()
00477 {
00478
00479
00480
00481
00482
00483
00484
00485 rtos_task_set_period(&rtos_task, period);
00486
00487
00488 if (msched_type != rtos_task_get_scheduler(&rtos_task))
00489 {
00490 rtos_task_set_scheduler(&rtos_task, msched_type);
00491 msched_type = rtos_task_get_scheduler(&rtos_task);
00492 }
00493 }
00494
00495 void Thread::step()
00496 {
00497 }
00498
00499 void Thread::loop()
00500 {
00501 this->step();
00502 }
00503
00504 bool Thread::breakLoop()
00505 {
00506 return false;
00507 }
00508
00509
00510 bool Thread::initialize()
00511 {
00512 return true;
00513 }
00514
00515 void Thread::finalize()
00516 {
00517 }
00518
00519 bool Thread::setPeriod(double s)
00520 {
00521 nsecs nsperiod = Seconds_to_nsecs(s);
00522 return setPeriod(0, nsperiod);
00523 }
00524
00525 bool Thread::setPeriod(secs s, nsecs ns)
00526 {
00527 nsecs nsperiod = ns + 1000* 1000* 1000* s ;
00528 if (nsperiod < 0)
00529 return false;
00530
00531 if ( (nsperiod == 0 && period != 0) || (nsperiod != 0 && period == 0)) {
00532
00533
00534
00535 rtos_task_make_periodic(&rtos_task, nsperiod);
00536
00537 if ( period == 0) {
00538 period = nsperiod;
00539 rtos_sem_signal(&sem);
00540 }
00541 }
00542
00543 period = nsperiod;
00544
00545 return true;
00546 }
00547
00548 bool Thread::setPeriod( TIME_SPEC p)
00549 {
00550 return this->setPeriod( p.tv_sec, p.tv_nsec );
00551 }
00552
00553 void Thread::getPeriod(secs& s, nsecs& ns) const
00554 {
00555 s = secs(period/(1000*1000*1000));
00556 ns = period - s*1000*1000*1000;
00557 }
00558
00559 bool Thread::setPriority(int p)
00560 {
00561 return rtos_task_set_priority(&rtos_task, p) == 0;
00562 }
00563
00564 bool Thread::isPeriodic() const
00565 {
00566 return period != 0;
00567 }
00568
00569 int Thread::getPriority() const
00570 {
00571 return rtos_task_get_priority(&rtos_task);
00572 }
00573
00574 double Thread::getPeriod() const
00575 {
00576 return nsecs_to_Seconds(period);
00577 }
00578
00579 nsecs Thread::getPeriodNS() const
00580 {
00581 return period;
00582 }
00583
00584 bool Thread::setCpuAffinity(unsigned cpu_affinity)
00585 {
00586 return rtos_task_set_cpu_affinity(&rtos_task, cpu_affinity) == 0;
00587 }
00588
00589 unsigned Thread::getCpuAffinity() const
00590 {
00591 return rtos_task_get_cpu_affinity(&rtos_task);
00592 }
00593
00594 void Thread::yield()
00595 {
00596 rtos_task_yield( &rtos_task );
00597 }
00598
00599 void Thread::terminate()
00600 {
00601
00602 if (prepareForExit) return;
00603
00604 prepareForExit = true;
00605 rtos_sem_signal(&sem);
00606
00607 rtos_task_delete(&rtos_task);
00608 }
00609
00610 const char* Thread::getName() const
00611 {
00612 return rtos_task_get_name(&rtos_task);
00613 }
00614
00615 void Thread::setMaxOverrun( int m )
00616 {
00617 maxOverRun = m;
00618 }
00619
00620 int Thread::getMaxOverrun() const
00621 {
00622 return maxOverRun;
00623 }
00624
00625 void Thread::setWaitPeriodPolicy(int p)
00626 {
00627 rtos_task_set_wait_period_policy(&rtos_task, p);
00628 }
00629 }
00630 }
00631