分析的内核版本截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本的内核开发进度,若源码注释出现”???”字样,则是未深究理解部分。
Raw-OS官方网站:http://www.raw-os.org/
Raw-OS托管地址:https://github.com/jorya/raw-os/
这篇开始会连续几篇讲一讲Raw-OS的状态机编程那点破事,实际上来说,在实践上我并没有用过状态机编程这种思想,可能使用过的某些库是状态机实现的我并不知道,但是在我写过的应用层代码至少没有涉及过状态机编程,但是确实这个也是非常非常好的思想,感觉理解起来很简单,状态机编程的精髓是如何根据需要设计合理的状态机,而并不是状态机执行的过程,当然了~Raw-OS中的状态机模块就相当于QP-NANO的改写版本,童鞋们可以去了解一下QP事件驱动框架,这也是水很深的东西。
今天就先再回顾Raw-OS中IDLE任务这个东东
在最开始我们讲Raw-OS初始化的代码的时候讲过,Raw-OS内核在初始化过程中,会建立一个系统最低优先级(255)的任务,这个任务称为IDLE任务,也就是所谓的“空闲任务”,IDLE任务是在系统没有有用任务执行的时候才执行,那么在Raw-OS中,当系统没什么事可做的时候,执行IDLE任务,而IDLE任务的具体内容,Raw-OS实现了两种操作:
第一,在开发和调试用户业务逻辑代码的时候,使用实现1,即监控各个任务的任务堆栈使用情况,在开发阶段,监控任务堆栈的做法使得任务运行过程可以实时监控,各个任务所需的系统资源可以达到收敛的情况
IDLE任务监控各个用户任务代码:
/*
* 当开启RAW_SYSTEM_CHECK宏时,idle任务其实做的事情很简单
* 就是不断测试系统各个任务栈空间的剩余情况,在Raw-OS中,开启RAW_SYSTEM_CHECK宏后,
* idle任务就当检测到任何任务的剩余栈空间少于12%时,系统就会down掉,打印哪个任务出现这种情况
* 是为了在用户应用层开发的时候避免系统产生不必要的无故down机的检测手段
*/
#if (RAW_SYSTEM_CHECK > 0)
RAW_VOID raw_idle_task(void *p_arg)
{
LIST *iter;
RAW_TASK_OBJ *task_ptr;
PORT_STACK *task_stack;
RAW_U32 free_stack;
RAW_SR_ALLOC();
p_arg = p_arg; /* Make compiler happy ^_^ */
/* 现在可以回头去看看task creat函数关于加入到系统debug链表的实现 */
iter = system_debug.task_head.next;
while (1) {
free_stack = 0u;
/*
* 任务通过任务TCB的stack_check_list元素连接成系统debug链表
* 这里通过存在debug链表的stack_check_list,逆计算出任务TCB地址
*/
task_ptr = list_entry(iter,RAW_TASK_OBJ, stack_check_list);
/*
* 计算任务栈剩余空间时要注意CPU的栈空间生长的方向,低地址->高地址还是高地址->低地址
*/
#if (RAW_CPU_STACK_DOWN > 0)
task_stack = task_ptr->task_stack_base;
/* 如果堆栈是向下生成(高地址->低地址),那么栈顶在低地址,统计时往上计数 */
while (*task_stack++ == 0u) {
free_stack++;
/* 逻辑运算右移1位相当于/2,右移3位相当于/8,那么结果就是1/8*100% = 12% */
if (free_stack > (task_ptr->stack_size >> 3)) {
break;
}
}
#else
task_stack = (PORT_STACK *)(task_ptr->task_stack_base) + task_ptr->stack_size - 1;
/* 如果堆栈是向上生成(低地址->高地址),那么栈顶在低地址,统计时往下计数 */
while (*task_stack-- == 0) {
free_stack++;
/* 逻辑运算右移1位相当于/2,右移3位相当于/8,那么结果就是1/8*100% = 12% */
if (free_stack > (task_ptr->stack_size >> 3)) {
break;
}
}
#endif
TRACE_TASK_STACK_SPACE(task_ptr);
/* 统计idle任务运行次数 */
raw_idle_count++;
RAW_CPU_DISABLE();
if (task_ptr->task_state != RAW_DELETED) {
/* 这里就是判断任务栈空间的剩余大小,小于任务总堆栈空间的12%时,down掉打印信息 */
if (free_stack < (task_ptr->stack_size >> 3)) {
RAW_ASSERT(0);
}
/* 更新到系统debug的堆栈检查链表中的下一个任务,知道完整历遍一次stack_debug链表 */
iter = iter->next;
if (iter == (&(system_debug.task_head))) {
iter = system_debug.task_head.next;
}
}
/* 当在idle堆栈检查前任务已被删除,那么就马上跳过,再检索下下个堆栈检查链表任务 */
else {
iter = system_debug.after_delete_list;
}
RAW_CPU_ENABLE();
}
}
第二,当用户任务开发完成时,通常会使用第二个实现,就是使用协程,但是这个协程是什么呢,这里仅仅需要知道,IDLE使用协程,其实就是调用一个钩子函数,这个钩子函数命名为“协程”而已,完全可以当做,就是IDLE任务的执行时,调用一个用户自定义的钩子函数,这个钩子函数称为“协程的钩子”而已,完事
#else
/*
* 未开启RAW_SYSTEM_CHECK宏时,idle任务其实做的事情很简单
* 仅仅是全局统计运行idle任务次数的raw_idle_count变量自加,可以检索系统运行多少次idle任务
* 然后调用所谓的“协程”,“协程”其实就是一个运行在idle任务的钩子函数
*
* 不过“协程”这个东西可以利用一些思想和编程技巧来实现比较有趣的东西
* 在Raw-OS中就存在一个叫做“空闲事件编程”的东东,很有意思
*/
RAW_VOID raw_idle_task (void *p_arg)
{
RAW_SR_ALLOC();
p_arg = p_arg; /* Make compiler happy ^_^ */
while (1) {
USER_CPU_INT_DISABLE();
/* 统计idle任务运行次数 */
raw_idle_count++;
USER_CPU_INT_ENABLE();
/* idle任务中的协程钩子函数 */
raw_idle_coroutine_hook();
}
}
#endif