Raw-OS源码分析之软件定时器

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

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

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

 

        看过内核中互斥量这些变态代码之后,来看看简单的代码找找自信吧,这节,软件定时器,还记得讲任务轮转的时候的ticks计数在内核实现的原理没,先回顾一下任务tick计数的一些细节,然后再看下面的文字。

        那么首先,在系统初始化的时候讲过,Raw-OS有一个任务优先级别是5的软件定时器任务,当没有任务的优先级高于5时,内核就会轮转到这个任务,执行这个任务的任务函数,在系统初始化阶段,软件定时器的任务初始化函数是raw_timer_init(),这个软件定时器任务的建立函数就不展开了,很容易懂,接下来我们来展开软件定时器任务的任务函数timer_task(),详细解说一下。

 

 

 

        看完上面这个图,你会发现软件定时器的原理非常像tick计数的实现,其实道理上也是一样的,无非是当timer调度,任务函数执行,更新计数,判断有没有定时器计数完,执行定时器注册的回调函数,判断定时器计数形式,重新加入到timer list或者自删除。软件定时器的核心就是timer任务的任务函数

 

void timer_task(void *pa)
{
	RAW_U16 							position;
	LIST 								*timer_head_ptr;
	LIST 								*iter;
	LIST 								*iter_temp;
	RAW_TIMER							*timer_ptr;

	/*reset the timer_sem count since it may not be 0 at this point, make it start here*/
	raw_semaphore_set(&timer_sem, 0);
	pa = pa;

	while (1) {
		/*
		 * 因为在call_timer_task()函数内释放系统软件定时器任务的信号量,这里获取此信号量
		 * 执行完timer时间更新后,系统定时器任务将会再次阻塞在此信号量上,等待下次call_timer_task()释放
		 */
		raw_semaphore_get(&timer_sem, RAW_WAIT_FOREVER);

		/* 禁止系统调度 */
		raw_disable_sche();

		/* 更新系统软件定时器全局计数器 */
		raw_timer_count++;
		/* 模x后计算出超时可能发生的timer_head[x]位置,这个和寻找tick_head[x]的原理一样,参考tick_list_update()函数注释 */
		position = (RAW_U16)(raw_timer_count & (TIMER_HEAD_NUMBERS - 1) );
		timer_head_ptr  = &timer_head[position];
		/* timer_head[x]中都是按从小到大的超时时间排序的,所以取出timer_head[x]的第一项即可 */
		iter = timer_head_ptr->next;

		while (RAW_TRUE) {
			/* 判断在timer_head[x]是否存在timer超时的等待项,如果不存在时,timer_head_ptr->next是指向timer_head[x]的,即是定时器链表的第一项 */
			if (iter != timer_head_ptr) {
				/* 取出timer_head[x]的第二项,因为第一项会超时删除信息,留作更新信息的目的 */
				iter_temp = iter->next;
				/* 计算出timer_head[x]第一项的任务控制块地址 */
				timer_ptr =  list_entry(iter, RAW_TIMER, timer_list);

				/* 比较系统timer全局计数器和任务超时时间点,相等时timer就超时 */
				if (raw_timer_count == timer_ptr->match) {

					/* 从系统软件定时器链表timer_head[x]中删除定时器信息 */
					timer_list_remove(timer_ptr);

					/* 如果创建timer控制块时指定了超时时间间隔,那么就会重新插入到模x之后的timer_head[%x]位置中 */
					if (timer_ptr->reschedule_ticks) {
						/* 重置定时器剩余超时时间间隔 */
						timer_ptr->remain = timer_ptr->reschedule_ticks;
						/* 重置定时器超时时间点 */
						timer_ptr->match  = raw_timer_count + timer_ptr->remain;
						/* 模x寻找timer_head[%x]位置 */
						position   = (RAW_U16)(timer_ptr->match & (TIMER_HEAD_NUMBERS - 1));
						timer_ptr->to_head = &timer_head[position];
						/* 按超时时间间隔大小插入到timer_head[%x]链表的适当位置 */
						timer_list_priority_insert(&timer_head[position], timer_ptr);
					}

					/* 如果没有指定超时时间,即timer为一次性计时性质,超时后设置为deactive状态 */
					else {
						timer_ptr->timer_state = TIMER_DEACTIVE;
					}

					/*Any way both condition need to call registered timer function*/
					/*the registered timer function should not touch any timer related API,otherwise you get deadlock*/

					/* 超时后timer马上执行注册的timer回调函数,传入参数为raw_timeout_param */
					if (timer_ptr->raw_timeout_function) {
						timer_ptr->raw_timeout_function(timer_ptr->raw_timeout_param);
					}
					/* 超时后,timer_head[x]的第1项会被删除,更新timer_head[x]的第2项为第1项 */
					iter  = iter_temp;
				}

				else {
					break;
				}
			}

			/*exit because timer is not exit*/
			else {
				break;
			}
		}
		/* 开启系统调度 */
		raw_enable_sche();
	}
}


        然后剩下的包括定时器创建、激活、删除、反激活、更改定时周期都是一些基本和辅助功能,这里不展开了,都是很简单的代码,或者可以向我要注释版的内核代码~

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值