分析的内核版本截止到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中断特性的作用。