玖叶教程网

前端编程开发入门

LiteOS内核源码分析系列六-任务调度LOS_Task-5

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;
}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言