3.2 控制任务状态
3.2.1 恢复挂起的任务LOS_TaskResume()
恢复挂起的任务,使该任务进入就绪状态,和下文中的LOS_TaskSuspend()成对使用。⑴处获取任务的TCB,执行⑵清理任务的信号标记为非挂起状态。⑶处获取任务的状态进行判断,如果任务没有创建或者不是挂起状态,则返回相应的错误码。 ⑷设置任务状态非挂起。⑸检查任务状态是否为OS_CHECK_TASK_BLOCK,即(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND | OS_TASK_STATUS_SUSPEND)中的一种,这几个状态影响恢复挂起的任务。⑹把任务状态改为就绪状态,入队就绪队列,并标记是否需要调度needSched = TRUE。⑺如果需要调度,则触发调度。
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskId)
{
UINT32 intSave;
LosTaskCB *taskCB = NULL;
UINT16 tempStatus;
UINT32 errRet;
BOOL needSched = FALSE;
if (OS_TASK_ID_CHECK_INVALID(taskId)) {
return LOS_ERRNO_TSK_ID_INVALID;
}
⑴ taskCB = OS_TCB_FROM_TID(taskId);
SCHEDULER_LOCK(intSave);
/* clear pending signal */
⑵ taskCB->signal &= ~SIGNAL_SUSPEND;
⑶ tempStatus = taskCB->taskStatus;
if (tempStatus & OS_TASK_STATUS_UNUSED) {
errRet = LOS_ERRNO_TSK_NOT_CREATED;
OS_GOTO_ERREND();
} else if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) {
errRet = LOS_ERRNO_TSK_NOT_SUSPENDED;
OS_GOTO_ERREND();
}
⑷ taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPEND;
⑸ if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) {
⑹ taskCB->taskStatus |= OS_TASK_STATUS_READY;
OsPriQueueEnqueue(&taskCB->pendList, taskCB->priority);
if (OS_SCHEDULER_ACTIVE) {
needSched = TRUE;
}
}
SCHEDULER_UNLOCK(intSave);
LOS_TRACE(TASK_RESUME, taskCB->taskId, taskCB->taskStatus, taskCB->priority);
if (needSched) {
⑺ LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return LOS_OK;
LOS_ERREND:
SCHEDULER_UNLOCK(intSave);
return errRet;
}
3.2.2 挂起指定的任务LOS_TaskSuspend()
函数用于挂起指定的任务。⑴处获取任务的TCB,如果当前任务是系统任务,返回错误码。⑵处开始获取任务的状态进行判断,如果任务没有创建、任务已经挂起,返回相应的错误码。⑶处如果任务是运行状态,并且不满足挂起任务的条件时,跳转到LOS_ERREND结束挂起操作。BOOL OsTaskSuspendCheckOnRun(LosTaskCB *taskCB, UINT32 *ret)可以检查运行的任务能否挂起的条件,包括:
- 开启SMP多核时,不允许跨核挂起运行状态的任务
- 不允许调度时,不能挂起运行状态的任务
- 中断处理期间,不能挂起运行状态的任务
⑷处如果任务是就绪状态,从就绪队列出队,并取消任务的就绪状态,下一条语句设置任务状态为阻塞状态。⑸处获取当前任务,如果挂起的是当前任务,则需要执行⑹触发调度。
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskId)
{
UINT32 intSave;
LosTaskCB *taskCB = NULL;
LosTaskCB *runTask = NULL;
UINT16 tempStatus;
UINT32 errRet;
if (OS_TASK_ID_CHECK_INVALID(taskId)) {
return LOS_ERRNO_TSK_ID_INVALID;
}
⑴ taskCB = OS_TCB_FROM_TID(taskId);
if (taskCB->taskFlags & OS_TASK_FLAG_SYSTEM) {
return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK;
}
SCHEDULER_LOCK(intSave);
⑵ tempStatus = taskCB->taskStatus;
if (tempStatus & OS_TASK_STATUS_UNUSED) {
errRet = LOS_ERRNO_TSK_NOT_CREATED;
OS_GOTO_ERREND();
}
if (tempStatus & OS_TASK_STATUS_SUSPEND) {
errRet = LOS_ERRNO_TSK_ALREADY_SUSPENDED;
OS_GOTO_ERREND();
}
⑶ if ((tempStatus & OS_TASK_STATUS_RUNNING) &&
!OsTaskSuspendCheckOnRun(taskCB, &errRet)) {
OS_GOTO_ERREND();
}
⑷ if (tempStatus & OS_TASK_STATUS_READY) {
OsPriQueueDequeue(&taskCB->pendList);
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
}
taskCB->taskStatus |= OS_TASK_STATUS_SUSPEND;
⑸ runTask = OsCurrTaskGet();
LOS_TRACE(TASK_SUSPEND, taskCB->taskId, taskCB->taskStatus, runTask->taskId);
if (taskId == runTask->taskId) {
⑹ OsSchedResched();
}
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
LOS_ERREND:
SCHEDULER_UNLOCK(intSave);
return errRet;
}
3.2.3 任务延时等待LOS_TaskDelay()
任务延时等待,释放CPU,等待时间到期后该任务会重新进入就绪状态。⑴处代码获取当前运行任务,如果当前任务是系统任务,则打印回溯栈并返回错误码。⑵如果不可调度,返回错误码。
⑶处如果延迟的时间为0,则执行让权操作,否则执行⑷,把当前任务取消就绪状态并加入排序链表进行等待,然后调用OsSchedResched()触发调度。
LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick)
{
UINT32 intSave;
LosTaskCB *runTask = NULL;
if (OS_INT_ACTIVE) {
return LOS_ERRNO_TSK_DELAY_IN_INT;
}
⑴ runTask = OsCurrTaskGet();
if (runTask->taskFlags & OS_TASK_FLAG_SYSTEM) {
OsBackTrace();
return LOS_ERRNO_TSK_OPERATE_SYSTEM_TASK;
}
⑵ if (!OsPreemptable()) {
return LOS_ERRNO_TSK_DELAY_IN_LOCK;
}
⑶ if (tick == 0) {
return LOS_TaskYield();
} else {
SCHEDULER_LOCK(intSave);
⑷ OsTaskAdd2TimerList(runTask, tick);
runTask->taskStatus |= OS_TASK_STATUS_DELAY;
OsSchedResched();
SCHEDULER_UNLOCK(intSave);
}
return LOS_OK;
}
3.2.4 任务让权LOS_TaskYield()
当前任务释放CPU,并将其移到具有相同优先级的就绪任务队列的末尾。⑴处如果当前处理中断,返回错误码。⑵处判断是否可以抢占调度,如果不可调度,返回错误码。
⑶处获取当前运行中的任务runTask,执行⑷获取当前任务优先级下的就绪任务的数量。如果数量不足,返回错误。否则执行⑸,把当前任务改为就绪状态并入队就绪队列。然后,执行⑹触发调度。
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID)
{
UINT32 tskCount;
UINT32 intSave;
LosTaskCB *runTask = NULL;
⑴ if (OS_INT_ACTIVE) {
return LOS_ERRNO_TSK_YIELD_IN_INT;
}
⑵ if (!OsPreemptable()) {
return LOS_ERRNO_TSK_YIELD_IN_LOCK;
}
⑶ runTask = OsCurrTaskGet();
if (runTask->taskId >= g_taskMaxNum) {
return LOS_ERRNO_TSK_ID_INVALID;
}
SCHEDULER_LOCK(intSave);
#ifdef LOSCFG_BASE_CORE_TIMESLICE
/* reset timeslice of yielded task */
runTask->timeSlice = 0;
#endif
⑷ tskCount = OsPriQueueSize(runTask->priority);
if (tskCount > 0) {
runTask->taskStatus |= OS_TASK_STATUS_READY;
⑸ OsPriQueueEnqueue(&(runTask->pendList), runTask->priority);
} else {
SCHEDULER_UNLOCK(intSave);
return LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK;
}
⑹ OsSchedResched();
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}