1.任务的挂起与创建 OS 的任务支持挂起和恢复的功能,挂起就相当于暂停,暂停后任务从就绪列表中移除,恢复即重新将任务插入就绪列表。一个任务挂起多少次就要被恢复多少次才能重新运行在这里插入代码片
在任务实现挂起和恢复的时候,要根据任务的状态来操作,任务的状态不同,操作也不同,有关任务状态的宏定义在 os.h 中实现,总共有 9 种状态,
TaskState :
为了实现任务的挂起和恢复 TCB 中有任务的状态 TaskState 和任务挂起 计数器 SusPendCtr 这两个成员
OS_STATE TaskState; // See OS_TASK_STATE_xxx
#if OS_CFG_TASK_SUSPEND_EN > 0u
OS_NESTING_CTR SuspendCtr; // Nesting counter for OSTaskSuspend()
#endif
SuspendCtr: 任务挂起计数器,任务每被挂起一次, SuspendCtr 递增一次,一个任务挂起多少次就要被恢复多少次才能重新运行。
OS_TaskSuspend()任务挂起函数
#if OS_CFG_TASK_SUSPEND_EN > 0u
void OS_TaskSuspend (OS_TCB *p_tcb,
OS_ERR *p_err)
{
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
//是否挂起自己
if (p_tcb == (OS_TCB *)0) { /* See if specified to suspend self */
p_tcb = OSTCBCurPtr;
}
//如果调度器锁住则不能挂起自己
if (p_tcb == OSTCBCurPtr) {
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't suspend when the scheduler is locked */
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_SCHED_LOCKED;
return;
}
}
*p_err = OS_ERR_NONE;
//根据任务状态来决定挂起的动作
switch (p_tcb->TaskState) {
//任务在就绪状态,则将任务的状态改为挂起态,挂起计数器置 1,然后从就绪列表删除。
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;
//任务在延时状态,则将任务的状态改为延时加挂起态,挂起计数器置 1,不用改变 TCB 的位置,即还是在延时的时基列表
case OS_TASK_STATE_DLY:
p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;
//任务在等待状态,则将任务的状态改为等待加挂起态,挂起计数器置 1,不用改变 TCB 的位置,即还是在等待列表等待
case OS_TASK_STATE_PEND:
p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED;
p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
CPU_CRITICAL_EXIT();
break;
//任务在等待加超时态,则将任务的状态改为等待加超时加挂起态,挂起计数器置 1,不用改变 TCB 的位置,即还在等待和时基这两个列表中
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;
//只要有一个是挂起状态,则将挂起计数器加一操作,不用改变 TCB 的位置
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();
}
#endif
OS_TaskResume() 用于恢复被挂起的函数,但是不能恢复自己,挂起倒是可以挂起自己
#if OS_CFG_TASK_SUSPEND_EN > 0u
void OS_TaskResume (OS_TCB *p_tcb,
OS_ERR *p_err)
{
CPU_SR_ALLOC();
CPU_CRITICAL_ENTER();
*p_err = OS_ERR_NONE;
//根据任务的状态来决定恢复操作
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;
//任务只在挂起态,则递减挂起计数器 SuspendCtr,如果SuspendCtr 等于 0,则将任务的状态改为就绪态,并让任务就绪。
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;
//任务在延时加挂起态,则递减挂起计数器 SuspendCtr,如果SuspendCtr 等于 0,则将任务的状态改为延时态。
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;
//任务在延时加等待态,则递减挂起计数器 SuspendCtr,如果SuspendCtr 等于 0,则将任务的状态改为等待态。
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;
//任务在等待加超时加挂起态,则递减挂起计数器 SuspendCtr,如果 SuspendCtr 等于 0,则将任务的状态改为等待加超时态
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;
}
//任务切换
OSSched();
}
#endif
2.任务的删除 任务删除函数 OSTaskDel() 用于删除一个指定的任务,也可以删除自身,
#if OS_CFG_TASK_DEL_EN > 0u
void OSTaskDel (OS_TCB *p_tcb,
OS_ERR *p_err)
{
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to delete from ISR */
*p_err = OS_ERR_TASK_DEL_ISR;
return;
}
#endif
//空闲任务不能被删除。系统必须至少有一个任务在运行,当没有其他用户任务运行的时候,系统就会运行空闲任务。
if (p_tcb == &OSIdleTaskTCB) { /* Not allowed to delete the idle task */
*p_err = OS_ERR_TASK_DEL_IDLE;
return;
}
//不能删除中断里的任务
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
if (p_tcb == &OSIntQTaskTCB) { /* Cannot delete the ISR handler task */
*p_err = OS_ERR_TASK_DEL_INVALID;
return;
}
#endif
//删除自己
if (p_tcb == (OS_TCB *)0) { /* Delete 'Self'? */
CPU_CRITICAL_ENTER();
p_tcb = OSTCBCurPtr; /* Yes. */
CPU_CRITICAL_EXIT();
}
OS_CRITICAL_ENTER();
//根据任务的状态来决定删除的动作
switch (p_tcb->TaskState) {
//任务只在就绪态,则从就绪列表移除
case OS_TASK_STATE_RDY:
OS_RdyListRemove(p_tcb);
break;
//任务只是被挂起,则退出返回,不用做什么,挂起后,任务暂停,会从就绪表中删除
case OS_TASK_STATE_SUSPENDED:
break;
//任务在延时或者是延时加挂起,则从时基列表移除
case OS_TASK_STATE_DLY: /* Task is only delayed, not on any wait list */
case OS_TASK_STATE_DLY_SUSPENDED:
OS_TickListRemove(p_tcb);
break;
//任务在多种状态,但只要有一种是等待状态,就需要从等待列表移除。
如果任务等待是任务自身的信号量和消息,则直接退出返回,因为任务信号量
//和消息是没有等待列表的。
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_SUSPENDED:
case OS_TASK_STATE_PEND_TIMEOUT:
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
OS_TickListRemove(p_tcb);
switch (p_tcb->PendOn) { /* See what we are pending on */
// 如果任务等待是任务自身的信号量和消息,则直接退出返回,因为任务信号量和消息是没有等待列表的。
case OS_TASK_PEND_ON_NOTHING:
case OS_TASK_PEND_ON_TASK_Q: /* There is no wait list for these two */
case OS_TASK_PEND_ON_TASK_SEM:
break;
//从等待列表移除
case OS_TASK_PEND_ON_FLAG: /* Remove from wait list */
case OS_TASK_PEND_ON_MULTI:
case OS_TASK_PEND_ON_MUTEX:
case OS_TASK_PEND_ON_Q:
case OS_TASK_PEND_ON_SEM:
OS_PendListRemove(p_tcb);
break;
default:
break;
}
break;
default:
OS_CRITICAL_EXIT();
*p_err = OS_ERR_STATE_INVALID;
return;
}
#if OS_CFG_TASK_Q_EN > 0u
(void)OS_MsgQFreeAll(&p_tcb->MsgQ); /* Free task's message queue messages */
#endif
OSTaskDelHook(p_tcb); /* Call user defined hook */
#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
OS_TLS_TaskDel(p_tcb); /* Call TLS hook */
#endif
#if OS_CFG_DBG_EN > 0u
OS_TaskDbgListRemove(p_tcb);
#endif
OSTaskQty--; /* One less task being managed */
OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */
//修改任务的状态为删除态,即处于休眠
p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL; /* Indicate that the task was deleted */
OS_CRITICAL_EXIT_NO_SCHED();
*p_err = OS_ERR_NONE; /* See Note #1. */
OSSched(); /* Find new highest priority task */
}
#endif