Raw-OS源码分析之任务休眠

来源:互联网 发布:醉清风天猫和淘宝区别 编辑:程序博客网 时间:2024/06/06 23:51

分析的内核版本截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本的内核开发进度,若源码注释出现”???”字样,则是未深究理解部分。

        Raw-OS官方网站:http://www.raw-os.org/

        Raw-OS托管地址:https://github.com/jorya/raw-os/


1.Raw-OS任务休眠

        休眠操作,在系统中是把当前运行的任务,注意是当前运行的任务从就绪队列中移除或者从就绪队列中移动到同优先级就绪队列的末尾,对应在Raw-OS的user level API的raw_sleep(),这个函数的流程是这样的




        按照步骤1,2,3,4分析即可

        1.调用raw_sleep(xxx)后,会根据传入的休眠时间大小作模8处理,分散插入到tick的哈希表中,然后根据与超时时间点差值的大小,按从小到大的方式插入到tick[x]的链表中,例如,raw_sleep(50),那么模8的结果是2,然后就会插入到tick_list[2]的tick链表,再例如有一个raw_sleep(58)的任务,那么模8的结果还是2,同样会插入到tick_list[2]的tick链表中,但是由于58>50,插入排序的地方会比排在raw_sleep(50)后面

        2.然后休眠的任务会根据传入休眠时间是否为0选择操作,如过xxx>0,那么执行2,将任务从就绪链表中移除;如果xxx==0,那么执行3,移动到同优先级的链表的末尾

        3.最后执行系统调度,运行下一个就绪队列中最高优先级的任务

        结合一下源码注释更好理解:

#if (CONFIG_RAW_TASK_SLEEP > 0)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;}#endifRAW_CRITICAL_ENTER();/* 如果传入睡眠时间参数>0 */if (dly) {/* 这个宏检查当前系统是否上锁禁止调度,若已经上锁,那么任务就不允许休眠,立即返回 */SYSTEM_LOCK_PROCESS();/* 如果系统没有上锁,就改变当前运行任务状态->睡眠 */raw_task_active->task_state = RAW_DLY;/* 将当前任务按照超时时间大小插入到tick list中 */tick_list_insert(raw_task_active, dly);/* 将当前运行任务从就绪队列中移除 */remove_ready_list(&raw_ready_queue, raw_task_active);}/* 如果传入睡眠时间参数=0,把当前运行任务转移到就绪队列末尾 */else {/* 也就是说,raw_sleep(0)会引起同优先级任务立即切换 */ move_to_ready_list_end(&raw_ready_queue, raw_task_active);}RAW_CRITICAL_EXIT();/* 当前运行任务睡眠后,进行系统调度,这里发生任务切换 */raw_sched();if (dly) {/* 读取切换后新任务阻塞标志,根据这个任务之前如果是发生slepp的情况置位各种情况 */error_status = block_state_post_process(raw_task_active, 0);}/* 当传入超时参数=0,返回RAW_SUCCESS */else {error_status = RAW_SUCCESS;}return error_status;}


2.Raw-OS超时计算

        那么,在user调用raw_sleep()后,那么如何得知休眠的任务已经超时,要重新唤醒继续执行???

        那么就要看之前分析过的raw_time_tick()函数了,这个函数是在时钟中断的ISR里面调用的,之前分析过这个函数的流程:



        这里有关tick list计算的过程包含在raw_time_tick()函数中,具体看红色框图,那么这里Raw-OS对更新tick list的处理设计了两种模式,一种是在处理中直接调用内核tick_list_update()函数更新,一种是将tick_list_update()函数封装成tick任务,由raw_time_tick()函数释放信号量通知tick任务执行tick_list_update()函数,但是最终无论如何都是执行tick_list_update()函数更新任务超时的时间计算,所以直接分析tick_list_update()函数就可以了~


        具体看看代码是如何实现超时的,这里仅给出就绪任务简单休眠的代码注释,还不涉及其他类型的超时注释,例如任务挂起超时态等等的情况


void tick_list_update(void){LIST     *tick_head_ptr;RAW_TASK_OBJ            *p_tcb;LIST                            *iter;LIST                            *iter_temp;RAW_U16   spoke;RAW_SR_ALLOC();RAW_CRITICAL_ENTER();/* 这里是系统时间计时器++,之前讲的raw_time_tick或者独立的tick task最后都会调用tick_list_update */raw_tick_count++;/* * 同理tick_list_insert()函数,同样对tick list的大小进行求余处理,这里为什么??? * 只有当求余得到的tick list项内的任务才有可能发生tick list里面的任务超时到达的情况 * 例如,插入tick list时任务设置超时时间为50,假如系统tick list的大小为8,那么50%8=2, * 如果此时系统的计数器为12345,那么12345%8=1,那么在tick list[2]项中的任务是不可能发生超时的 * 所以之前说的raw_sleep()会分散到tick list中是为了加快搜索超时任务的速度 */spoke    = (RAW_U16)(raw_tick_count &  (TICK_HEAD_ARRAY - 1) );tick_head_ptr  = &tick_head[spoke];iter    = tick_head_ptr->next;while (RAW_TRUE) {/* 当选择的tick list[x]中存在等到超时的任务时,才可能进行任务唤醒操作 */if (iter != tick_head_ptr) {/* 计算出任务控制块的地址 */iter_temp =  iter->next;p_tcb =  list_entry(iter, RAW_TASK_OBJ, tick_list);/* 因为之前已经对任务睡眠时进行了排序操作,这里对比系统时间与超时时间点,相等时说明任务超时 */if (raw_tick_count == p_tcb->tick_match) {/* 判断任务状态,按照之前任务等待超时的情况处理,睡眠?挂起?等待信号量超时?等等 */switch (p_tcb->task_state) {/* 之前任务进行的是睡眠 */case RAW_DLY:/* 更改阻塞状态和任务状态 */p_tcb->block_status = RAW_B_OK;p_tcb->task_state = RAW_RDY;/* 从tick list中对应项移除 */tick_list_remove(p_tcb);/* 重新加入到就绪队列中等待系统调度 */add_ready_list(&raw_ready_queue, p_tcb);break;case RAW_PEND_TIMEOUT:......default:RAW_ASSERT(0);}iter  = iter_temp;}/* * if current task time out absolute time is not equal current system time, * just break because timer list is sorted */else {break;}}/*finish all the time list search */else {break;}}RAW_CRITICAL_EXIT();}



0 0