平台:VS2010 版本:1.04

   在讲解任务管理之前先看RAW-OS的就绪队列结构:

typedef struct RAW_RUN_QUEUE {
    RAW_U8                    highest_priority;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    LIST                      task_ready_list[CONFIG_RAW_PRIO_MAX];
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    RAW_U32                   task_bit_map[NUM_WORDS];
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
} RAW_RUN_QUEUE;

   先看看RAW_RUN_QUEUE这个结构体:highest_priority指当前就绪任务的最高优先级(RAW-OS会执行优先级为highest_priority的任务);task_ready_list[CONFIG_RAW_PRIO_MAX]是就绪任务的链表,CONFIG_RAW_PRIO_MAX代表可以有多少个优先级,每个优先级都有自己的就绪任务链表;若task_bit_map(n)为1代表有优先级为n的就绪任务(n/32为task_bit_map数组的index)。这样任务调度时,RAW-OS就可以根据RAW_RUN_QUEUE来进行任务切换。


   任务的管理重点就是任务的调度,那什么时候会产生任务的调度呢。

   一:RAW-OS的任务状态改变(来自RAW-OS作者的任务管理文档):

wKioL1Mq1pvA-QI1AAGOjSfcK4s786.jpg

   由上图我们看到RAW-OS有这么多状态,但是我们根据状态名不难发现改变任务状态的事件:sleep(DLY)、阻塞(PEND或者PEND_TIMEOUT)、暂停(SUPEND)和resume(只要状态中有SUPEND,resume就可以让任务去掉SUPEND状态)。那我们就分析下各个事件操作

   1.1 sleep

RAW_U16 raw_sleep(RAW_TICK_TYPE dly)
{
    RAW_U16 error_status;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    RAW_SR_ALLOC();
    #if (RAW_TASK_FUNCTION_CHECK > 0)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    if (raw_int_nesting) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        return RAW_NOT_CALLED_BY_ISR;
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    #endif    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
    RAW_CRITICAL_ENTER();
    if (dly) {
        /*system is locked so task can not sleep just return immediately*/
        SYSTEM_LOCK_PROCESS();
        raw_task_active->task_state = RAW_DLY;
        tick_list_insert(raw_task_active, dly);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        remove_ready_list(&raw_ready_queue, raw_task_active);
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    else {
        /*make current task to the end of ready list*/
         move_to_ready_list_end(&raw_ready_queue, raw_task_active);
    }
    RAW_CRITICAL_EXIT();
    raw_sched(); 
    if (dly) {
        /*task is timeout after sleep*/
        error_status = block_state_post_process(raw_task_active, 0);
    }
    else {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        error_status = RAW_SUCCESS;
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    return error_status;
}

   sleep函数参数dly指task的sleep时间,单位是1个时间节拍(以下若涉及到时间都是以1个时间节拍为单位)。sleep的具体操作如下:若dly>0,将task的state改为DLY并插入到tick_list链表中(参考时间管理),接着在就绪队列中删除当前task;dly=0,将task移到就绪队列的最后面(此时task的state没改变还是RDY)。当过去dly后(tick_list_updat函数),task的state就变成RDY了并重新加入到就绪队列中。

   1.2 阻塞--信号量阻塞

RAW_U16 raw_pend_object(RAW_COMMON_BLOCK_OBJECT  *block_common_obj, RAW_TASK_OBJ *task_ptr, RAW_TICK_TYPE timeout)
{
    /*timeout 0 should not happen here, it has been processed before*/
    if (timeout == 0u) {
        RAW_ASSERT(0);
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    /*task need to remember which object is blocked on*/
    task_ptr->block_obj = block_common_obj;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    if (timeout == RAW_WAIT_FOREVER) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        task_ptr->task_state = RAW_PEND;
    }
    /*task is blocked with timeout*/
    else {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        /*add to time sorted tick list */ 
        tick_list_insert(task_ptr,timeout);
        task_ptr->task_state = RAW_PEND_TIMEOUT;
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    /*Remove from the ready list*/
    remove_ready_list(&raw_ready_queue, task_ptr);
    //将task_list挂到等待信号量的链表下
    if (block_common_obj->block_way == RAW_BLOCKED_WAY_FIFO) {
        /*add to the end of blocked objet list*/
        list_insert(&block_common_obj->block_list, &task_ptr->task_list);
    }
    else {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
        /*add to the priority sorted block list*/
        add_to_priority_list(&block_common_obj->block_list, task_ptr);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    return RAW_SUCCESS;
}

信号量阻塞事件将task从就绪队列中删除并将之添加到block_list(信号量)中。根据阻塞函数的timeout函数,分为以下两种情况:若timeout=RAW_WAIT_FOREVER,则表示task会一直等下去即state=RAW_PEND直到获取到信号量state才会变成RDY;相反state=RAW_PEND_TIMEOUT,并根据timeout将task添加到tick_list链表(等待timeout(tick_list_updat)后,task自动变成RDY状态并添加到就绪队列),但是如果在timeout之前获取到信号量,此时state也会变为RDY。

   

   1.3    SUPEND

RAW_U16 task_suspend(RAW_TASK_OBJ *task_ptr)
{
    RAW_SR_ALLOC();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    RAW_CRITICAL_ENTER();
    if (task_ptr == raw_task_active) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
        SYSTEM_LOCK_PROCESS();
    }
    switch (task_ptr->task_state) {
        case RAW_RDY:
            task_ptr->suspend_count = 1;
            task_ptr->task_state  =  RAW_SUSPENDED;
            remove_ready_list(&raw_ready_queue, task_ptr);
            break;
        case RAW_DLY:
            task_ptr->suspend_count = 1;
            task_ptr->task_state  = RAW_DLY_SUSPENDED;
            break;
        case RAW_PEND:
            task_ptr->suspend_count = 1;
            task_ptr->task_state  = RAW_PEND_SUSPENDED;
            break;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
        case RAW_PEND_TIMEOUT:
            task_ptr->suspend_count = 1;
            task_ptr->task_state  = RAW_PEND_TIMEOUT_SUSPENDED;
            break;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
        case RAW_SUSPENDED:
        case RAW_DLY_SUSPENDED:
        case RAW_PEND_SUSPENDED:
        case RAW_PEND_TIMEOUT_SUSPENDED:
            task_ptr->suspend_count++;
            if (task_ptr->suspend_count >= 250u) {
                RAW_CRITICAL_EXIT();
                return RAW_SUSPENDED_COUNT_OVERFLOWED;
            }
            break;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
        default:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
            RAW_CRITICAL_EXIT();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
            return RAW_STATE_UNKNOWN;
    }
    RAW_CRITICAL_EXIT();
    TRACE_TASK_SUSPEND(raw_task_active, task_ptr);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    #if (CONFIG_RAW_SYSTEM_PREEMPTABLE > 0)
    raw_sched();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
    return RAW_SUCCESS;
}

supend将state追加SUPEND状态,若原本state为RDY,则需要将task从就绪队列中删除并将state修改为supend。当之前的state符合时,state为SUPEND,例当state为pend_supend时获取到信号量,state就变为supend。

   

   1.4 resume

RAW_U16 task_resume(RAW_TASK_OBJ *task_ptr)
{
    RAW_SR_ALLOC();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    RAW_CRITICAL_ENTER();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    switch (task_ptr->task_state) {
        case RAW_RDY:
        case RAW_DLY:
        case RAW_PEND:
        case RAW_PEND_TIMEOUT:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            RAW_CRITICAL_EXIT();
            return HAS_NOT_SUSPENDED;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
        case RAW_SUSPENDED:
            task_ptr->suspend_count--;
            if (task_ptr->suspend_count == 0) {
                /*Make task ready*/
                task_ptr->task_state = RAW_RDY;
                add_ready_list(&raw_ready_queue, task_ptr);//如果同当前任务的优先级相同则插到队列的最后,否则插到队列的最前面
            }
            break;
        case RAW_DLY_SUSPENDED:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            task_ptr->suspend_count--;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            if (task_ptr->suspend_count == 0) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                task_ptr->task_state = RAW_DLY;
            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            break;
        case RAW_PEND_SUSPENDED:
            task_ptr->suspend_count--;
            if (task_ptr->suspend_count == 0) {
                task_ptr->task_state = RAW_PEND;
            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            break;
        case RAW_PEND_TIMEOUT_SUSPENDED:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            task_ptr->suspend_count--;
            if (task_ptr->suspend_count == 0) {
                task_ptr->task_state = RAW_PEND_TIMEOUT;
            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            break;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
        default:
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            RAW_CRITICAL_EXIT();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
            return RAW_STATE_UNKNOWN;
    }
    RAW_CRITICAL_EXIT();
    TRACE_TASK_RESUME(raw_task_active, task_ptr);
    do_possible_sche(); 
    return RAW_SUCCESS;
}

   看代码可知,resume能将有supend状态的task去掉supen状态。若task只是supend状态,需要将state改为RDY并将其添加到就绪队列(若state=RDY,则RAW-OS就会task添加到就绪队列中)。


   二:任务状态的改变会引起schde,下面这种情况也会sched:

void calculate_time_slice(RAW_U8 task_prio)
{
    RAW_TASK_OBJ   *task_ptr;
    LIST *head;
    RAW_SR_ALLOC();
    head = &raw_ready_queue.task_ready_list[task_prio];
                                                                                                                                                                                                                                                                                                                                                       
    RAW_CRITICAL_ENTER();
                                                                                                                                                                                                                                                                                                                                                      
    /*if ready list is empty then just return because nothing is to be caculated*/                     
    if (is_list_empty(head)) {
        RAW_CRITICAL_EXIT();  
        return;
    }
    /*Always look at the first task on the ready list*/ /*because active task is the first task on the ready list*/
    task_ptr = list_entry(head->next, RAW_TASK_OBJ, task_list);
    /*SCHED_FIFO does not has timeslice, just return*/
    if (task_ptr->sched_way == SCHED_FIFO) {
                                                                                                                                                                                                                                                                                                                                                          
        RAW_CRITICAL_EXIT();    /*FIFO 调度模式会一直执行到其他任务抢占或者是当前任务阻塞,跟task's timeslice无关*/
        return;
    }
    /*there is only one task on this ready list, so do not need to caculate time slice*/
    /*idle task must satisfy this condition*/
    if (head->next->next == head)  {
                                                                                                                                                                                                                                                                                                                                                          
        RAW_CRITICAL_EXIT();        /*若当前任务列表只有一个任务那自然不需要计算timeslice*/
        return;
                                                                                                                                                                                                                                                                                                                                                          
    }
    if (task_ptr->time_slice) {
        task_ptr->time_slice--;
    }
    /*if current active task has time_slice, just return*/
    if (task_ptr->time_slice) {             
        RAW_CRITICAL_EXIT();
        return;
    }
    /*Move current active task to the end of ready list for the same priority*/
    move_to_ready_list_end(&raw_ready_queue, task_ptr);
    /*restore the task time slice*/
    task_ptr->time_slice = task_ptr->time_total;
                                                                                                                                                                                                                                                                                                                                                      
    RAW_CRITICAL_EXIT();
}

   RAW-OS会为每个任务分配time_slice(FIFO模式例外),当任务执行time_slice后,RAW-OS就会将task移到就绪队列的末端(毫无疑问此时会sched)。

 


    Sched:

void raw_sched(void)
{
    RAW_SR_ALLOC();
    /*if it is in interrupt or system is locked, just return*/
    if (raw_int_nesting || raw_sched_lock) {            
        return;                                           
    }
    RAW_CPU_DISABLE();
                                                                                                                                                        
    get_ready_task(&raw_ready_queue);
    /*if highest task is currently task, then no need to do switch and just return*/
    if (high_ready_obj == raw_task_active) {               
        RAW_CPU_ENABLE();                                   
        return;
    }
    TRACE_TASK_SWITCH(raw_task_active, high_ready_obj);
    CONTEXT_SWITCH(); //设置任务切换标志并增加timer_or_task_switch_event信号量使之响应WaitForMultipleObjects函数后停止当前任务开启最高优先级的任务
    RAW_CPU_ENABLE();
}

   sched函数很简单,它要做的就是执行当前优先级最高的task。那RAW-OS怎么得到最高优先级task呢,其实看RAW_RUN_QUEUE结构体就一目了然。如果当前task是最高优先级的任务,则不需要进行任务的切换(Note1);否则就要进行任务的切换了,暂停当前任务(此时state还是为RDY)执行执行最高优先级的任务(关于切换的具体机制,可以查看WaitForMultipleObjects函数)。


Note1:任务状态的改变不一定就会进行任务的调度(只有从RDY到别状态才一定会任务调度),例如在task1的状态从PEND-->RDY时,如果task1的优先级不是最高的就不进行任务切换,所以RAW-OS在这里调用do_possible_sche()(#define do_possible_sche()       raw_sched())。我想RAW-OS的意思已经表达的很清楚了。