如果上一篇文章看明白了,看代码的速度应该会加快很多。
上篇文章写了LiteOS是建立了一个大的任务数组,任务的ID也可以通过数组唯一指定,那通过索引可以快速定位要看的任务。
同时,在不同状态间进行切换时,LiteOS通过两个双向链表实现,这两个双向链表也是能快速理解代码的关键。
下面我们通过一些实例看看它的应用。
首先,我们看看任务结构体的定义:
结构的定义是在文件:Los_tast.ph中(和本文无关的信息,作者删掉了,如果看详细信息请查看源码)
typedef struct tagTaskCB
{
VOID *pStackPointer; /**< Task stack pointer */
..........
CHAR *pcTaskName; /**< Task name */
LOS_DL_LIST stPendList;
LOS_DL_LIST stTimerList;
....................................
} LOS_TASK_CB;
这个结构体重,有两个双向链表:stPendList、stTimerList,这篇文章,我们重点讲的就是这两个。
下面我们通过:LOS_TaskCreate和LOS_TaskCreateOnly来讲解。
//LOS_TaskCreateOnly函数
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *puwTaskID, TSK_INIT_PARAM_S *pstInitParam)
{
.............................
//申请堆栈,8字节对齐
pstInitParam->uwStackSize = ALIGN(pstInitParam->uwStackSize , 8);
................................
//查看待回收的任务列表是不是空的
//如果非空,则把相关任务列表放到g_stLosFreeTask
//同时释放任务堆栈空间
while (!LOS_ListEmpty(&g_stTskRecyleList))
{
pstTaskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_stTskRecyleList)); /*lint !e413*/
LOS_ListDelete(LOS_DL_LIST_FIRST(&g_stTskRecyleList));
LOS_ListAdd(&g_stLosFreeTask, &pstTaskCB->stPendList);
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)pstTaskCB->uwTopOfStack);
}
if (LOS_ListEmpty(&g_stLosFreeTask))
{
uwErrRet = LOS_ERRNO_TSK_TCB_UNAVAILABLE;
OS_GOTO_ERREND();
}
//取出可用任务列表中的第一个任务信息结构体
//并在链表中删除相关结构体
pstTaskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_stLosFreeTask)); /*lint !e413*/
LOS_ListDelete(LOS_DL_LIST_FIRST(&g_stLosFreeTask));
(VOID)LOS_IntRestore(uvIntSave);
uwTaskID = pstTaskCB->uwTaskID; //取任务编号,即数组的索引
//分配堆栈空间
pTopStack = (void *)LOS_MemAllocAlign(m_aucSysMem0, pstInitParam->uwStackSize, 8);
//分配失败,则将任务放回g_stLosFreeTask
if (NULL == pTopStack)
{
uvIntSave = LOS_IntLock();
LOS_ListAdd(&g_stLosFreeTask, &pstTaskCB->stPendList);
uwErrRet = LOS_ERRNO_TSK_NO_MEMORY;
OS_GOTO_ERREND();
}
//任务堆栈初始化,并获取堆栈信息
pStackPtr = osTskStackInit(uwTaskID, pstInitParam->uwStackSize, pTopStack);
.....................................................
pstTaskCB->pcTaskName = pstInitParam->pcName;//传入的任务名不能是局部变量
*puwTaskID = uwTaskID;//返回任务编号,这任务号就是创建任务时传入的那个全局变量或者局部变量;
...................................................
}
在上面的代码中,有一个While循环:
while (!LOS_ListEmpty(&g_stTskRecyleList))
{
pstTaskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_stTskRecyleList)); /*lint !e413*/
LOS_ListDelete(LOS_DL_LIST_FIRST(&g_stTskRecyleList));
LOS_ListAdd(&g_stLosFreeTask, &pstTaskCB->stPendList);
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)pstTaskCB->uwTopOfStack);
}
看到我们的主角了吧:stPendList
整个代码中,这个变量贯穿始终,所有对任务状态切换的管理都是通过stPendList和stTimerList俩实现的。
其中stTimerList主要是用来管理同步过程中的timer状态的。这个链表加入了
stPendList在不运行时,加入了g_stTskRecyleList和g_stLosFreeTask;
其中在LOS_TaskDelete过程中,stPendList加入g_stTskRecyleList中,用于资源回收,表明有可回收的任务列表
g_stLosFreeTask则是我们申请创建任务获取任务资源的链表,从上面的代码我们也可以看到,当获取堆栈资源失败时,我们又把已经取出来的任务放回到了这个链表中。
我们另一个主角stTimerList是在进行任务同步时,加入了g_stTskSortLink。感兴趣的小伙伴可以自己查看osTaskAdd2TimerList
或者等我后续给大家慢慢写。
觉得文章有用的小伙伴,给留言或者点赞吧。