1. 程式人生 > 實用技巧 >LiteOS-任務篇-原始碼分析-建立任務函式

LiteOS-任務篇-原始碼分析-建立任務函式

目錄


前言

  • 20201009
  • LiteOS 2018
  • 需要會通用連結串列

連結

參考

  • 上面連結

筆錄草稿

部分原始碼分析

原始碼分析

LOS_TaskCreate函式

  • 需要一個 任務初始化引數結構體 TSK_INIT_PARAM_S 和 一個任務控制代碼。
  • TSK_INIT_PARAM_S 原始碼
/**
 * @ingroup los_task
 * Define the structure of the parameters used for task creation.
 *
 * Information of specified parameters passed in during task creation.
 */
typedef struct tagTskInitParam
{
   TSK_ENTRY_FUNC       pfnTaskEntry;               /**< Task entrance function    */
   UINT16               usTaskPrio;                 /**< Task priority             */
   UINT32               uwArg;                      /**< Task parameters           */
   UINT32               uwStackSize;                /**< Task stack size           */
   CHAR                 *pcName;                    /**< Task name                 */
   UINT32               uwResved;                   /**< Reserved                  */
} TSK_INIT_PARAM_S;
  • LOS_TaskCreate 函式原始碼
    • 內含解讀
/*****************************************************************************
 Function : LOS_TaskCreate
 Description : Create a task
 Input       : pstInitParam --- Task init parameters
 Output      : puwTaskID    --- Save task ID
 Return      : LOS_OK on success or error code on failure
 *****************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *puwTaskID, TSK_INIT_PARAM_S *pstInitParam)
{
    UINT32 uwRet = LOS_OK;
    UINTPTR uvIntSave;
    LOS_TASK_CB *pstTaskCB; // 定義一個任務控制塊

    uwRet = LOS_TaskCreateOnly(puwTaskID, pstInitParam); // 以掛起的方式建立一個新的任務(即是阻塞態)
    if (LOS_OK != uwRet)
    {
        return uwRet;
    }
    pstTaskCB = OS_TCB_FROM_TID(*puwTaskID); // 通過任務 ID 獲取 TCB 控制代碼

    uvIntSave = LOS_IntLock(); // 鎖任務
    pstTaskCB->usTaskStatus &= (~OS_TASK_STATUS_SUSPEND);
    pstTaskCB->usTaskStatus |= OS_TASK_STATUS_READY; // 解除阻塞-->進入就緒

#if (LOSCFG_BASE_CORE_CPUP == YES) // CPU 利用率模組程式碼段
    g_pstCpup[pstTaskCB->uwTaskID].uwID = pstTaskCB->uwTaskID;
    g_pstCpup[pstTaskCB->uwTaskID].usStatus = pstTaskCB->usTaskStatus;
#endif

    osPriqueueEnqueue(&pstTaskCB->stPendList, pstTaskCB->usPriority); // 將該任務插入 優先順序佇列 ,即是 就緒列表
    g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(osPriqueueTop(), LOS_TASK_CB, stPendList); /*lint !e413*/ /* 找出已經建立的任務中最高優先順序、最先插入的 TCB */

	/* 以下只是判斷是否需要排程而已 */
	/* 如果系統開啟了排程,且,鎖任務關閉,則,進入二次判斷 */
    if ((g_bTaskScheduled) && (g_usLosTaskLock == 0))
    {
    	/* 如果最高優先順序、最先插入的任務不在執行態,則進行排程 */
        if (g_stLosTask.pstRunTask != g_stLosTask.pstNewTask)
        {
            if (LOS_CHECK_SCHEDULE)
            {
                (VOID)LOS_IntRestore(uvIntSave);
                osSchedule();
                return LOS_OK;
            }
        }
    }
	/* 解鎖任務排程 */
    (VOID)LOS_IntRestore(uvIntSave);
    return LOS_OK;
}

LOS_TaskCreateOnly函式

  • g_stTskRecyleList
    • 任務可回收連結串列
  • g_stLosFreeTask
    • 任務可用連結串列
/*****************************************************************************
 Function : LOS_TaskCreateOnly
 Description : Create a task and suspend
 Input       : pstInitParam --- Task init parameters
 Output      : puwTaskID    --- Save task ID
 Return      : LOS_OK on success or error code on failure
 *****************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *puwTaskID, TSK_INIT_PARAM_S *pstInitParam)
{
    UINT32 uwTaskID = 0;
    UINTPTR uvIntSave;
    VOID  *pTopStack;
    VOID  *pStackPtr;
    LOS_TASK_CB *pstTaskCB;
    UINT32 uwErrRet = OS_ERROR;
	
	/* 元素合法檢查 [start][A] */
    if (NULL == puwTaskID)
    {
        return LOS_ERRNO_TSK_ID_INVALID;
    }

    if (NULL == pstInitParam)
    {
        return LOS_ERRNO_TSK_PTR_NULL;
    }

    if (NULL == pstInitParam->pcName)
    {
        return LOS_ERRNO_TSK_NAME_EMPTY;
    }

    if (NULL == pstInitParam->pfnTaskEntry)
    {
        return LOS_ERRNO_TSK_ENTRY_NULL;
    }

    if ((pstInitParam->usTaskPrio) > OS_TASK_PRIORITY_LOWEST)
    {
        return LOS_ERRNO_TSK_PRIOR_ERROR;
    }

    if (((pstInitParam->usTaskPrio) == OS_TASK_PRIORITY_LOWEST)
        && (pstInitParam->pfnTaskEntry != OS_IDLE_TASK_ENTRY))
    {
        return LOS_ERRNO_TSK_PRIOR_ERROR;
    }

    if (pstInitParam->uwStackSize > OS_SYS_MEM_SIZE)
    {
        return LOS_ERRNO_TSK_STKSZ_TOO_LARGE;
    }

    if (0 == pstInitParam->uwStackSize)
    {
        pstInitParam->uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
    }
    pstInitParam->uwStackSize = ALIGN(pstInitParam->uwStackSize , 8);

    if (pstInitParam->uwStackSize < LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE)
    {
        return LOS_ERRNO_TSK_STKSZ_TOO_SMALL;
    }
	/* 元素合法檢查 [end][A] */
	
    uvIntSave = LOS_IntLock(); // 鎖任務
    /* 處理任務可回收連結串列,釋放出可用任務空間 */
    while (!LOS_ListEmpty(&g_stTskRecyleList))
    {
        pstTaskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_stTskRecyleList)); /*lint !e413*/ /* 獲取任務 可回收連結串列 中的 第一個 TCB。 *後面有原始碼分析* */
        LOS_ListDelete(LOS_DL_LIST_FIRST(&g_stTskRecyleList)); // 從該連結串列中刪除該節點
        LOS_ListAdd(&g_stLosFreeTask, &pstTaskCB->stPendList); // 把該任塊放到 可用連結串列 中
        (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)pstTaskCB->uwTopOfStack); // 釋放該任務申請的任務棧空間
        pstTaskCB->uwTopOfStack = (UINT32)NULL;// 初始化該任務塊棧頂指標
    }

	/* 判斷是否還有可用任務塊使用,若沒有,則,退出 */
    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*/ /* 獲取 可用連結串列 中第一個節點對應的 TCB。*後面有原始碼分析* */
    LOS_ListDelete(LOS_DL_LIST_FIRST(&g_stLosFreeTask)); // 上面獲取後,便從 可用連結串列 中刪除該節點。
    (VOID)LOS_IntRestore(uvIntSave); // 解鎖任務
    uwTaskID = pstTaskCB->uwTaskID;  // 獲取 ID

    pTopStack = (VOID *)LOS_MemAllocAlign(m_aucSysMem0, pstInitParam->uwStackSize, 8); // 申請動態記憶體,8 位元組對齊

    if (NULL == pTopStack) // 申請失敗
    {
        uvIntSave = LOS_IntLock();
        LOS_ListAdd(&g_stLosFreeTask, &pstTaskCB->stPendList);
        uwErrRet = LOS_ERRNO_TSK_NO_MEMORY;
        OS_GOTO_ERREND();
    }
	/* 申請成功 */
	
	/* 初始化 TCB */
    pStackPtr = osTskStackInit(uwTaskID, pstInitParam->uwStackSize, pTopStack);
    pstTaskCB->pStackPointer     = pStackPtr;
    pstTaskCB->uwArg             = pstInitParam->uwArg;
    pstTaskCB->uwTopOfStack      = (UINT32)pTopStack;
    pstTaskCB->uwStackSize       = pstInitParam->uwStackSize;
    pstTaskCB->pTaskSem          = NULL;
    pstTaskCB->pTaskMux          = NULL;
    pstTaskCB->usTaskStatus      = OS_TASK_STATUS_SUSPEND;
    pstTaskCB->usPriority        = pstInitParam->usTaskPrio;
    pstTaskCB->pfnTaskEntry      = pstInitParam->pfnTaskEntry;
    pstTaskCB->uwEvent.uwEventID = 0xFFFFFFFF;
    pstTaskCB->uwEventMask       = 0;
    pstTaskCB->pcTaskName        = pstInitParam->pcName;
    pstTaskCB->puwMsg = NULL;

    *puwTaskID = uwTaskID; /* 更新 ID,返回給上層 */
    return LOS_OK; /* 建立成功 */

LOS_ERREND:
    (VOID)LOS_IntRestore(uvIntSave);
    return uwErrRet;
}

巨集 OS_TCB_FROM_PENDLIST 和 巨集 LOS_DL_LIST_FIRST

  • OS_TCB_FROM_PENDLIST
    • 獲取 連結因子 ptr 中所在的任務控制塊的首地址
    • 意思就是:獲取某條 stPendList 連結串列 中 ptr 節點的 TCB控制代碼
/**
* @ingroup  los_task
* @brief Obtain the pointer to a task control block.
* @par Description:
* This API is used to obtain the pointer to a task control block using a corresponding parameter.
* @param  ptr [IN] Parameter used for obtaining the task control block.
* @retval Pointer to the task control block.
*/
#define OS_TCB_FROM_PENDLIST(ptr)                       LOS_DL_LIST_ENTRY(ptr, LOS_TASK_CB, stPendList)
  • LOS_DL_LIST_ENTRY
    • 通用連結串列的演算法
    • 獲取連結因子 item 所在的資料塊的首地址
/**
 *@ingroup los_list
 *@brief Obtain the pointer to a structure that contains a doubly linked list.
 *@par Description:
 *This API is used to obtain the pointer to a structure that contains a doubly linked list.
 *@param item    [IN] Current node's pointer to the next node.
 *@param type    [IN] Structure name.
 *@param member  [IN] Member name of the doubly linked list in the structure.
 *@retval Pointer to the structure that contains the doubly linked list.
 */
#define LOS_DL_LIST_ENTRY(item, type, member) \
    ((type *)((char *)item - LOS_OFF_SET_OF(type, member))) \
  • LOS_OFF_SET_OF
    • 通用連結串列的演算法
    • 算出 結構體首地址成員 之間的便宜。
/**
 *@ingroup los_list
 *@brief Obtain the pointer to a doubly linked list in a structure.
 *@par Description:
 *This API is used to obtain the pointer to a doubly linked list in a structure.
 *@param type    [IN] Structure name.
 *@param member  [IN] Member name of the doubly linked list in the structure.
 *@retval Pointer to the doubly linked list in the structure.
 */
#define LOS_OFF_SET_OF(type, member) ((long)&((type *)0)->member)   /*lint -e(413) */

任務控制塊 LOS_TASK_CB

/**
 * @ingroup los_task
 * Define the task control block structure.
 */
typedef struct tagTaskCB
{
    VOID                        *pStackPointer;             /**< Task stack pointer          */
    UINT16                      usTaskStatus;
    UINT16                      usPriority;
    UINT32                      uwStackSize;                /**< Task stack size             */
    UINT32                      uwTopOfStack;               /**< Task stack top              */
    UINT32                      uwTaskID;                   /**< Task ID                     */
    TSK_ENTRY_FUNC              pfnTaskEntry;               /**< Task entrance function      */
    VOID                        *pTaskSem;                  /**< Task-held semaphore         */
    VOID                        *pTaskMux;                  /**< Task-held mutex             */
    UINT32                      uwArg;                      /**< Parameter                   */
    CHAR                        *pcTaskName;                /**< Task name                   */
    LOS_DL_LIST                 stPendList;
    LOS_DL_LIST                 stTimerList;
    UINT32                      uwIdxRollNum;
    EVENT_CB_S                  uwEvent;
    UINT32                      uwEventMask;                /**< Event mask                  */
    UINT32                      uwEventMode;                /**< Event mode                  */
    VOID                        *puwMsg;                    /**< Memory allocated to queues  */
} LOS_TASK_CB;