RAW-OS之任务0执行时钟节拍event的过程

一、步骤简介


1.创建任务0 , 任务0处理函数为task_0_process(void *pa);

 

2.设置时钟节拍中断时发给任务0的event的处理函数task_0_event_handler.handle_event= task_0_tick_handler(RAW_U8 ev, RAW_U8 *data);

 

3.把任务0的就绪标志置'1' , task_0_is_ready = 1 .

 

4.把任务0设置为当前最高优先级任务 ,并作为当前运行任务 .

 

5.启动os , 第一次进入时钟节拍中断, 调用task_0_tick_post()发送时钟节拍事件task_0_event_handler (在步骤2,对其赋值) .

 

6 .调用raw_finish_int()切换到任务0去运行;

 

7.task_0_process(void*pa)会获取时钟节拍事件并执行该事件的处理函数task_0_tick_handler(RAW_U8 ev, RAW_U8*data)


二、详细过程及源码分析

1.在raw_os_init()(定义在raw_sched.c里)函数里通过调用raw_task_0_init()(定义在raw_task_0.c里)对任务0进行初始化 .
源码及注释如下:
void raw_task_0_init()
{

    /*创建任务0 , 该任务0的处理函数指针为timer_0_process(后面会提起) ,  并自动加入到就绪链表上*/
    raw_task_create(&raw_task_0_obj, (RAW_U8  *)"timer_object",  0,
    0,  0, task_0_stack, TASK_0_STACK_SIZE, task_0_process, 1);
           /*设置任务0的event处理函数*/
    task_0_event_handler.handle_event = task_0_tick_handler;
    /*设置任务0就绪标志*/
    task_0_is_ready = 1;
    
    #if (CONFIG_RAW_ZERO_INTERRUPT > 0)
    int_msg_init();
    #endif
}

2.之后调用raw_os_start(),该函数启动rawos并开始执行第一个最高优先级的任务 . 也就是上面创建的任务0 ,

RAW_U16 raw_os_start()
{
    if (raw_os_active == RAW_OS_STOPPED) {
               /*获取最高优先级的任务 , 任务0控制块会被存在high_ready_obj*/
        get_ready_task(&raw_ready_queue);
        /*把最高就绪任务(任务0)作为当前运行任务*/
        raw_task_active = high_ready_obj;
        raw_os_active = RAW_OS_RUNNING;
        /*
        *这个函数的里面模拟中断处理simulated_interrupt_process()
        *会调用到task_0_tick_post()(步骤3)来发送时钟节拍event给任务0,然后调用
        *raw_finish_int()(步骤4)来作退出中断处理,主要完成了获取最高优先级任务,
        *执行一次中断切换raw_int_switch()给最高优先级的任务 , 然后跳
*任务0的处理函数task_0_process()(步骤5)去执行
        **/
        raw_start_first_task();
    }
    else {
        return RAW_OS_RUNNING;
    }
    #if (CONFIG_RAW_ASSERT > 0)
    RAW_ASSERT(0);
    #endif
    return RAW_SYSTEM_ERROR;
}

3.一旦os开始了, 则在每一次的时钟节拍中断里面需要调用task_0_tick_post()来传递时钟节拍中断事件给任务0

该函数定义及注释如下:

/*
*发送时钟节拍中断的event给任务0
*触发任务0执行时钟节拍中断的后续处理
**/
void task_0_tick_post()
{
    /*发送event给任务0 , */
    raw_task_0_post(&task_0_event_handler, raw_task_active->priority, 0);
}
/*
*该函数用于给任务0发送event
**/
void raw_task_0_post(EVENT_HANLDER *p, RAW_U8 ev, RAW_U8 *data)
{
    RAW_U32 snum;
    RAW_SR_ALLOC();
    /*if message is max, probally interrupt is too fast, please check your interrupt*/
    if(nevents_points == MAX_TASK_EVENT) {
        RAW_ASSERT(0);
    }
    /*fastest way to make task 0 ready*/
    RAW_CPU_DISABLE();
    /*fevent_point指向最先进入队列的任务, 计算出任务0的event队列的第一个空闲位置 , 用于插入event   .  (FIFO)*/
    snum = (fevent_point + nevents_points) & (MAX_TASK_EVENT - 1); //
    /*任务0 event数加一*/
    ++nevents_points;  
    /*设置任务0就绪标志*/
    if (task_0_is_ready == 0) {  
        task_0_is_ready = 1;
    }
    RAW_CPU_ENABLE();
    /*把该event插入队列里*/  
    task_0_events_queue[snum].ev = ev;
    task_0_events_queue[snum].data = data;
    task_0_events_queue[snum].p = p;
    /*更新调试信息*/  
    if (nevents_points > peak_events) {
        peak_events = nevents_points;
    }
}

4.调用raw_finish_int()来处理退出中断的必要工作并退出中断 .

函数定义及注释如下:
RAW_VOID raw_finish_int()
{
    RAW_SR_ALLOC();
    RAW_CPU_DISABLE();
    /*如果已经不在中断里面的 , 则直接返回*/
    if (raw_int_nesting == 0) {
        RAW_CPU_ENABLE();                                  
        return;
    }
    /*把中断嵌套数减一*/
    raw_int_nesting--;
    /*如果减一之后还处在中断里面 , 也直接返回,因为中断里面不允许调度 */
    if (raw_int_nesting) {              
        RAW_CPU_ENABLE();                                  
        return;
    }
    /*如果调度器被上锁了,也不能切换给高优先级的任务 , 直到调度锁被释放*/
    if (raw_sched_lock) {
        RAW_CPU_ENABLE();
        /*if interrupt happen here, it may cause raw_int_nesting equal 0*/
        return;
    }
    #if (CONFIG_RAW_TASK_0 > 0)
    /*如果任务0处于就绪态 , 则需要把任务0交给high_ready_obj*/
    if (task_0_is_ready) {
        high_ready_obj = &raw_task_0_obj;
    }
    /*否则,需要在就绪队列里获取最高优先级的任务*/
    else {
        /*get the highest task*/
        get_ready_task(&raw_ready_queue);
    }
    #else
    /*get the highest task*/
    get_ready_task(&raw_ready_queue);
    #endif
    /*如果当前被中断的任务已经是最高优先级的任务了,就不需要执行下面的切换了,直接退出*/
    if (high_ready_obj == raw_task_active) {                 
        RAW_CPU_ENABLE();                                     
        return;
    }
    /*切换到最高优先级的任务(此时是任务0,所以会切换到task_0_process()(步骤5))去执行 , 这个函数涉及到CPU硬件的处理 , 需要被移植*/
    raw_int_switch();  
    RAW_CPU_ENABLE();  
}
 

5.task_0_process()(定义在raw_task_0.c里 , 任务0的处理函数) ,

该函数源码及注释如下:
static void task_0_process(void *pa)
{
    RAW_U8 ev;
    RAW_U8 *data;
    EVENT_HANLDER *receiver;
    RAW_U8 done;
    RAW_S32 i;
    RAW_SR_ALLOC();
    /*把任务0控制块从就绪链表里摘除*/
    list_delete(&raw_task_0_obj.task_list);   
    /*把就绪队列里task_bit_map对应于任务0的位清零*/
    data = (RAW_U8 *)raw_ready_queue.task_bit_map;   
    *data &= ~1;
    while (1) {
        done = 0;
        while (done == 0) {
            /*以下获取消息并更新*/
            RAW_CPU_DISABLE();
            if (nevents_points) {//不为0表示有event发生,遍历直到所有event处理完
            
                /* 任务0释放这些event */
                
                /*
                *fevent_point指明发生的event所存放在task_0_events_queue的位置,
                *取出这些event信息进行处理
                **/
                ev = task_0_events_queue[fevent_point].ev;
                data = task_0_events_queue[fevent_point].data;
                receiver = task_0_events_queue[fevent_point].p;  
                /*更新fevent_point , 对其加一指向下一个事件,如果达到数组尾部则跳到数组头部继续取*/
                fevent_point = (fevent_point + 1) & (MAX_TASK_EVENT - 1);
                /*更新nevents_points , 因为取出了一个event了,所以对其减一*/
                --nevents_points;   
                RAW_CPU_ENABLE();
                /*
                *执行该事件的关联函数 , handle_event由用户自定义 ,
                *此例为步骤3 post的task_0_event_handler->hendle_event,
                *在步骤1有对其赋值为task_0_tick_handler ,
                * 所以调用步骤6的函数
                **/
                receiver->handle_event(ev, data);
            }
             /*指明没有event需要处理了,执行以下代码*/
            else {
                /*关闭任务0就绪标志*/
                task_0_is_ready = 0;  
                RAW_CRITICAL_ENTER_CPU_ENABLE();
                /*获取下一个最高优先级与当前优先级与优先级1的偏移量*/
                i = bit_search_first_one(raw_ready_queue.task_bit_map, 1, CONFIG_RAW_PRIO_MAX - 1);
                /*更新就绪队列里维护的最高优先级*/
                if (i >= 0) {  
                    raw_ready_queue.highest_priority = 1 + i;
                }
                else {
                    #if (CONFIG_RAW_ASSERT > 0)
                    RAW_ASSERT(0);
                    #endif
                }
                /*这里退出临界区而不执行调度*/
                RAW_CRITICAL_EXIT_NO_SCHED();
                /*从任务0切换到其它普通任务去*/
                task_0_switch();  //从任务0切换到普通任务执行  ,切换之后任务0不再被调度 , 直到task_0_is_ready=1
                done = 1;
            }
        }
    }
}

6.调用task_0_tick_handler(RAW_U8 ev, RAW_U8 *data)用于处理时钟节拍中断的后续事情(中断下半部) .

函数定义及注释如下:

void task_0_tick_handler(RAW_U8 ev, RAW_U8 *data)
{
    data = data;
    #if (CONFIG_RAW_USER_HOOK > 0)
    raw_tick_hook();
    #endif
    /* 更新系统的时钟节拍计数 , 判断是否有任务阻塞超时或者睡眠超时,不会开启调度器*/
    tick_list_update();
    /*update task time slice if possible*/
    #if (CONFIG_SCHED_FIFO_RR > 0)
    /*更新指定优先级第一个任务的时间片 , 通常传入当前优先级 ,
    *如果时间片用完就要把该任务放到该链表的尾部并复位时间片
    *在每一次调用RAW_CRITICAL_EXIT()退出临界区都会判断任务0
    *是否就绪了,是话会调度到任务0执行*/
    caculate_time_slice(ev);
    #endif
    #if (CONFIG_RAW_TIMER > 0)
    /*通知软定时器管理任务更新软定时器*/    
    call_timer_task();
    #endif
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值