- union
- {
- uint64 total;
- struct
- {
- uint32 current;
- uint32 overflow;
- }part;
- }clock;
再定义两个定时链表timer[0]和timer[1],用于接收添加的定时消息块。且以计时周期溢出次数的0位值来指示哪个链表是当前延时链表,也就是在每次计时溢出后都会切换一次当前延时链表。
当添加一个延时消息时,以time+current(即tick)做为参考,在当前定时链表中按照从小到大排列,不会修改已有消息块的计时值,每次心跳中断时只比较current和表头tick值,如果tick<=current则认为计时时间到,进行相应处理后删除首节点,再以下一个节点为首进行相同处理。这样通过比较系统时间轴上前后位置来判定计时时间是否到达就避免了减减计数方式带来的定时块间的关联耦合。
这里有一个问题就是time和current都是无符号32位数据,出现加值溢出怎么办?
办法就是如果tick< current即出现加值溢出,则将该消息块以同样的方式添加到非当前定时链表中。在定时链表切换后自然就会得到准确处理。
这样在系统心跳中断中只做一次数值比较,时间复杂度为O(1),而在添加延时时只需要一次队列比较和插入操作。而且系统心跳计时clock的加入为系统还带来了跟多的功能和好处(好处以后在讲)。
怎么样,是不是非常高效呢?
下面是系统心跳中断延时处理函数源码
- void msg_irq(void)
- {
- msg_st *msg;
- link_st *link;
- link_st *node;
- scb.mcb.clock.total++;/**/
- link =&scb.mcb.timers[scb.mcb.clock.part.overflow & 0x01];/**/
- while(!link_isempty(link))/**/
- {
- node = link->next;/**/
- msg =(msg_st *)node;/**/
- if(msg->tick <= scb.mcb.clock.part.current)/**/
- {
- link_remove(node);/**/
- if(msg->opt & MSG_OPT_IRQ)/**/
- {
- msg->state=MSG_STATE_RUNING;/**/
- (msg->msgf)(msg->data,msg->ptr);/**/
- if(msg->opt & MSG_OPT_PERIODIC)/**/
- {
- msg_enqueue_delay(msg);/**/
- }
- else
- {
- link_insert_before(&scb.mcb.free,node);/**/
- msg->state=MSG_STATE_FREE;/**/
- }
- }
- else
- {
- msg_enqueue_thread(msg);/**/
- }
- }
- else
- {
- break;/**/
- }
- }
- }