分析的内核版本截止到2014-04-15,基于1.05正式版,blogs会及时跟进最新版本的内核开发进度,若源码注释出现”???”字样,则是未深究理解部分。
Raw-OS官方网站:http://www.raw-os.org/
Raw-OS托管地址:https://github.com/jorya/raw-os/
这节讨论一下Raw-OS中的任务挂起操作的实现,但是系统对于任务挂起操作的情况是很多的,就绪任务可以被挂起,休眠的任务可以被挂起,等待任务可以被挂起,已经被挂起的任务也可以再次被挂起,这里仅仅给出就绪任务被挂起的情况,先看挂起操作的流程:
就绪任务的挂起:找到任务所属的就绪链表的位置,然后执行list_remove()操作,这个操作在之前讨论过,那么通过list_enrty宏设置任务控制块中的任务指示标志位为suspended状态,从就绪队列删除这个任务信息即可,具体代码:
RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr) { #if (RAW_TASK_FUNCTION_CHECK > 0) /* 检查任务控制块是否为空,为空即任务不存在,无所谓挂不挂起 */ if (task_ptr == 0) { return RAW_NULL_OBJECT; } #endif /* 检查任务优先级,这里检查是否是IDEL任务优先级,即IDEL任务不能被挂起??? */ if (task_ptr->priority == IDLE_PRIORITY) { return RAW_SUSPEND_TASK_NOT_ALLOWED; } #if (CONFIG_RAW_TASK_0 > 0) /* 检查任务优先级,开启Task 0任务相关宏后,同样task 0不能被挂起??? */ if (task_ptr->priority == 0) { return RAW_SUSPEND_TASK_NOT_ALLOWED; } #endif #if (CONFIG_RAW_ZERO_INTERRUPT > 0) /* 开启0中断特性后,任务挂起消息通过task 0转发??? */ if (raw_int_nesting) { /* ??? */ return int_msg_post(RAW_TYPE_SUSPEND, task_ptr, 0, 0, 0, 0); } #endif /* 挂起任务操作 */ return task_suspend(task_ptr); } /* 挂起任务操作 */ RAW_U16 task_suspend(RAW_TASK_OBJ *task_ptr) { RAW_SR_ALLOC(); /* * 这个宏跟是否实现0中断特性有关,按照之前的配置,不实现0中断特性 * 因为没研究过,不好解释,后续分析再不上 * * 不实现0中断特性,这个宏就是简单禁止CPU中断,然后把状态字保存起来 */ RAW_CRITICAL_ENTER(); /* 如果挂起的是当前系统运行中的任务,必须先给系统解锁,开放系统调度??? */ if (task_ptr == raw_task_active) { SYSTEM_LOCK_PROCESS(); } /* 读取被挂起任务的任务状态 */ switch (task_ptr->task_state) { /* 任务为就绪态时 */ case RAW_RDY: /* 任务挂起次数=1 */ task_ptr->suspend_count = 1; /* 挂起后,设置任务状态为挂起态 */ task_ptr->task_state = RAW_SUSPENDED; /* 把就绪任务从就绪队列中删除 */ remove_ready_list(&raw_ready_queue, task_ptr); break; /* 任务为休眠状态 */ case RAW_DLY: task_ptr->suspend_count = 1; /* 挂起后,变为休眠挂起状态 */ task_ptr->task_state = RAW_DLY_SUSPENDED; break; /* 任务为阻塞状态 */ case RAW_PEND: task_ptr->suspend_count = 1; /* 挂起后,设置任务状态为阻塞挂起态 */ task_ptr->task_state = RAW_PEND_SUSPENDED; break; /* 任务为阻塞超时状态 */ case RAW_PEND_TIMEOUT: task_ptr->suspend_count = 1; /* 挂起后,设置任务状态为阻塞超时挂起态 */ task_ptr->task_state = RAW_PEND_TIMEOUT_SUSPENDED; break; /* 下面的是已经被挂起的状态,在Raw-OS中允许挂起的任务再一次被挂起 */ case RAW_SUSPENDED: case RAW_DLY_SUSPENDED: case RAW_PEND_SUSPENDED: case RAW_PEND_TIMEOUT_SUSPENDED: /* 再次被挂起的任务在挂起嵌套层变量++ */ task_ptr->suspend_count++; /* 可以看出允许任务重复挂起249次,谁那么无聊会挂起这么多次??? */ if (task_ptr->suspend_count >= 250u) { RAW_CRITICAL_EXIT(); return RAW_SUSPENDED_COUNT_OVERFLOWED; } break; default: RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } RAW_CRITICAL_EXIT(); /* 又是trace调试系统??? */ TRACE_TASK_SUSPEND(raw_task_active, task_ptr); /* 这里就是系统调度,任务挂起后会马上执行任务调度 */ raw_sched(); /* 函数没有检查中断嵌套的情况,那么在中断是可以执行任务挂起操作的 */ return RAW_SUCCESS; }
那么对于唤醒一个仅仅是简单挂起状态的任务,就是唤醒任务的逆操作,什么是简单挂起,开始的时候说明过,任务挂起的状态是可以叠加的,休眠的任务可以被挂起,等待任务可以被挂起,已经被挂起的任务也可以再次被挂起,这是我个人理解的非简单挂起,那么对于简单挂起的唤醒操作,流程是这样的:
唤醒操作,先设置任务TCB里面的任务状态标志为ready,然后通过TCB中的tasklist信息加入到就绪队列的适当位置,至于就绪队列的insert操作,在系统初始化阶段讨论过,可参考之前的blog,那么内核实现的代码是:
RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr) { #if (RAW_TASK_FUNCTION_CHECK > 0) /* 检查任务控制块是否为空,为空即任务不存在,无所谓唤不唤醒 */ if (task_ptr == 0) { return RAW_NULL_OBJECT; } #endif #if (CONFIG_RAW_ZERO_INTERRUPT > 0) /* 开启0中断特性后,系统处理中断或调度被上锁时,唤醒操作通过task 0 转发??? */ if (raw_int_nesting && raw_sched_lock) { return int_msg_post(RAW_TYPE_RESUME, task_ptr, 0, 0, 0, 0); } #endif /* 唤醒任务 */ return task_resume(task_ptr); } RAW_U16 task_resume(RAW_TASK_OBJ *task_ptr) { /* task 0不实现时,保存CPU状态字,禁止CPU中断 */ RAW_SR_ALLOC(); RAW_CRITICAL_ENTER(); /* 检查被唤醒任务状态 */ switch (task_ptr->task_state) { /* 就绪,睡眠,阻塞,阻塞超时状态不是挂起状态,所以无所谓唤不唤醒 */ case RAW_RDY: case RAW_DLY: case RAW_PEND: case RAW_PEND_TIMEOUT: /* 使能CPU中断后返回 */ RAW_CRITICAL_EXIT(); return HAS_NOT_SUSPENDED; /* 如果当前任务为挂起态 */ case RAW_SUSPENDED: /* 之前讲过Raw-OS允许任务挂起嵌套的,这里嵌套层数-1 */ task_ptr->suspend_count--; /* 当被唤醒任务嵌套挂起计数器=0时,唤醒任务 */ if (task_ptr->suspend_count == 0) { /* 更改任务状态为就绪态 */ task_ptr->task_state = RAW_RDY; /* 调度到就绪队列,等待系统调度 */ add_ready_list(&raw_ready_queue, task_ptr); } break; /* 如果当前任务为休眠挂起态 */ case RAW_DLY_SUSPENDED: /* 这里嵌套层数-1 */ task_ptr->suspend_count--; if (task_ptr->suspend_count == 0) { /* 更改任务状态为休眠态 */ task_ptr->task_state = RAW_DLY; } break; /* 如果当前任务为阻塞挂起态 */ case RAW_PEND_SUSPENDED: /* 这里嵌套层数-1 */ task_ptr->suspend_count--; if (task_ptr->suspend_count == 0) { /* 更改任务状态为阻塞态 */ task_ptr->task_state = RAW_PEND; } break; /* 如果当前任务为阻塞超时挂起态 */ case RAW_PEND_TIMEOUT_SUSPENDED: /* 这里嵌套层数-1 */ task_ptr->suspend_count--; if (task_ptr->suspend_count == 0) { /* 更改任务状态为阻塞超时态 */ task_ptr->task_state = RAW_PEND_TIMEOUT; } break; default: RAW_CRITICAL_EXIT(); return RAW_STATE_UNKNOWN; } RAW_CRITICAL_EXIT(); /* 又是trace调试系统??? */ TRACE_TASK_RESUME(raw_task_active, task_ptr); /* 执行系统调度了,那么任务唤醒操作时会进行系统调度 */ raw_sched(); return RAW_SUCCESS; }
那么需要注意的一点是,讨论中是Raw-OS的配置头文件是不涉及CONFIG_RAW_ZERO_INTERRUPT宏和CONFIG_RAW_TASK_0的实现的,以后会另外讨论系统task 0和0中断特性的作用。