uCOS-Ⅲ学习笔记: 任务挂起&恢复
一、简介
任务的挂起:即将任务从就绪列表中暂时移除,不再参与运行,恢复即把任务从新插入到就绪列表,继续运行
二、设置挂起恢复有关函数以及变量
挂起恢复有关变量(TCB中)
- 任务TCB添加有关变量储存任务状态以及记录任务挂起的次数(挂起多少次就要恢复多少次才能继续插入就绪列表)
- OS_STATE TaskState(记入任务状态)
- OS_STATE u8类型重定义类型
- SuspendCtr(挂起次数计数器)
编写调度函数
任务挂起函数
OSTaskSuspend
(
OS_TCB *tcb
OS_ERR *err
)//(任务挂起函数格式,以及其传递进去函数形式)
- 创建临界段调用参数
CPU_SR_ALLOC();
//展开(头文件中的定义)
/* 定义一个局部变量,用于保存CPU中断状态 */
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0
#else
#define CPU_SR_ALLOC()
#endif
- 是否开启屏蔽
- 根据宏定义判断一些任务的可执行性
- ISR程序中不可调用挂起,否则报错
- 中断处理函数不能挂起,否则报错
- 空闲任务不能挂起,否则报错
#if 0 /* 屏蔽开始 */
#ifdef OS_SAFETY_CRITICAL
/* 安全检查,OS_SAFETY_CRITICAL_EXCEPTION()函数需要用户自行编写 */
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
/* 不能在ISR程序中调用该函数 */
if (OSIntNestingCtr > (OS_NESTING_CTR)0) {
*p_err = OS_ERR_TASK_SUSPEND_ISR;
return;
}
#endif
/* 不能挂起空闲任务 */
if (p_tcb == &OSIdleTaskTCB) {
*p_err = OS_ERR_TASK_SUSPEND_IDLE;
return;
}
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
/* 不能挂起中断处理任务 */
if (p_tcb == &OSIntQTaskTCB) {
*p_err = OS_ERR_TASK_SUSPEND_INT_HANDLER;
return;
}
#endif
- 进入临界段
CPU_CRITICAL_ENTER();
- 判断传入TCB==0?
- 若等于0,则令TCB=OSTCBCurPtr
- 不为0,判断若为OSTCBCurPtr ,则根据一个调度器宏定义变量判断,若调度器锁住,退出临界段,并报错
/* 是否挂起自己 */
if (p_tcb == (OS_TCB *)0)
{
p_tcb = OSTCBCurPtr;
}
if (p_tcb == OSTCBCurPtr)
{
/* 如果调度器锁住则不能挂起自己 */
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0)
{
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_SCHED_LOCKED;
return;
}
}
*p_err = OS_ERR_NONE;
- 判断传入TCB的状态 switch判断
- 非挂起状态进行挂起操作(状态切换为当前状态+挂起),挂起数目1,退出临界段和判断
- 已经挂起的任务执行default,挂起数目+1,退出临界段和判断
/* 根据任务的状态来决定挂起的动作 */
switch (p_tcb->TaskState)
{
case OS_TASK_STATE_RDY:
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
OS_RdyListRemove(p_tcb);
OS_CRITICAL_EXIT_NO_SCHED();
break;
case OS_TASK_STATE_DLY:
p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;
case OS_TASK_STATE_PEND:
p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;
case OS_TASK_STATE_PEND_TIMEOUT:
p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;
case OS_TASK_STATE_SUSPENDED:
case OS_TASK_STATE_DLY_SUSPENDED:
case OS_TASK_STATE_PEND_SUSPENDED:
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
p_tcb->SuspendCtr++;
CPU_CRITICAL_EXIT();
break;
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_STATE_INVALID;
return;
}
- 任务切换(任务状态改变后都要进行任务切换)
/* 任务切换 */
OSSched();
任务挂起恢复函数
OSTaskResume
{
OS_TCB *p_tcb
OS_TCB *p_err
}
//(任务恢复函数,用于恢复被挂起的任务,无法恢复自己,函数形式如上)
- 创建临界段调用参数
(同挂起函数) - 是否开启屏蔽
- 根据宏定义判断一些任务的可执行性
- ISR程序中不可调用挂起,否则报错
- 不能挂起当前任务自己
(同上,因为没有空闲任务挂起,所以少一个) - 判断任务状态,执行对应的恢复动作(switch判断)任务挂起数目递减;同时判断若挂起数量等于0,则将任务恢复到挂起之前状态(就绪、延迟、等待、等待+超时),再退出临界段
/* 根据任务的状态来决定恢复的动作 */
switch (p_tcb->TaskState)
{
case OS_TASK_STATE_RDY:
case OS_TASK_STATE_DLY:
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_TIMEOUT:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_TASK_NOT_SUSPENDED;
break;
case OS_TASK_STATE_SUSPENDED:
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
p_tcb->TaskState = OS_TASK_STATE_RDY;
OS_TaskRdy(p_tcb);
}
OS_CRITICAL_EXIT_NO_SCHED();
break;
case OS_TASK_STATE_DLY_SUSPENDED:
p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
p_tcb->TaskState = OS_TASK_STATE_DLY;
}
CPU_CRITICAL_EXIT();
break;
case OS_TASK_STATE_PEND_SUSPENDED:
p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
p_tcb->TaskState = OS_TASK_STATE_PEND;
}
CPU_CRITICAL_EXIT();
break;
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
}
CPU_CRITICAL_EXIT();
break;
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_STATE_INVALID;
return;
}
- 任务切换
三、调用流程
- 初始化
- 任务TCB、创建变量;
*/
struct os_tcb
{
//任务状态标志
OS_STATE TaskState;
#if OS_CFG_TASK_SUSPEND_EN > 0u
/* 任务挂起函数OSTaskSuspend()计数器 */
OS_NESTING_CTR SuspendCtr;
#endif
};
- 调用
- 在任务中直接根据需求使用
//挂起
OSTaskSuspend(&Task1TCB,&err);
//恢复
OSTaskResume(&Task1TCB,&err);