玖叶教程网

前端编程开发入门

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

3、任务模块常用操作

3.1 创建和删除任务

3.1.1 创建任务

LiteOS提供了4个创建任务的函数,有LOS_TaskCreateLOS_TaskCreateOnlyLOS_TaskCreateStaticLOS_TaskCreateOnlyStaticLOS_TaskCreateLOS_TaskCreateOnly的区别是,前者创建任务完毕就使任务进入就绪状态,并触发调度,如果就绪队列中没有更高优先级的任务,则运行该任务。后者只创建任务,设置任务状态为阻塞suspend状态,需要开发者去调用LOS_TaskResume使该任务进入ready状态。
LOS_TaskCreateStaticLOS_TaskCreateOnlyStatic的区别同上,是否自动去调度。LOS_TaskCreateLOS_TaskCreateOnlyLOS_TaskCreateStaticLOS_TaskCreateOnlyStatic的区别是,创建任务时,任务栈由系统创建还是使用用户提供的任务栈。这4个函数都会调用OsTaskCreateOnly来创建函数,我们以函数LOS_TaskCreate为例一起剖析下创建任务的源码。

函数LOS_TaskCreate代码如下,可以看出创建任务的时候,调用⑴处的函数OsTaskCreateOnly(taskId, initParam, NULL, FALSE),其中FALSE表示不使用用户传入的栈。如果创建精通分配用户栈的任务,需要传递用户栈顶指针、TRUE2个参数,如OsTaskCreateOnly(taskId, initParam, topStack, TRUE)。创建任务后,执行⑶处的代码使任务进行ready就绪状态,下文分别详细分析下这2个函数。

  LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskId, TSK_INIT_PARAM_S *initParam)
  {
⑴    return OsTaskCreateOnly(taskId, initParam, NULL, FALSE);
  }

  LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskId, TSK_INIT_PARAM_S *initParam)
  {
      UINT32 ret;

⑵    ret = LOS_TaskCreateOnly(taskId, initParam);
      if (ret != LOS_OK) {
          return ret;
      }

⑶    OsTaskResume(taskId);

      return LOS_OK;
  }

我们接着分析下如何使用函数UINT32 OsTaskCreateOnly()创建任务,参数BOOL useUsrStack此时取值为FALSE。⑴处调用OsTaskCreateParamCheck(taskId, initParam, &pool)检测创建任务的参数的合法性。⑵处代码调用OsTaskGetFreeTaskCB(&taskCB)g_losFreeTask空闲任务链表中获取一个可用的taskCB。⑶处调用OsTaskSyncCreate(taskCB),只有开启SMP模式、开启LOSCFG_KERNEL_SMP_TASK_SYNC宏时,才支持多任务同步操作,我们先忽略这个方法的实现。⑷处代码不使用用户栈时,调用函数OsTaskStackAlloc(),申请内存,栈顶为topStack。⑸处代码调用OsTaskStackInit()初始化任务栈,函数返回值是栈指针地址stackPtr,⑹调用函数OsTaskCBInit()初始化任务TCB,然后更新taskId,完成任务的创建。OsTaskStackInit()OsTaskCBInit()的具体实现在下文分析。⑺创建任务成功后,返回任务Id

STATIC UINT32 OsTaskCreateOnly(UINT32 *taskId, TSK_INIT_PARAM_S *initParam, VOID *topStack, BOOL useUsrStack)
{
    UINT32 intSave, errRet;
    VOID *stackPtr = NULL;
    LosTaskCB *taskCB = NULL;
    VOID *pool = NULL;

#ifdef LOSCFG_TASK_STATIC_ALLOCATION
    if (useUsrStack) {
        errRet = OsTaskCreateParamCheckStatic(taskId, initParam, topStack);
    } else {
#endif
⑴      errRet = OsTaskCreateParamCheck(taskId, initParam, &pool);
#ifdef LOSCFG_TASK_STATIC_ALLOCATION
    }
#endif
    if (errRet != LOS_OK) {
        return errRet;
    }

    SCHEDULER_LOCK(intSave);
⑵  errRet = OsTaskGetFreeTaskCB(&taskCB);
    if (errRet != LOS_OK) {
        OS_GOTO_ERREND();
    }
    SCHEDULER_UNLOCK(intSave);

⑶  errRet = OsTaskSyncCreate(taskCB);
    if (errRet != LOS_OK) {
        goto LOS_ERREND_REWIND_TCB;
    }

⑷  if (useUsrStack == FALSE) {
        OsTaskStackAlloc(&topStack, initParam->uwStackSize, pool);
        if (topStack == NULL) {
            errRet = LOS_ERRNO_TSK_NO_MEMORY;
            goto LOS_ERREND_REWIND_SYNC;
        }
    }
⑸  stackPtr = OsTaskStackInit(taskCB->taskId, initParam->uwStackSize, topStack);
⑹  OsTaskCBInit(taskCB, initParam, stackPtr, topStack, useUsrStack);

    if (OsConsoleIDSetHook != NULL) {
        OsConsoleIDSetHook(taskCB->taskId, OsCurrTaskGet()->taskId);
    }

#ifdef LOSCFG_KERNEL_CPUP
    OsCpupCB *cpup = OsCpupCBGet(taskCB->taskId);
    cpup->id = taskCB->taskId;
    cpup->status = taskCB->taskStatus;
#endif

⑺  *taskId = taskCB->taskId;
    return LOS_OK;

LOS_ERREND_REWIND_SYNC:
    OsTaskSyncDestroy(taskCB);
LOS_ERREND_REWIND_TCB:
    SCHEDULER_LOCK(intSave);
    LOS_ListAdd(&g_losFreeTask, &taskCB->pendList);
LOS_ERREND:
    SCHEDULER_UNLOCK(intSave);
    return errRet;
}

最后,来看看函数VOID OsTaskResume(const UINT32 *taskId),⑴处把任务的状态从挂起状态``OS_TASK_STATUS_SUSPEND改为就绪状态OS_TASK_STATUS_READY,⑵处代码先判断是否支持调度,支持调度则调用LOS_Schedule()`函数调度,如果就绪队列中没有更高优先级的任务,则运行该新创建的任务。

STATIC VOID OsTaskResume(const UINT32 *taskId)
{
    UINT32 intSave;
    LosTaskCB *taskCB = NULL;

    taskCB = OS_TCB_FROM_TID(*taskId);

    SCHEDULER_LOCK(intSave);

⑴  taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPEND;
    taskCB->taskStatus |= OS_TASK_STATUS_READY;
    OsPriQueueEnqueue(&taskCB->pendList, taskCB->priority);

    SCHEDULER_UNLOCK(intSave);

    LOS_TRACE(TASK_CREATE, taskCB->taskId, taskCB->taskStatus, taskCB->priority);

    LOS_MpSchedule(OS_MP_CPU_ALL);
    if (OS_SCHEDULER_ACTIVE) {
⑵      LOS_Schedule();
    }
}

3.1.2 删除任务UINT32 LOS_TaskDelete()

该函数根据传入的参数UINT32 taskId删除任务。我们分析下删除任务的源代码,⑴处检验传入的参数,然后获取任务taskCB。如果是系统任务,或者任务未创建,返回错误码。⑵处如果删除的是运行中的任务,需要调用函数OsTaskDeleteCheckOnRun(taskCB, &errRet)判断是否允许删除,该函数做如下判断:

  • 开启SMP多核时,不允许跨核删除运行状态的任务
  • 不允许调度时,不能删除运行状态的任务
  • 中断处理期间,不能删除运行状态的任务

⑶处如果任务处于就绪队列中,着从就绪队列出队,并设置状态为非就绪状态。如果处于阻塞状态,从阻塞队列中删除。⑷如果任务处于超时等待状态,从超时排序链表中删除。⑸处设置任务状态非阻塞,未创建。如果开启LOSCFG_BASE_IPC_EVENTLOSCFG_LAZY_STACK宏,重置相关的信息。⑹处调用函数OsTaskDelAction(taskCB, taskCB->usrStack)执行删除任务操作。

LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskId)
{
    LosTaskCB *taskCB = NULL;
    UINT32 intSave, errRet;
    UINT16 tempStatus;

⑴  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_RUNNING) &&
        !OsTaskDeleteCheckOnRun(taskCB, &errRet)) {
        OS_GOTO_ERREND();
    }

⑶  if (tempStatus & OS_TASK_STATUS_READY) {
        OsPriQueueDequeue(&taskCB->pendList);
        taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
    } else if (tempStatus & OS_TASK_STATUS_PEND) {
        LOS_ListDelete(&taskCB->pendList);
    }

⑷  if (tempStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) {
        OsTimerListDelete(taskCB);
    }

⑸  taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPEND;
    taskCB->taskStatus |= OS_TASK_STATUS_UNUSED;
#ifdef LOSCFG_BASE_IPC_EVENT
    taskCB->event.uwEventID = OS_INVALID_VALUE;
    taskCB->eventMask = 0;
#endif
#ifdef LOSCFG_LAZY_STACK
    taskCB->stackFrame = 0;
#endif
#ifdef LOSCFG_KERNEL_CPUP
    (VOID)memset_s((VOID *)OsCpupCBGet(taskCB->taskId), sizeof(OsCpupCB), 0, sizeof(OsCpupCB));
#endif
    OS_MEM_CLEAR(taskId);

    OsTaskSyncWake(taskCB);
⑹  if (OsTaskDelAction(taskCB, taskCB->usrStack)) {
        OsSchedResched();
    }

    SCHEDULER_UNLOCK(intSave);
    return LOS_OK;

LOS_ERREND:
    SCHEDULER_UNLOCK(intSave);
    return errRet;
}

接下来,我们分析下负责删除任务的核心函数BOOL OsTaskDelAction(LosTaskCB *taskCB, BOOL useUsrStack)。⑴先处理下运行状态的任务的删除。⑵如果支持静态分配任务并且使用用户栈,则直接把任务加入空闲任务链表g_losFreeTask,否则把任务加入待回收列表g_losFreeTask,等执行空闲任务时再回收。⑶处的函数会把待删除任务的信息备份到任务池的最后g_taskCBArray[g_taskMaxNum],然后把任务taskCB的状态设置为未使用。

⑷处删除非运行状态的任务,把任务taskCB的状态设置为未使用,然后把任务加入空闲任务链表g_losFreeTask。⑸处如果使用的不是用户栈,需要释放任务栈使用的内存空间。LOSCFG_TASK_STACK_PROTECT宏只有部分平台支持,可以忽略。或者任务栈顶指针,然后执行⑹释放内存,完成任务删除。

LITE_OS_SEC_TEXT_INIT STATIC BOOL OsTaskDelAction(LosTaskCB *taskCB, BOOL useUsrStack)
{
    VOID *pool = (VOID *)m_aucSysMem1;
    UINTPTR taskStack;

    LOS_TRACE(TASK_DELETE, taskCB->taskId, taskCB->taskStatus, taskCB->usrStack);

⑴  if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
#ifdef LOSCFG_TASK_STATIC_ALLOCATION
⑵      if (useUsrStack) {
            LOS_ListAdd(&g_losFreeTask, &taskCB->pendList);
        } else {
#endif
            LOS_ListTailInsert(&g_taskRecycleList, &taskCB->pendList);
#ifdef LOSCFG_TASK_STATIC_ALLOCATION
        }
#endif
⑶      OsTaskDelActionOnRun(taskCB);
        return TRUE;
    }

⑷  taskCB->taskStatus = OS_TASK_STATUS_UNUSED;
    LOS_ListAdd(&g_losFreeTask, &taskCB->pendList);
⑸  if (useUsrStack == FALSE) {
#ifdef LOSCFG_TASK_STACK_PROTECT
        taskStack = taskCB->topOfStack - MMU_4K;
        OsTaskStackProtect(taskStack, MMU_4K, ACCESS_PERM_RW_RW);
#else
        taskStack = taskCB->topOfStack;
#endif

#ifdef LOSCFG_EXC_INTERACTION
        if (taskStack < (UINTPTR)m_aucSysMem1) {
            pool = (VOID *)m_aucSysMem0;
        }
#endif
⑹      (VOID)LOS_MemFree(pool, (VOID *)taskStack);
    }
    taskCB->topOfStack = 0;
    return FALSE;
}

发表评论:

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