ecos kernel 分析 转自黑嘴公 PiPi Cat



    ecos kernel 是个典型的抢占式多任务的rtos,我这里想从代码上,把它的实现搭个框架出来。

    分时的多任务系统是靠定时时间中断实现的,所以我从这里做切入点

有kernel 的ecos重写了interrupt 处理代码,原来的在drv_api.c里实现的,现在的在kernel/intr/intr.cxx里,时间中断的注册在kernel/common/clock.cxx里

 

Cyg_RealTimeClock Cyg_RealTimeClock::rtc CYG_INIT_PRIORITY( CLOCK );

 

// -------------------------------------------------------------------------

 

Cyg_RealTimeClock::Cyg_RealTimeClock()

    : Cyg_Clock(rtc_resolution),

      interrupt(CYGNUM_HAL_INTERRUPT_RTC,

                CYGNUM_KERNEL_COUNTERS_CLOCK_ISR_PRIORITY,

                (CYG_ADDRWORD)this, isr, dsr)

{

    CYG_REPORT_FUNCTION();

 

    HAL_CLOCK_INITIALIZE( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );

   

    interrupt.attach();

    interrupt.unmask_interrupt(CYGNUM_HAL_INTERRUPT_RTC);

 

    Cyg_Clock::real_time_clock = this;

}

中断的注册很好理解,但这里有个有趣的是这个函数是怎样被调用到的,直接搜索ecos所有的代码是找不到的。一般我们有个概念c++的类在声明后就会被自动调用里面和自己名字一样的那个函数,(很久没有接触c++,忘记叫什么名字了)

这里也是这样,这里第一句就是声明这个实例,然后编译器会把这个函数放到一个特殊的段__CTOR_LIST__里面(target.ld),

然后cyg_hal_invoke_constructors()会遍历__CTOR_LIST__并执行所有的函数,cyg_hal_invoke_constructors() 是在vector.S里面被调用到的。这个“自动调用”就是这样实现的。

    再看时间中断服务程序,ecos 把中断服务分为两块ISR和DSR,ISR里只做些最简单的事情,发生中断后会被直接调到,以保证kernel快速响应的效果。把其他的事情都放到DSR里面,DSR会被稍后调用,先看DSR里面代码

// -------------------------------------------------------------------------

void Cyg_RealTimeClock::dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data)

{

//    CYG_REPORT_FUNCTION();

 

    Cyg_RealTimeClock *rtc = (Cyg_RealTimeClock *)data;

 

    CYG_INSTRUMENT_CLOCK( TICK_START,

                          rtc->current_value_lo(),

                          rtc->current_value_hi());

>>这里是提供系统时钟

    rtc->tick( count );

#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE

#if    0 == CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES

 

    // If timeslicing is enabled, call the scheduler to

    // handle it. But not if we have unique priorities.

>>分时多任务的处理,它的实现在算法里,我以mlqueue为例

    Cyg_Scheduler::scheduler.timeslice();

 

#endif

#endif

 

    CYG_INSTRUMENT_CLOCK( TICK_END,

                          rtc->current_value_lo(),

                          rtc->current_value_hi());

   

}

 

timeslice()调用timeslice_cpu(),timeslice_cpu里要找出同一priority任务队列中下一个任务,如果有,则设置reschedule的标志:需要做任务切换。

到这里这条路就断了。但是前面我没有讲到DSR是怎样被调到的,这里要看interrupt_end()

在vector.S里被调到,interrupt_end代码在kernel/intr/intr.cxx里

 

//-------------------------------------

externC void

interrupt_end(

    cyg_uint32          isr_ret,

    Cyg_Interrupt       *intr,

    HAL_SavedRegisters  *regs

    )

{

//    CYG_REPORT_FUNCTION();

 

#ifdef CYGPKG_KERNEL_SMP_SUPPORT

    Cyg_Scheduler::lock();

#endif

   

    // Sometimes we have a NULL intr object pointer.

    cyg_vector vector = (intr!=NULL)?intr->vector:0;

 

    CYG_INSTRUMENT_INTR(END, vector, isr_ret);

   

    CYG_UNUSED_PARAM( cyg_vector, vector ); // prevent compiler warning

   

#ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN

 

    // Only do this if we are in a non-chained configuration.

    // If we are chained, then chain_isr below will do the DSR

    // posting.

>>这里把当前的DSR post出去,其实就是加入一个DSR 任务链表里去,之后再拿出来处理

    if( isr_ret & Cyg_Interrupt::CALL_DSR && intr != NULL ) intr->post_dsr();

 

#endif   

 

 

    // Now unlock the scheduler, which may also call DSRs

    // and cause a thread switch to happen.

>>这里就是多任务处理的入口了,下面再去看里面的实现

    Cyg_Scheduler::unlock();

 

    CYG_INSTRUMENT_INTR(RESTORE, vector, 0);   

}

 

unlock()会调用unlock_inner,unlock_inner是kernel最重要的一个函数了,它是多任务切换的

执行者,来看它的实现,代码很长,只挑其中一段

 

//-------------------------------------

void Cyg_Scheduler::unlock_inner( cyg_ucount32 new_lock )

{

 

    do {

 

#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS

       

        // Call any pending DSRs. Do this here to ensure that any

        // threads that get awakened are properly scheduled.

>>调用前面post的所有的DSR,注意里面会有reschedule flag的设置

>>下面就要用到

        if( new_lock == 0 && Cyg_Interrupt::DSRs_pending() )

            Cyg_Interrupt::call_pending_DSRs();

#endif

 

        Cyg_Thread *current = get_current_thread();

 

        // If the current thread is going to sleep, or someone

        // wants a reschedule, choose another thread to run

>>这里有几种情况需要处理,一个是当前的任务主动要求休息(调用yield()),当然就要切换给别的任务;

>>另外一个就是在DSR的timeslice中找到优先级相同的下个任务需要运行;

>>还有一种是当有新的高优先级的任务加入。(所有都会调用set_need_reschedule())        if( current->state != Cyg_Thread::RUNNING || get_need_reschedule() ) {

 

            CYG_INSTRUMENT_SCHED(RESCHEDULE,0,0);

           

            // Get the next thread to run from scheduler

            Cyg_Thread *next = scheduler.schedule();

 

            if( current != next )

            {

 

                CYG_INSTRUMENT_THREAD(SWITCH,current,next);

 

                // Count this thread switch

                thread_switches[CYG_KERNEL_CPU_THIS()]++;

>>上下文切换,在contexts.S里

                // Switch contexts

                HAL_THREAD_SWITCH_CONTEXT( &current->stack_ptr,

                                           &next->stack_ptr );

 

                // Worry here about possible compiler

                // optimizations across the above call that may try to

                // propogate common subexpresions.  We would end up

                // with the expression from one thread in its

                // successor. This is only a worry if we do not save

                // and restore the complete register set. We need a

                // way of marking functions that return into a

                // different context. A temporary fix would be to

                // disable CSE (-fdisable-cse) in the compiler.

               

                // We return here only when the current thread is

                // rescheduled.  There is a bit of housekeeping to do

                // here before we are allowed to go on our way.

>>一般就不会跑到这里了,cpu pc指针已经切换到别的任务上去了,只有等这个任务再次

>>被reschedule时,才会从这里开始执行

                current_thread[CYG_KERNEL_CPU_THIS()] = current;   // restore current thread pointer

            }

 

#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE

            // Reset the timeslice counter so that this thread gets a full

            // quantum.

            reset_timeslice_count();

#endif

 

            clear_need_reschedule();    // finished rescheduling

        }

 

        return;

 

    } while( 1 );

}

 

至此,整个框架已经出来了,对于schedule,thread,semphone,mutex,flag,mailbox等等其他概念,在ecos 发布的文档上

有比较详细的介绍(ecos reference manual),我就不再赘述了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值