玖叶教程网

前端编程开发入门

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

3.6 回收任务栈资源

从上文已经知道,系统空闲时会调用VOID LOS_TaskResRecycle(VOID)函数回收任务栈资源,该函数调用函数VOID OsTaskCBRecycleToFree(VOID)实现任务资源回收。我们分析下它的代码。

3.6.1 回收所有待回收的任务栈资源LOS_TaskResRecycle

任务删除时,会把任务挂在双向链表里g_taskRecycleList。⑴处循环遍历回收链表,⑵从回收链表获取第一个任务taskCB,从回收链表删除并插入到空闲任务链表里。任务栈保护、异常交互在后续系列再深入分析,继续往下看代码,⑶处释放任务栈占用的内存,并设置任务的栈顶为空。

LITE_OS_SEC_TEXT_INIT STATIC VOID OsTaskCBRecycleToFree(VOID)
{
    LosTaskCB *taskCB = NULL;
    VOID *poolTmp = NULL;
#ifdef LOSCFG_TASK_STACK_PROTECT
    UINTPTR MMUProtectAddr;
#endif
⑴  while (!LOS_ListEmpty(&g_taskRecycleList)) {
        poolTmp = (VOID *)m_aucSysMem1;
⑵      taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_taskRecycleList));
        LOS_ListDelete(LOS_DL_LIST_FIRST(&g_taskRecycleList));
        LOS_ListAdd(&g_losFreeTask, &taskCB->pendList);
#ifdef LOSCFG_TASK_STACK_PROTECT
        MMUProtectAddr = taskCB->topOfStack - MMU_4K;
        OsTaskStackProtect(MMUProtectAddr, MMU_4K, ACCESS_PERM_RW_RW);
#ifdef LOSCFG_EXC_INTERACTION
        if (MMUProtectAddr < (UINTPTR)m_aucSysMem1) {
            poolTmp = (VOID *)m_aucSysMem0;
        }
#endif
        (VOID)LOS_MemFree(poolTmp, (VOID *)MMUProtectAddr);
#else
#ifdef LOSCFG_EXC_INTERACTION
        if (taskCB->topOfStack < (UINTPTR)m_aucSysMem1) {
            poolTmp = (VOID *)m_aucSysMem0;
        }
#endif
⑶      (VOID)LOS_MemFree(poolTmp, (VOID *)taskCB->topOfStack);
#endif
        taskCB->topOfStack = 0;
    }
}

VOID LOS_TaskResRecycle(VOID)
{
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);
    OsTaskCBRecycleToFree();
    SCHEDULER_UNLOCK(intSave);
}

3.7 任务阻塞和唤醒

最后,我们分析下函数OsTaskWait()OsTaskWake(),任务在申请互斥锁、信号量、出入队列、读写事件时,都可能导致任务进入阻塞状态,对应地也需要任务唤醒重新进入就绪队列状态。这2个函数就负责任务的阻塞和唤醒,我们分析下他们的代码。

3.7.1 任务阻塞

我们分析下任务阻塞的函数OsTaskWait(),需要3个参数:LOS_DL_LIST *list是互斥锁等资源的阻塞链表,阻塞的任务会挂这个链表里;UINT16 taskStatus是需要设置阻塞的任务的状态,一般为OS_TASK_STATUS_PENDUINT32 timeout是任务阻塞的时间。分析下具体代码:

⑴获取正在请求互斥锁等资源的当前任务,更改其优先级,不再是就绪状态。⑵设置任务的阻塞状态。⑶把任务插入互斥锁等资源的阻塞链表的尾部。⑷如果不是永久等待,任务的状态还需要设置为OS_TASK_STATUS_PEND_TIME,然后把任务加入定时器排序链表里。

VOID OsTaskWait(LOS_DL_LIST *list, UINT16 taskStatus, UINT32 timeout)
{
    LosTaskCB *runTask = NULL;
    LOS_DL_LIST *pendObj = NULL;

⑴  runTask = OsCurrTaskGet();
    runTask->taskStatus &= ~OS_TASK_STATUS_READY;
    pendObj = &runTask->pendList;
⑵  runTask->taskStatus |= taskStatus;
⑶  LOS_ListTailInsert(list, pendObj);
    if (timeout != LOS_WAIT_FOREVER) {
⑷      runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;
        OsTaskAdd2TimerList((LosTaskCB *)runTask, timeout);
    }
}

3.7.2 任务唤醒

我们分析下任务唤醒的函数OsTaskWake(),需要2个参数:LosTaskCB *resumedTask是需要唤醒的任务;UINT16 taskStatus是需要设置阻塞的任务的状态,一般为OS_TASK_STATUS_PEND;任务唤醒函数会从阻塞链表里删除并加入就绪队列,下面分析下具体代码:

⑴把要唤醒的任务从所在的阻塞队列中删除,然后更改状态不再为阻塞状态。⑵如果任务不是永久等待,需要从定时器排序链表中删除。⑶如果任务是阻塞状态,改为就绪状态并加入就绪队列。

VOID OsTaskWake(LosTaskCB *resumedTask, UINT16 taskStatus)
{
⑴  LOS_ListDelete(&resumedTask->pendList);
    resumedTask->taskStatus &= ~taskStatus;

⑵  if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
        OsTimerListDelete(resumedTask);
        resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
    }
⑶  if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPEND)) {
        resumedTask->taskStatus |= OS_TASK_STATUS_READY;
        OsPriQueueEnqueue(&resumedTask->pendList, resumedTask->priority);
    }
}

小结

本文带领大家一起剖析了LiteOS任务模块的源代码,包含任务模块的结构体,任务初始化过程源代码,任务常用操作的源代码。

感谢阅读,如有任何问题、建议,都可以留言给我们: https://gitee.com/LiteOS/LiteOS/issues 。为了更容易找到LiteOS代码仓,建议访问 https://gitee.com/LiteOS/LiteOS ,关注Watch、点赞Star、并Fork到自己账户下,如下图,谢谢。

发表评论:

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