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 <os/PeriodicThread.hpp>
00040 #include <os/Time.hpp>
00041 #include "os/threads.hpp"
00042 #include "Logger.hpp"
00043
00044 #include "../rtt-config.h"
00045
00046 #ifdef OROPKG_OS_THREAD_SCOPE
00047 # include "dev/DigitalOutInterface.hpp"
00048 #endif
00049
00050 namespace RTT
00051 { namespace OS {
00052 using RTT::Logger;
00053 using namespace detail;
00054
00055 void *periodicThread(void* t)
00056 {
00060 PeriodicThread* task = static_cast<OS::PeriodicThread*> (t);
00061
00062
00063 task->configure();
00064
00065 #ifdef OROPKG_OS_THREAD_SCOPE
00066
00067 unsigned int bit = task->threadNumber();
00068 if ( task->d )
00069 task->d->switchOff( bit );
00070 #endif // OROPKG_OS_THREAD_SCOPE
00071 int overruns = 0;
00072 while ( !task->prepareForExit ) {
00073 #ifndef ORO_EMBEDDED
00074 try {
00075 #endif // !ORO_EMBEDDED
00076
00079 while(1)
00080 {
00081 if( !task->running ) {
00082
00083 overruns = 0;
00084
00085 rtos_task_set_period(task->getTask(), 0);
00086
00087 rtos_sem_signal( &(task->confDone) );
00088
00089 rtos_sem_wait( &(task->sem) );
00090
00091 task->configure();
00092
00093 if ( task->prepareForExit )
00094 {
00095 break;
00096 }
00097
00098 } else {
00099
00100 #ifdef OROPKG_OS_THREAD_SCOPE
00101 if ( task->d )
00102 task->d->switchOn( bit );
00103 #endif
00104 {
00105 task->step();
00106 }
00107 #ifdef OROPKG_OS_THREAD_SCOPE
00108 if ( task->d )
00109 task->d->switchOff( bit );
00110 #endif
00111
00112 if ( rtos_task_wait_period( task->getTask() ) != 0) {
00113 ++overruns;
00114 if ( overruns == task->maxOverRun )
00115 break;
00116 } else if ( overruns != 0 )
00117 --overruns;
00118 }
00119 }
00120 if ( overruns == task->maxOverRun ) {
00121 #ifdef OROPKG_OS_THREAD_SCOPE
00122 if ( task->d )
00123 task->d->switchOff( bit );
00124 #endif
00125 task->emergencyStop();
00126 Logger::In in(rtos_task_get_name(task->getTask()));
00127 Logger::log() << Logger::Fatal << rtos_task_get_name(task->getTask()) <<" got too many periodic overruns in step() ("<< overruns << " times), stopped Thread !"<<Logger::nl;
00128 Logger::log() <<" See PeriodicThread::setMaxOverrun() for info." << Logger::endl;
00129 }
00130 #ifndef ORO_EMBEDDED
00131 } catch( ... ) {
00132 #ifdef OROPKG_OS_THREAD_SCOPE
00133 if ( task->d )
00134 task->d->switchOff( bit );
00135 #endif
00136 task->emergencyStop();
00137 Logger::In in(rtos_task_get_name(task->getTask()));
00138 Logger::log() << Logger::Fatal << rtos_task_get_name(task->getTask()) <<" caught a C++ exception, stopped thread !"<<Logger::endl;
00139 }
00140 #endif // !ORO_EMBEDDED
00141 }
00142
00143 rtos_sem_signal( &(task->confDone));
00144
00145 return 0;
00146 }
00147
00148 void PeriodicThread::emergencyStop()
00149 {
00150
00151 this->running = false;
00152
00153 this->finalize();
00154 }
00155
00156 PeriodicThread::PeriodicThread(int _priority,
00157 const std::string & name,
00158 Seconds periods,
00159 RunnableInterface* r) :
00160 msched_type(ORO_SCHED_RT), running(false), prepareForExit(false),
00161 wait_for_step(true), runComp(r),
00162 maxOverRun( OROSEM_OS_PERIODIC_THREADS_MAX_OVERRUN),
00163 period(Seconds_to_nsecs(periods))
00164 #ifdef OROPKG_OS_THREAD_SCOPE
00165 ,d(NULL)
00166 #endif
00167 {
00168 this->setup(_priority, name);
00169 }
00170
00171 PeriodicThread::PeriodicThread(int scheduler, int _priority,
00172 const std::string & name,
00173 Seconds periods,
00174 RunnableInterface* r) :
00175 msched_type(scheduler), running(false), prepareForExit(false),
00176 wait_for_step(true), runComp(r),
00177 maxOverRun( OROSEM_OS_PERIODIC_THREADS_MAX_OVERRUN),
00178 period(Seconds_to_nsecs(periods))
00179 #ifdef OROPKG_OS_THREAD_SCOPE
00180 ,d(NULL)
00181 #endif
00182 {
00183 log(Info) << "Creating PeriodicThread for scheduler: "<< scheduler << endlog();
00184 this->setup(_priority, name);
00185 }
00186
00187 void PeriodicThread::setup(int _priority, const std::string& name)
00188 {
00189 Logger::In in("PeriodicThread");
00190 int ret;
00191
00192 ret = rtos_sem_init(&sem, 0);
00193 if ( ret != 0 ) {
00194 Logger::log() << Logger::Critical << "Could not allocate configuration semaphore 'sem' for "<< rtos_task_get_name(&rtos_task) <<". Throwing std::bad_alloc."<<Logger::endl;
00195 rtos_sem_destroy( &sem );
00196 #ifndef ORO_EMBEDDED
00197 throw std::bad_alloc();
00198 #else
00199 return;
00200 #endif
00201 }
00202
00203 ret = rtos_sem_init(&confDone, 0);
00204 if ( ret != 0 ) {
00205 Logger::log() << Logger::Critical << "Could not allocate configuration semaphore 'confDone' for "<< rtos_task_get_name(&rtos_task) <<". Throwing std::bad_alloc."<<Logger::endl;
00206 rtos_sem_destroy( &sem );
00207 #ifndef ORO_EMBEDDED
00208 throw std::bad_alloc();
00209 #else
00210 return;
00211 #endif
00212 }
00213
00214 if (runComp)
00215 runComp->setThread(this);
00216 #ifdef OROPKG_OS_THREAD_SCOPE
00217
00218 {
00219 if ( DigitalOutInterface::nameserver.getObject("ThreadScope") ){
00220 d = DigitalOutInterface::nameserver.getObject("ThreadScope");
00221 }
00222 else{
00223 log(Warning) << "Failed to find 'ThreadScope' object in DigitalOutInterface::nameserver." << endlog();
00224 }
00225 }
00226 #endif
00227 int rv = rtos_task_create(&rtos_task, _priority, name.c_str(), msched_type, periodicThread, this );
00228 if ( rv != 0 ) {
00229 Logger::log() << Logger::Critical << "Could not create thread "
00230 << rtos_task_get_name(&rtos_task) <<"."<<Logger::endl;
00231 rtos_sem_destroy( &sem );
00232 rtos_sem_destroy( &confDone );
00233 #ifndef ORO_EMBEDDED
00234 throw std::bad_alloc();
00235 #else
00236 return;
00237 #endif
00238 }
00239
00240 rtos_sem_wait(&confDone);
00241
00242 const char* modname = getName();
00243 Logger::In in2(modname);
00244 log(Info)<< "PeriodicThread created with scheduler type '"<< getScheduler() <<"', priority " << getPriority()
00245 <<" and period "<< getPeriod() << "." << endlog();
00246 #ifdef OROPKG_OS_THREAD_SCOPE
00247 if (d){
00248 unsigned int bit = threadNumber();
00249 log(Info) << "ThreadScope :"<< modname <<" toggles bit "<< bit << endlog();
00250 }
00251 #endif
00252 }
00253
00254 PeriodicThread::~PeriodicThread()
00255 {
00256 Logger::In in("~PeriodicThread");
00257 if (this->isRunning())
00258 this->stop();
00259
00260 log(Debug) << "Terminating "<< this->getName() <<endlog();
00261 terminate();
00262 log(Debug) << " done"<< endlog();
00263 rtos_sem_destroy(&confDone);
00264 rtos_sem_destroy(&sem);
00265
00266 if (runComp)
00267 runComp->setThread(0);
00268
00269 }
00270
00271 bool PeriodicThread::run( RunnableInterface* r)
00272 {
00273 if ( isRunning() )
00274 return false;
00275 if (runComp)
00276 runComp->setThread(0);
00277 runComp = r;
00278 if (runComp)
00279 runComp->setThread(this);
00280 return true;
00281 }
00282
00283
00284 bool PeriodicThread::start()
00285 {
00286 if ( running ) return false;
00287
00288 Logger::log() << Logger::Debug << "Periodic Thread "<< rtos_task_get_name(&rtos_task) <<" started."<<Logger::endl;
00289
00290 bool result;
00291 result = this->initialize();
00292
00293 if (result == false) {
00294 Logger::log() << Logger::Critical << "Periodic Thread "<< rtos_task_get_name(&rtos_task) <<" failed to initialize()."<<Logger::endl;
00295 return false;
00296 }
00297
00298 running=true;
00299
00300
00301
00302 rtos_sem_trywait( &confDone );
00303
00304 rtos_task_make_periodic(&rtos_task, period );
00305 int ret = rtos_sem_signal(&sem);
00306 if ( ret != 0 )
00307 Logger::log() << Logger::Critical <<"PeriodicThread::start(): sem_signal returns "<< ret << Logger::endl;
00308
00309
00310 return true;
00311 }
00312
00313 bool PeriodicThread::stop()
00314 {
00315 if ( !running ) return false;
00316
00317 Logger::log() << Logger::Debug << "Periodic Thread "<< rtos_task_get_name(&rtos_task) <<" stopping...";
00318
00319 running=false;
00320 int cnt = 0;
00321 int ret = -1;
00322
00323
00324
00325 while ( ret == -1 && cnt < 10 )
00326 {
00327
00328 ret = rtos_sem_wait_timed( &confDone, 5*period );
00329
00330 cnt++;
00331 }
00332
00333 if ( ret != 0 ) {
00334 Logger::log() << Logger::Debug << " failed."<<Logger::endl;
00335 Logger::log() << Logger::Critical << "The "<< rtos_task_get_name(&rtos_task) <<" thread seems to be blocked ( ret was "<< ret<<" .)"<<Logger::nl;
00336 }
00337 else
00338 Logger::log() << Logger::Debug << " done."<<Logger::endl;
00339
00340 rtos_task_make_periodic(&rtos_task, 0);
00341
00342
00343
00344
00345 this->finalize();
00346
00347 return true;
00348 }
00349
00350 bool PeriodicThread::isRunning() const
00351 {
00352 return running;
00353 }
00354
00355 bool PeriodicThread::setScheduler(int sched_type)
00356 {
00357 if ( !running )
00358 {
00359 if ( OS::CheckScheduler(sched_type) == false)
00360 return false;
00361 if ( this->getScheduler() == sched_type ) {
00362 log(Debug) << "Scheduler type for Thread "<< rtos_task_get_name(&rtos_task) <<" is already configured as "<< sched_type << endlog();
00363 return true;
00364 }
00365
00366 log(Error) << "Setting scheduler type for Thread "<< rtos_task_get_name(&rtos_task) <<" to "<< sched_type;
00367 msched_type = sched_type;
00368 rtos_sem_signal(&sem);
00369 rtos_sem_wait(&confDone);
00370 }
00371 else {
00372 log() << "Failed to change scheduler for "<< rtos_task_get_name(&rtos_task) <<" since thread is still running."<<endlog(Warning);
00373 return false;
00374 }
00375 if (msched_type != rtos_task_get_scheduler(&rtos_task) )
00376 {
00377 msched_type = rtos_task_get_scheduler(&rtos_task);
00378 log() << ": failed."<<endlog(Error);
00379 return false;
00380 }
00381 log() << ": done."<<endlog(Debug);
00382 return true;
00383
00384 #if 0
00385
00386 if ( rtos_task_set_scheduler(&rtos_task, sched_type) == 0)
00387 return true;
00388 return false;
00389 #endif
00390 }
00391 int PeriodicThread::getScheduler() const
00392 {
00393 return rtos_task_get_scheduler(&rtos_task);
00394 }
00395
00396 void PeriodicThread::configure()
00397 {
00398
00399 if ( wait_for_step )
00400 rtos_task_set_period(&rtos_task, period );
00401 else
00402 rtos_task_set_period(&rtos_task, 0);
00403
00404 if ( msched_type != rtos_task_get_scheduler(&rtos_task) )
00405 {
00406 rtos_task_set_scheduler( &rtos_task, msched_type );
00407 msched_type = rtos_task_get_scheduler(&rtos_task);
00408 }
00409 }
00410
00411
00412 void PeriodicThread::step()
00413 {
00414 if ( runComp )
00415 runComp->step();
00416 }
00417
00418 bool PeriodicThread::initialize()
00419 {
00420 if ( runComp )
00421 return runComp->initialize();
00422
00423 return true;
00424 }
00425
00426 void PeriodicThread::finalize()
00427 {
00428 if ( runComp )
00429 runComp->finalize();
00430 }
00431
00432 bool PeriodicThread::setPeriod( double s )
00433 {
00434 if ( isRunning() )
00435 return false;
00436
00437 period = Seconds_to_nsecs(s);
00438
00439
00440 rtos_sem_signal(&sem);
00441 rtos_sem_wait(&confDone);
00442
00443 return true;
00444 }
00445
00446 bool PeriodicThread::setPeriod(secs s, nsecs ns)
00447 {
00448 if ( isRunning() ) return false;
00449 period = ns + 1000*1000*1000*s;
00450
00451
00452 rtos_sem_signal(&sem);
00453 rtos_sem_wait(&confDone);
00454
00455 return true;
00456 }
00457
00458 bool PeriodicThread::setPeriod( TIME_SPEC p)
00459 {
00460 return this->setPeriod( p.tv_sec, p.tv_nsec );
00461 }
00462
00463 void PeriodicThread::getPeriod(secs& s, nsecs& ns) const
00464 {
00465 s = period/(1000*1000*1000);
00466 ns = period - s*1000*1000*1000;
00467 }
00468
00469 bool PeriodicThread::setPriority(int p)
00470 {
00471 return rtos_task_set_priority(&rtos_task, p) == 0;
00472 }
00473
00474 int PeriodicThread::getPriority() const
00475 {
00476 return rtos_task_get_priority(&rtos_task);
00477 }
00478
00479 double PeriodicThread::getPeriod() const
00480 {
00481 return nsecs_to_Seconds(period);
00482 }
00483
00484 nsecs PeriodicThread::getPeriodNS() const
00485 {
00486 return period;
00487 }
00488
00489 void PeriodicThread::yield() {
00490 rtos_task_yield( &rtos_task );
00491 }
00492
00493
00494 void PeriodicThread::continuousStepping(bool yes_no)
00495 {
00496 wait_for_step = !yes_no;
00497
00498 }
00499
00500 void PeriodicThread::terminate()
00501 {
00502
00503 if (prepareForExit) return;
00504
00505 prepareForExit = true;
00506 rtos_sem_signal(&sem);
00507
00508 rtos_sem_wait(&confDone);
00509 rtos_task_delete(&rtos_task);
00510
00511 }
00512
00513 bool PeriodicThread::setToStop()
00514 {
00515 running = false;
00516 this->finalize();
00517 return true;
00518 }
00519
00520 const char* PeriodicThread::getName() const
00521 {
00522 return rtos_task_get_name(&rtos_task);
00523 }
00524
00525 void PeriodicThread::setMaxOverrun( int m )
00526 {
00527 maxOverRun = m;
00528 }
00529
00530 int PeriodicThread::getMaxOverrun() const
00531 {
00532 return maxOverRun;
00533 }
00534
00535 }}
00536