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 == ORO_SCHED_OTHER ? "ORO_SCHED_OTHER" : "ORO_SCHED_RT")
00260 << ", priority=" << _priority
00261 << ", CPU affinity=" << cpu_affinity
00262 << ", with name='" << name << "'"
00263 << endlog();
00264 ret = rtos_sem_init(&sem, 0);
00265 if (ret != 0)
00266 {
00267 log(Critical)
00268 << "Could not allocate configuration semaphore 'sem' for "
00269 << name
00270 << ". Throwing std::bad_alloc." << endlog();
00271 rtos_sem_destroy(&sem);
00272 #ifndef ORO_EMBEDDED
00273 throw std::bad_alloc();
00274 #else
00275 return;
00276 #endif
00277 }
00278
00279 #ifdef OROPKG_OS_THREAD_SCOPE
00280
00281
00282 {
00283 if ( DigitalOutInterface::nameserver.getObject("ThreadScope") )
00284 {
00285 d = DigitalOutInterface::nameserver.getObject("ThreadScope");
00286 }
00287 else
00288 {
00289 log(Warning) << "Failed to find 'ThreadScope' object in DigitalOutInterface::nameserver." << endlog();
00290 }
00291 }
00292 #endif
00293 int rv = rtos_task_create(&rtos_task, _priority, cpu_affinity, name.c_str(),
00294 msched_type, default_stack_size, thread_function, this);
00295 if (rv != 0)
00296 {
00297 log(Critical) << "Could not create thread "
00298 << name << "."
00299 << endlog();
00300 rtos_sem_destroy(&sem);
00301 #ifndef ORO_EMBEDDED
00302 throw std::bad_alloc();
00303 #else
00304 return;
00305 #endif
00306 }
00307
00308
00309 rtos_sem_wait( &sem );
00310
00311 const char* modname = getName();
00312 Logger::In in2(modname);
00313 log(Info) << "Thread created with scheduler type '"
00314 << (getScheduler() == ORO_SCHED_OTHER ? "ORO_SCHED_OTHER" : "ORO_SCHED_RT") << "', priority " << getPriority()
00315 << ", cpu affinity " << getCpuAffinity()
00316 << " and period " << getPeriod() << " (PID= " << getPid() << " )." << endlog();
00317 #ifdef OROPKG_OS_THREAD_SCOPE
00318 if (d)
00319 {
00320 unsigned int bit = threadNumber();
00321 log(Info) << "ThreadScope :"<< modname <<" toggles bit "<< bit << endlog();
00322 }
00323 #endif
00324 }
00325
00326 Thread::~Thread()
00327 {
00328 Logger::In in("~Thread");
00329 if (this->isRunning())
00330 this->stop();
00331
00332 log(Debug) << "Terminating " << this->getName() << endlog();
00333 terminate();
00334 log(Debug) << " done" << endlog();
00335 rtos_sem_destroy(&sem);
00336
00337 }
00338
00339 bool Thread::start()
00340 {
00341 if ( period == 0)
00342 {
00343
00344 if ( isActive() ) {
00345 #ifndef OROPKG_OS_MACOSX
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 if ( rtos_sem_value(&sem) > 0 )
00357 return true;
00358 #endif
00359 rtos_sem_signal(&sem);
00360 return true;
00361 }
00362
00363 active=true;
00364 if ( this->initialize() == false || active == false ) {
00365 active = false;
00366 return false;
00367 }
00368
00369 running = true;
00370 rtos_sem_signal(&sem);
00371
00372 return true;
00373 }
00374 else {
00375
00376 if ( active )
00377 return false;
00378 active = true;
00379
00380 bool result;
00381 result = this->initialize();
00382
00383 if (result == false || active == false)
00384 {
00385 active = false;
00386 return false;
00387 }
00388
00389 running = true;
00390
00391
00392 rtos_task_make_periodic(&rtos_task, period);
00393 int ret = rtos_sem_signal(&sem);
00394 if (ret != 0)
00395 log(Critical)
00396 << "Thread::start(): sem_signal returns " << ret
00397 << endlog();
00398
00399
00400 return true;
00401 }
00402 }
00403
00404 bool Thread::stop()
00405 {
00406 if (!active)
00407 return false;
00408
00409 running = false;
00410
00411 if ( period == 0)
00412 {
00413 if ( inloop ) {
00414 if ( !this->breakLoop() ) {
00415 log(Warning) << "Failed to stop thread " << this->getName() << ": breakLoop() returned false."<<endlog();
00416 running = true;
00417 return false;
00418 }
00419
00420 }
00421
00422 MutexTimedLock lock(breaker, 1.0);
00423 if ( !lock.isSuccessful() ) {
00424 log(Error) << "Failed to stop thread " << this->getName() << ": breakLoop() returned true, but loop() function did not return after 1 second."<<endlog();
00425 running = true;
00426 return false;
00427 }
00428 } else {
00429
00430 MutexTimedLock lock(breaker, 10*getPeriod() );
00431 if ( lock.isSuccessful() ) {
00432
00433 rtos_task_make_periodic(&rtos_task, 0);
00434 } else {
00435 log(Error) << "Failed to stop thread " << this->getName() << ": step() function did not return after "<< 5*getPeriod() <<" seconds."<<endlog();
00436 running = true;
00437 return false;
00438 }
00439 }
00440
00441 this->finalize();
00442 active = false;
00443 return true;
00444 }
00445
00446 bool Thread::isRunning() const
00447 {
00448 return period == 0 ? inloop : running;
00449 }
00450
00451 bool Thread::isActive() const
00452 {
00453 return active;
00454 }
00455
00456 bool Thread::setScheduler(int sched_type)
00457 {
00458 Logger::In in("Thread::setScheduler");
00459 if (os::CheckScheduler(sched_type) == false)
00460 return false;
00461 if (this->getScheduler() == sched_type)
00462 {
00463 return true;
00464 }
00465
00466 log(Info) << "Setting scheduler type for Thread '"
00467 << rtos_task_get_name(&rtos_task) << "' to "
00468 << sched_type << endlog();
00469 rtos_task_set_scheduler(&rtos_task, sched_type);
00470 msched_type = sched_type;
00471 rtos_sem_signal(&sem);
00472 return true;
00473 }
00474
00475 int Thread::getScheduler() const
00476 {
00477 return rtos_task_get_scheduler(&rtos_task);
00478 }
00479
00480 void Thread::configure()
00481 {
00482
00483
00484
00485
00486
00487
00488
00489 rtos_task_set_period(&rtos_task, period);
00490
00491
00492 if (msched_type != rtos_task_get_scheduler(&rtos_task))
00493 {
00494 rtos_task_set_scheduler(&rtos_task, msched_type);
00495 msched_type = rtos_task_get_scheduler(&rtos_task);
00496 }
00497 }
00498
00499 void Thread::step()
00500 {
00501 }
00502
00503 void Thread::loop()
00504 {
00505 this->step();
00506 }
00507
00508 bool Thread::breakLoop()
00509 {
00510 return false;
00511 }
00512
00513
00514 bool Thread::initialize()
00515 {
00516 return true;
00517 }
00518
00519 void Thread::finalize()
00520 {
00521 }
00522
00523 bool Thread::setPeriod(double s)
00524 {
00525 nsecs nsperiod = Seconds_to_nsecs(s);
00526 return setPeriod(0, nsperiod);
00527 }
00528
00529 bool Thread::setPeriod(secs s, nsecs ns)
00530 {
00531 nsecs nsperiod = ns + 1000* 1000* 1000* s ;
00532 if (nsperiod < 0)
00533 return false;
00534
00535 if ( (nsperiod == 0 && period != 0) || (nsperiod != 0 && period == 0)) {
00536
00537
00538
00539 rtos_task_make_periodic(&rtos_task, nsperiod);
00540
00541 if ( period == 0) {
00542 period = nsperiod;
00543 rtos_sem_signal(&sem);
00544 }
00545 }
00546
00547 period = nsperiod;
00548
00549 return true;
00550 }
00551
00552 bool Thread::setPeriod( TIME_SPEC p)
00553 {
00554 return this->setPeriod( p.tv_sec, p.tv_nsec );
00555 }
00556
00557 void Thread::getPeriod(secs& s, nsecs& ns) const
00558 {
00559 s = secs(period/(1000*1000*1000));
00560 ns = period - s*1000*1000*1000;
00561 }
00562
00563 bool Thread::setPriority(int p)
00564 {
00565 return rtos_task_set_priority(&rtos_task, p) == 0;
00566 }
00567
00568 bool Thread::isPeriodic() const
00569 {
00570 return period != 0;
00571 }
00572
00573 int Thread::getPriority() const
00574 {
00575 return rtos_task_get_priority(&rtos_task);
00576 }
00577
00578 double Thread::getPeriod() const
00579 {
00580 return nsecs_to_Seconds(period);
00581 }
00582
00583 nsecs Thread::getPeriodNS() const
00584 {
00585 return period;
00586 }
00587
00588 bool Thread::setCpuAffinity(unsigned cpu_affinity)
00589 {
00590 return rtos_task_set_cpu_affinity(&rtos_task, cpu_affinity) == 0;
00591 }
00592
00593 unsigned Thread::getCpuAffinity() const
00594 {
00595 return rtos_task_get_cpu_affinity(&rtos_task);
00596 }
00597
00598 unsigned int Thread::getPid() const
00599 {
00600 return rtos_task_get_pid(&rtos_task);
00601 }
00602
00603 void Thread::yield()
00604 {
00605 rtos_task_yield( &rtos_task );
00606 }
00607
00608 void Thread::terminate()
00609 {
00610
00611 if (prepareForExit) return;
00612
00613 prepareForExit = true;
00614 rtos_sem_signal(&sem);
00615
00616 rtos_task_delete(&rtos_task);
00617 }
00618
00619 const char* Thread::getName() const
00620 {
00621 return rtos_task_get_name(&rtos_task);
00622 }
00623
00624 void Thread::setMaxOverrun( int m )
00625 {
00626 maxOverRun = m;
00627 }
00628
00629 int Thread::getMaxOverrun() const
00630 {
00631 return maxOverRun;
00632 }
00633
00634 void Thread::setWaitPeriodPolicy(int p)
00635 {
00636 rtos_task_set_wait_period_policy(&rtos_task, p);
00637 }
00638 }
00639 }
00640