Orocos Activity&ExecutionEngine 解析

原创 2016年06月01日 13:47:20

Orocos 每一个TaskContext 类表示一个完整的模块,该模块有configure,start,stop,clean,setPeriod等等方法来控制这个模块的运行。如果使用了该模块的 setActivity 方法,该模块将置于一个单独的线程中运行,根据自己的周期频率执行各个函数,读写dataport等。

setActivity 方法如下:

bool TaskContext::setActivity(ActivityInterface* new_act)  // Activity 继承于 ActivityInterface
{
    if (this->isRunning())
        return false;
    if ( new_act == 0) {
#if defined(ORO_ACT_DEFAULT_SEQUENTIAL)
        new_act = new SequentialActivity();
#elseif defined(ORO_ACT_DEFAULT_ACTIVITY)
        new_act = new Activity();  // 在这new了一个新的Activity,即创建了一个新的线程用于执行该模块。
#endif
    }
    new_act->stop();
    if(our_act){
        our_act->stop();
    }
    new_act->run( this->engine() );  // 这个模块所有需要运行的资源都是通过这个 ExecutionEngine 来执行的。
    our_act = ActivityInterface::shared_ptr( new_act );
    our_act->start();
    return true;
}

所以说,ExecutionEngine 是通过 Activity 来执行的,而 TaskContext 中的资源又是通过 ExecutionEngine 来执行的。归根到底是通过 Activity 来执行的 :)

其中每一个 Activity 类都表示一个线程:

class Activity : public base::ActivityInterface, public os::Thread

其中 os::Thread 类根据编译时所选择的平台可以是 gnulinux, xenomai, win32等线程的实现:

#ifdef OROPKG_OS_GNULINUX
 #include "gnulinux/fosi.h"
#endif

#ifdef OROPKG_OS_LXRT
 #include "lxrt/fosi.h"
#endif


#ifdef OROPKG_OS_XENOMAI
 #include "xenomai/fosi.h"
#endif

#ifdef OROPKG_OS_ECOS
 #include "ecos/fosi.h"
#endif

#ifdef OROPKG_OS_MACOSX
  #include "macosx/fosi.h"
#endif

#ifdef OROPKG_OS_WIN32
  #include "win32/fosi.h"
#endif

Thread 类结构如下:

class Thread: public ThreadInterface
{
    friend void* thread_function(void* t);  // 传入Activity的this指针(其中又保存了一个ExecutionEngine的指针),thread_function中实现一个while(1){...}来运行各种Hook,从而驱动顶层的 TaskContext 的运转。
public:
    Thread(int scheduler, int priority, double period, unsigned cpu_affinity,
           const std::string & name);  // 根据条件构造相应的线程

    virtual ~Thread();
    bool setPeriod(Seconds s);  // 执行周期,也可以为非周期性的
    ...
private:
    Thread(const Thread&);  // noncopiable
    ...
}

最关键的就是 thread_function 这个函数了,实现了线程的周期性执行,step执行等:

void *thread_function(void* t)
{
    /**
     * This is one time initialisation
     */
    Thread* task = static_cast<os::Thread*> (t);
    Logger::In in(task->getName());

    task->configure();

    // signal to setup() that we're created.
    rtos_sem_signal(&(task->sem));

    // This lock forces setup(), which holds the lock, to continue.
    { MutexLock lock(task->breaker); }
#ifdef OROPKG_OS_THREAD_SCOPE
    // order thread scope toggle bit on thread number
    unsigned int bit = task->threadNumber();
#endif
    SCOPE_OFF

    int overruns = 0, cur_sched = task->msched_type;
    NANO_TIME cur_period = task->period;

    while (!task->prepareForExit)
    {
        TRY(
            /**
             * The real task starts here.
             */
            while (1)
            {
                if (!task->active || (task->active && task->period == 0) || !task->running )
                {
                    // consider this the 'configuration or waiting for command state'
                    if (task->period != 0) {
                        overruns = 0;
                        // drop out of periodic mode:
                        rtos_task_set_period(task->getTask(), 0);
                    }
                    rtos_sem_wait(&(task->sem)); // wait for command.
                    task->configure();           // check for reconfigure
                    if (task->prepareForExit)    // check for exit
                    {
                        break; // break while(1) {}
                    }
                    // end of configuration
                }
                // This is the running state. Only enter if a task is running
                if ( task->running )
                {
                    if (task->period != 0) // periodic
                    {
                        MutexLock lock(task->breaker);
                        while(task->running && !task->prepareForExit )
                        {
                            TRY
                            (
                                SCOPE_ON
                                task->step(); // one cycle
                                SCOPE_OFF
                            )
                            CATCH_ALL
                            (
                                SCOPE_OFF
                                throw;
                            )

                            // Check changes in period
                            if ( cur_period != task->period) {
                                // reconfigure period before going to sleep
                                rtos_task_set_period(task->getTask(), task->period);
                                cur_period = task->period;
                                if (cur_period == 0)
                                    break; // break while(task->running) if no longer periodic
                            }

                            // Check changes in scheduler
                            if ( cur_sched != task->msched_type) {
                                rtos_task_set_scheduler(task->getTask(), task->msched_type);
                                cur_sched = task->msched_type;
                            }
                            // rtos_task_wait_period will return immediately if
                            // the task is not periodic (ie period == 0)
                            // return non-zero to indicate overrun.
                            if (rtos_task_wait_period(task->getTask()) != 0)
                            {
                                ++overruns;
                                if (overruns == task->maxOverRun)
                                    break; // break while(task->running)
                            }
                            else if (overruns != 0)
                                --overruns;
                        } // while(task->running)
                        if (overruns == task->maxOverRun || task->prepareForExit)
                            break; // break while(1) {}
                    }
                    else // non periodic:
                    TRY
                    (
                        // this mutex guarantees that stop() waits
                        // until loop() returns.
                        MutexLock lock(task->breaker);

                        task->inloop = true;
                        SCOPE_ON
                        task->loop();
                        SCOPE_OFF
                        task->inloop = false;
                    ) CATCH_ALL
                    (
                        SCOPE_OFF
                        task->inloop = false;
                        throw;
                    )
                }
            } // while(1)
            if (overruns == task->maxOverRun)
            {
                task->emergencyStop();
                Logger::In in(rtos_task_get_name(task->getTask()));
                log(Critical) << rtos_task_get_name(task->getTask())
                        << " got too many periodic overruns in step() ("
                        << overruns << " times), stopped Thread !"
                        << endlog();
                log()   << " See Thread::setMaxOverrun() for info."
                        << endlog();
            }
        )CATCH(std::exception const& e,
            SCOPE_OFF
            task->emergencyStop();
            Logger::In in(rtos_task_get_name(task->getTask()));
            log(Critical) << rtos_task_get_name(task->getTask())
                    << " caught a C++ exception, stopped thread !"
                    << endlog();
            log(Critical) << "exception was: "
                       << e.what() << endlog();
        ) CATCH_ALL
        (
            SCOPE_OFF
            task->emergencyStop();
            Logger::In in(rtos_task_get_name(task->getTask()));
            log(Critical) << rtos_task_get_name(task->getTask())
                    << " caught an unknown C++ exception, stopped thread !"
                    << endlog();
        )
    } // while (!prepareForExit)

    return 0;
}

void Thread::emergencyStop()
{
    // set state to not running
    this->running = false;
    this->inloop  = false;
    this->active  = false;
    // execute finalize in current mode, even if hard.
    this->finalize();
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

scrapy源码分析(八)--------ExecutionEngine

上一节分析了Crawler的源码,其中关键方法crawl最后会调用ExecutionEngine的open_spider和start方法。本节就结合ExecutionEngine的源码进行详细分析。 ...

scrapy源码分析(二)----------ExecutionEngine(一)主循环

ExecutionEngine是scrapy的核心模块之一,顾名思义是执行引擎。 它驱动了整个爬取的开始,进行,关闭。 它又使用了如下几个主要模块来为其工作: 1.slot:它使用Twisted的主...

OROCOS 网上注释文档

博客分类: 机器人和PLC Twist是代表速度和角速度的6x1矩阵,Wrench是代表力和力矩的6x1矩阵,两者可相互转化 KDL::Twist link to API ...

orocos 的数据表示(模板template): DataObject (还有一条主线为 DataSource)

数据有不同的type(int,double,struct…),还有 c-v qualifier, 还可以是 reference、pointer、array等等。因此,在处理数据的时候要正确区分每一种数...

orocos rtt with xenomai &amp; kuka lwr

  • 2017年03月01日 14:18
  • 2.49MB
  • 下载

orocos 类型系统分析

其实代码分析是完整的,需要点耐心才能看完。。。在 orocos 中所有类型的信息是通过一个叫 TypeInfo 的结构体来保存的,每增加一种类型就会 new 一个 TypeInfo 对象来表示该类型的...

typeinfo dynamic_cast & 模板编程 & orocos OperationCaller 类的设计

dynamic_cast 判断该基类指针到底指向哪一类派生类: dynamic_cast 就是运用 RTTI 来判断该指针所指的对象的 typeinfo (一般位于 virtual table 的...

编译 linux kernel + xenomai 2/3(在orocos中需要注意资源配置)

尊重原作,从github拷贝的,以免翻墙或者找不到。 原作链接:https://github.com/kuka-isir/rtt_lwr/blob/rtt_lwr-2.0/docs/source/r...

ROS节点与OROCOS组件通信--构建组件

完成ROS、orocos_toolchain、rtt_ros_integration三个部分的安装后,开始构建orocos组件。 一、构建catkin编译包 使用ocl脚本构建orocos的cat...
  • sukha
  • sukha
  • 2014年12月17日 08:54
  • 1554
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Orocos Activity&ExecutionEngine 解析
举报原因:
原因补充:

(最多只允许输入30个字)