文章目录
1 时钟节拍列表
- 表项的数目由OS_CFG_TICK_WHEEL_SIZE设定,同时,该值需要根据处理器中可用RAM存储量和应用程序中的最大任务数来确定,一般该值设为最大任务数的1/4,且该值不能与时钟节拍的频率成倍数关系,最好用素数表示该值,这样可以使每个表项上等待的任务数目均匀分布。
- 表项成员.NbrEntriesMax表征该表项上等待任务的最大数目,通过调用OSStatReset()使其复位
- 表项成员.NbrEntries表征该表项上等待的任务数目
- 表项成员.FirstPtr为指针变量,指向在该表项上等待任务构成的双向链表(由个任务的OS_TCB组成)
- OSTickCtr是一个时钟节拍计数器,没当一个时钟节拍发生,该值+1
- 时钟节拍列表时一个环形表,该环形表也被称为时钟节拍轮,其中每一个表项表示轮上的一根“辐条”
2 任务插入表项过程
当应用程序中的某个任务调用OSTimeDly???()函数或使用非零的超时值条用OS???Pend()函数时,该任务将被插入到时钟节拍表中。
- 假定时钟节拍列表全空,OS_CFG_TICK_WHEEL_SIZE为12,且OSTickCtr当前值为10
- 任务调用OSTimeDly(1, OS_OPT_TIME_DLY, &err)
- 因为OSTickCtr的当前值为10,因此,该任务延迟到达时间为 MatchValue = OSTickCtr + Dly,该值被存入任务的控制块中的TickCtrMatch成员中,其中TickCtrPrev成员表示任务开始延时时OSTickCtr的值
- 该任务插入到时钟节拍表的表项数计算为:Index = MatchValue % OS_CFG_TICK_WHEEL_SIZE;并且该值存放在任务控制块中的TickSpokePtr成员中
- 由于该表为空,因此该任务被插入在第11项中,第11项.FirstPtr指向该任务的控制块,同时,在该表项上的等待任务数+1,由于该表项目前只有一个任务,因此该任务控制块中的TickNextPtr与TickPrevPtr成员指向NULL。
- OSTimeDly()函数还会做其他的工作,如将改任务从就绪表中删除,该任务不再符合运行的条件,应该被挂起并等待延时结束,之后调度器启动,执行下一个就绪任务
- 相同表项中的任务按照剩余等待时间由少到多按照升序进行链接
- 当一个时钟节拍到达时,时钟节拍任务执行,该任务首先递增OSTickCtr的值,之后判断应该处理哪个表项OSTickCtr%OS_CFG_TICK_WHEEL_SIZE
- 如果该表项的时钟节拍任务列表中有任务存在(即.FirstPtr非空),则时钟节拍任务会检查相应的OS_TCB中TickCtrMatch的值是否与当前OSTickCtr值相等,如果相同就将该任务从表中删除,如果该任务只在等待延时结束,则会被插入到就绪列表中。如果该任务在等待某个事件,则不仅要将该任务从时钟节拍表中删除,还要将该任务从任务等待表中删除。
- 如果 FirstPtr指向的OS_TCB中的TickCtrMatch值与OSTickCtr不同,则立刻结束,因为相同表项中剩余等待时间最少的位于链表前面。