任务模块初始化
在系统启动时,在kernel\init\los_init.c中调用OsTaskInit()进行任务模块初始化,还会调用OsIdleTaskCreate()创建空闲任务。
2.1 任务模块初始化
函数OsTaskInit()定义在kernel\base\los_task.c,我们分析下这个函数的执行过程。
⑴处代码获取开发板配置的最大任务数g_taskMaxNum,计算需要申请的内存大小size,为任务控制块TCB数组(也叫作任务池)g_taskCBArray申请内存。为什么比最大任务数多申请一个呢?在删除任务时会使用。下文分析删除任务的源码时再详细讲解其用意。⑵处代码初始化双向链表g_losFreeTask用作空闲的任务链表、g_taskRecycleList可以回收的任务链表。⑶处循环初始化每一个任务,任务状态未使用OS_TASK_STATUS_UNUSED,初始化任务Id,并把任务挂在空闲任务链表上。⑷处初始化优先级队列,详细的代码实现剖析,参见之前的源码剖析文章。⑸处互斥锁死锁检测的调测特性的,后续系列文章专题进行讲解。⑹处代码初始化排序链表,详细的代码实现剖析,参见之前的源码剖析文章。⑺处如果开启了惰性栈,计算TCB的成员变量stackFrame在其结构体中的偏移量g_stackFrameOffLenInTcb。
LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
{
UINT32 index;
UINT32 ret;
UINT32 size;
⑴ g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;
size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);
if (g_taskCBArray == NULL) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
(VOID)memset_s(g_taskCBArray, size, 0, size);
⑵ LOS_ListInit(&g_losFreeTask);
LOS_ListInit(&g_taskRecycleList);
⑶ for (index = 0; index < g_taskMaxNum; index++) {
g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
g_taskCBArray[index].taskId = index;
LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);
}
⑷ ret = OsPriQueueInit();
if (ret != LOS_OK) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
⑸ ret = OsMuxDlockCheckInitHook();
if (ret != LOS_OK) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
⑹ for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
ret = OsSortLinkInit(&g_percpu[index].taskSortLink);
if (ret != LOS_OK) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
}
#ifdef LOSCFG_LAZY_STACK
⑺ g_stackFrameOffLenInTcb = (UINT16)LOS_OFF_SET_OF(LosTaskCB, stackFrame);
#endif
return LOS_OK;
}
2.2 创建空闲任务IdleCore000
除了初始化任务池,在系统启动阶段还会创建idle空闲任务。⑴处设置任务初始化参数时,空闲任务的入口执行函数为OsIdleTask()。⑵处可以看出空闲任务标记为了系统级别的任务OS_TASK_FLAG_SYSTEM。
LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S taskInitParam;
Percpu *perCpu = OsPercpuGet();
UINT32 *idleTaskId = &perCpu->idleTaskId;
(VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
⑴ taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsIdleTask;
taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE;
taskInitParam.pcName = "IdleCore000";
taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST;
#ifdef LOSCFG_KERNEL_SMP
taskInitParam.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
#endif
ret = LOS_TaskCreate(idleTaskId, &taskInitParam);
if (ret == LOS_OK) {
⑵ OS_TCB_FROM_TID(*idleTaskId)->taskFlags |= OS_TASK_FLAG_SYSTEM;
}
return ret;
}
我们看下空闲任务的入口执行函数为OsIdleTask(),它调用LOS_TaskResRecycle()回收任务栈资源,后文会分析如何回收任务指引。
LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID)
{
while (1) {
LOS_TaskResRecycle();
#ifdef LOSCFG_KERNEL_LOWPOWER
if (g_lowPowerHook != NULL) {
g_lowPowerHook();
}
#else
wfi();
#endif
}
}