成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

鴻蒙輕內核M核源碼分析系列六任務及任務調度(2)任務模塊

開發
本文帶領大家一起剖析了鴻蒙輕內核任務模塊的源代碼,包含任務模塊的結構體,任務初始化過程源代碼,任務常用操作的源代碼。

[[399389]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

任務是操作系統一個重要的概念,是競爭系統資源的最小運行單元。任務可以使用或等待CPU、使用內存空間等系統資源,并獨立于其它任務運行。鴻蒙輕內核的任務模塊可以給用戶提供多個任務,實現任務間的切換,幫助用戶管理業務程序流程。

接下來,我們看下任務模塊的結構體,任務初始化,任務常用操作的源代碼。

1、任務模塊的結構體定義

在文件kernel\include\los_task.h定義的任務控制塊結構體LosTaskCB,源代碼如下,結構體成員的解釋見注釋部分。

  1. typedef struct { 
  2.     VOID                        *stackPointer;            /* 任務棧指針 */ 
  3.     UINT16                      taskStatus;               /* 任務狀態 */ 
  4.     UINT16                      priority;                 /* 任務優先級 */ 
  5.     INT32                       timeSlice;                /* 剩余的時間片 */ 
  6.     UINT32                      waitTimes; 
  7.     SortLinkList                sortList;                 /* 任務超時排序鏈表節點 */ 
  8.     UINT64                      startTime; 
  9.     UINT32                      stackSize;                /* 任務棧大小 */ 
  10.     UINT32                      topOfStack;               /* 棧頂指針 */ 
  11.     UINT32                      taskID;                   /* 任務編號Id */ 
  12.     TSK_ENTRY_FUNC              taskEntry;                /* 任務入口函數 */ 
  13.     VOID                        *taskSem;                 /* 任務持有的信號量 */ 
  14.     VOID                        *taskMux;                 /* 導致任務阻塞的互斥鎖 */ 
  15.     UINT32                      arg;                      /* 任務入口函數的參數 */ 
  16.     CHAR                        *taskName;                /* 任務名稱 */ 
  17.     LOS_DL_LIST                 pendList;                 /* 就緒隊列等鏈表節點 */ 
  18.     LOS_DL_LIST                 timerList;                /* 任務超時排序鏈表節點 */ 
  19.     EVENT_CB_S                  event; 
  20.     UINT32                      eventMask;                /* 事件掩碼 */ 
  21.     UINT32                      eventMode;                /* 事件模式 */ 
  22.     VOID                        *msg;                     /* 分給給隊列的內存*/ 
  23.     INT32                       errorNo; 
  24. } LosTaskCB; 

 另外一個比較重要的結構體是TSK_INIT_PARAM_S,創建任務時,需要指定任務初始化的參數。源代碼如下,結構體成員的解釋見注釋部分。

  1. typedef struct tagTskInitParam { 
  2.     TSK_ENTRY_FUNC       pfnTaskEntry;              /** 任務入口函數 */ 
  3.     UINT16               usTaskPrio;                /** 任務參數  */ 
  4.     UINT32               uwStackSize;               /** 任務棧大小 */ 
  5.     CHAR                 *pcName;                   /** 任務名稱  */ 
  6.     UINT32               uwResved;                  /** 保留  */ 
  7. } TSK_INIT_PARAM_S; 

 2、任務模塊初始化

在系統啟動時,在kernel\src\los_init.c中調用OsTaskInit()進行任務模塊初始化,還會調用OsIdleTaskCreate()創建空閑任務。

2.1 任務模塊初始化

函數OsTaskInit()定義在kernel\src\los_task.c,我們分析下這個函數的執行過程。

⑴處代碼根據開發板配置的最大任務數g_taskMaxNum,計算需要申請的內存大小size,為任務控制塊TCB數組(也叫作任務池)g_taskCBArray申請內存。為什么比最大任務數多申請一個呢?在刪除任務時會使用。下文分析刪除任務的源碼時再詳細講解其用意。

⑵處代碼初始化雙向鏈表g_losFreeTask用作空閑的任務鏈表、g_taskRecyleList可以回收的任務鏈表。

⑶處循環初始化每一個任務,任務狀態未使用OS_TASK_STATUS_UNUSED,初始化任務Id,并把任務掛在空閑任務鏈表上。

⑷處初始化全局變量LosTask g_losTask,該全局變量維護當前運行的任務和要調度執行的任務。初始化任務池時,設置當前運行的任務為g_taskCBArray[g_taskMaxNum]。⑸處空閑任務編號暫時設置為無效值,后續創建空閑任務時再設置空閑任務編號。

優先級隊列,詳細的代碼實現剖析,參見之前的源碼剖析文章。⑸處互斥鎖死鎖檢測的調測特性的,后續系列文章專題進行講解。⑹處代碼初始化排序鏈表,詳細的代碼實現剖析,參見之前的源碼剖析文章。⑺處如果開啟了惰性棧,計算TCB的成員變量stackFrame在其結構體中的偏移量g_stackFrameOffLenInTcb。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID) 
  2.     UINT32 size
  3.     UINT32 index
  4.  
  5. ⑴  size = (g_taskMaxNum + 1) * sizeof(LosTaskCB); 
  6.     g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size); 
  7.     if (g_taskCBArray == NULL) { 
  8.         return LOS_ERRNO_TSK_NO_MEMORY; 
  9.     } 
  10.     (VOID)memset_s(g_taskCBArray, size, 0, size); 
  11.  
  12. ⑵  LOS_ListInit(&g_losFreeTask); 
  13.     LOS_ListInit(&g_taskRecyleList); 
  14. ⑶  for (index = 0; index <= LOSCFG_BASE_CORE_TSK_LIMIT; index++) { 
  15.         g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED; 
  16.         g_taskCBArray[index].taskID = index
  17.         LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList); 
  18.     } 
  19.  
  20.     // Ignore the return code when matching CSEC rule 6.6(4). 
  21. ⑷  (VOID)memset_s((VOID *)(&g_losTask), sizeof(g_losTask), 0, sizeof(g_losTask)); 
  22.     g_losTask.runTask = &g_taskCBArray[g_taskMaxNum]; 
  23.     g_losTask.runTask->taskID = index
  24.     g_losTask.runTask->taskStatus = (OS_TASK_STATUS_UNUSED | OS_TASK_STATUS_RUNNING); 
  25.     g_losTask.runTask->priority = OS_TASK_PRIORITY_LOWEST + 1; 
  26.  
  27. ⑸  g_idleTaskID = OS_INVALID; 
  28. ⑹  return OsSchedInit(); 

 2.2 創建空閑任務IdleCore000

除了初始化任務池,在系統啟動階段還會創建idle空閑任務。⑴處設置任務初始化參數時,空閑任務的入口執行函數為OsIdleTask()。⑵處調用函數把空閑任務狀態設置為就緒狀態。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(VOID) 
  2.     UINT32 retVal; 
  3.     TSK_INIT_PARAM_S taskInitParam; 
  4.     // Ignore the return code when matching CSEC rule 6.6(4). 
  5.     (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 
  6. ⑴  taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsIdleTask; 
  7.     taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE; 
  8.     taskInitParam.pcName = "IdleCore000"
  9.     taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST; 
  10.     retVal = LOS_TaskCreateOnly(&g_idleTaskID, &taskInitParam); 
  11.  
  12.     if (retVal != LOS_OK) { 
  13.         return retVal; 
  14.     } 
  15.  
  16. ⑵  OsSchedSetIdleTaskSchedPartam(OS_TCB_FROM_TID(g_idleTaskID)); 
  17.     return LOS_OK; 

 我們看下空閑任務的入口執行函數為OsIdleTask(),它調用OsRecyleFinishedTask()回收任務棧資源,后文會分析如何回收任務資源。

  1. LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID) 
  2.     while (1) { 
  3.         OsRecyleFinishedTask(); 
  4.         HalEnterSleep(OS_SYS_DEEP_SLEEP); 
  5.     } 

 3、任務模塊常用操作

3.1 創建和刪除任務

3.1.1 創建任務

鴻蒙輕內核提供了2個創建任務的函數,有LOS_TaskCreate、LOS_TaskCreateOnly。LOS_TaskCreate和LOS_TaskCreateOnly的區別是,前者創建任務完畢就使任務進入就緒狀態,并觸發調度,如果就緒隊列中沒有更高優先級的任務,則運行該任務。后者只創建任務,設置任務狀態為阻塞suspend狀態,需要開發者去調用LOS_TaskResume使該任務進入ready狀態。

函數LOS_TaskCreate代碼如下,可以看出創建任務的時候,調用⑴處的函數LOS_TaskCreateOnly()來創建任務。創建任務后,執行⑵處的代碼使任務進入ready就緒隊列,如果系統啟動完成,允許任務調度,則執行⑶觸發任務調度。如果新創建的任務優先級最高,則會被調度運行。 

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *taskInitParam) 
  2.     UINT32 retVal; 
  3.     UINTPTR intSave; 
  4.     LosTaskCB *taskCB = NULL
  5.  
  6. ⑴  retVal = LOS_TaskCreateOnly(taskID, taskInitParam); 
  7.     if (retVal != LOS_OK) { 
  8.         return retVal; 
  9.     } 
  10.     taskCB = OS_TCB_FROM_TID(*taskID); 
  11.  
  12.     intSave = LOS_IntLock(); 
  13. #if (LOSCFG_BASE_CORE_CPUP == 1) 
  14.     g_cpup[taskCB->taskID].cpupID = taskCB->taskID; 
  15.     g_cpup[taskCB->taskID].status = taskCB->taskStatus; 
  16. #endif 
  17.  
  18. ⑵  OsSchedTaskEnQueue(taskCB); 
  19.     LOS_IntRestore(intSave); 
  20.  
  21. ⑶  if (g_taskScheduled) { 
  22.         LOS_Schedule(); 
  23.     } 
  24.  
  25.     return LOS_OK; 

我們接著分析下如何使用函數UINT32 LOS_TaskCreateOnly()創建任務。⑴處調用OsTaskInitParamCheck()檢測創建任務的參數的合法性。⑵處調用函數回收釋放的任務。⑶處如果任務池為空,無法創建任務,返回錯誤碼。⑷處從任務池獲取一個空閑的任務控制塊taskCB,然后從空閑任務鏈表中刪除。⑸處根據指定的任務棧大小為任務棧申請內存,⑹處判斷任務棧內存申請釋放成功,如果申請失敗,則把任務控制塊歸還到空閑任務鏈表中,并返回錯誤碼。⑺處調用函數初始化任務棧,更新任務控制塊成員信息。詳細見后面對該函數的分析。 

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S *taskInitParam) 
  2.     UINTPTR intSave; 
  3.     VOID  *topOfStack = NULL
  4.     LosTaskCB *taskCB = NULL
  5.     UINT32 retVal; 
  6.  
  7.     if (taskID == NULL) { 
  8.         return LOS_ERRNO_TSK_ID_INVALID; 
  9.     } 
  10.  
  11. ⑴  retVal = OsTaskInitParamCheck(taskInitParam); 
  12.     if (retVal != LOS_OK) { 
  13.         return retVal; 
  14.     } 
  15.  
  16. ⑵  OsRecyleFinishedTask(); 
  17.  
  18.     intSave = LOS_IntLock(); 
  19. ⑶  if (LOS_ListEmpty(&g_losFreeTask)) { 
  20.         retVal = LOS_ERRNO_TSK_TCB_UNAVAILABLE; 
  21.         OS_GOTO_ERREND(); 
  22.     } 
  23.  
  24. ⑷  taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_losFreeTask)); 
  25.     LOS_ListDelete(LOS_DL_LIST_FIRST(&g_losFreeTask)); 
  26.  
  27.     LOS_IntRestore(intSave); 
  28.  
  29. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  30.     UINTPTR stackPtr = (UINTPTR)LOS_MemAllocAlign(OS_TASK_STACK_ADDR, taskInitParam->uwStackSize + 
  31.         OS_TASK_STACK_PROTECT_SIZE, OS_TASK_STACK_PROTECT_SIZE); 
  32.     topOfStack = (VOID *)(stackPtr + OS_TASK_STACK_PROTECT_SIZE); 
  33. #else 
  34. ⑸      topOfStack = (VOID *)LOS_MemAllocAlign(OS_TASK_STACK_ADDR, taskInitParam->uwStackSize, 
  35.         LOSCFG_STACK_POINT_ALIGN_SIZE); 
  36. #endif 
  37. ⑹  if (topOfStack == NULL) { 
  38.         intSave = LOS_IntLock(); 
  39.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  40.         LOS_IntRestore(intSave); 
  41.         return LOS_ERRNO_TSK_NO_MEMORY; 
  42.     } 
  43.  
  44. ⑺  retVal = OsNewTaskInit(taskCB, taskInitParam, topOfStack); 
  45.     if (retVal != LOS_OK) { 
  46.         return retVal; 
  47.     } 
  48.  
  49.     *taskID = taskCB->taskID; 
  50.     OsHookCall(LOS_HOOK_TYPE_TASK_CREATE, taskCB); 
  51.     return retVal; 
  52.  
  53. LOS_ERREND: 
  54.     LOS_IntRestore(intSave); 
  55.     return retVal; 

 我們看下創建任務函數調用的函數OsRecyleFinishedTask(),該函數在系統進入空閑時也會調用。刪除運行狀態的任務時,會把任務掛在雙向鏈表里g_taskRecyleList。任務回收函數就用來回收此類任務,實現任務資源回收。我們分析下它的代碼。⑴處循環遍歷回收鏈表,⑵從回收鏈表獲取第一個任務taskCB,從回收鏈表刪除并插入到空閑任務鏈表里。任務棧保護在后續系列再深入分析,繼續往下看代碼,⑶處獲取任務棧棧頂指針,接著調用內存釋放函數來釋放任務棧占用的內存,并設置任務棧的棧頂為空。

  1. STATIC VOID OsRecyleFinishedTask(VOID) 
  2.     LosTaskCB *taskCB = NULL
  3.     UINTPTR intSave; 
  4.     UINTPTR stackPtr; 
  5.  
  6.     intSave = LOS_IntLock(); 
  7. ⑴  while (!LOS_ListEmpty(&g_taskRecyleList)) { 
  8. ⑵      taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_taskRecyleList)); 
  9.         LOS_ListDelete(LOS_DL_LIST_FIRST(&g_taskRecyleList)); 
  10.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  11. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  12.         stackPtr = taskCB->topOfStack - OS_TASK_STACK_PROTECT_SIZE; 
  13. #else 
  14. ⑶      stackPtr = taskCB->topOfStack; 
  15. #endif 
  16.         (VOID)LOS_MemFree(OS_TASK_STACK_ADDR, (VOID *)stackPtr); 
  17.         taskCB->topOfStack = (UINT32)NULL
  18.     } 
  19.     LOS_IntRestore(intSave); 

 我們繼續分析下函數OsNewTaskInit(),⑴處調用函數初始化任務棧,上一系列已經分析過該函數,代碼的其余部分用來更新任務控制塊的成員信息,比如⑵處任務狀態設置為阻塞狀態。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsNewTaskInit(LosTaskCB *taskCB, TSK_INIT_PARAM_S *taskInitParam, VOID *topOfStack) 
  2. ⑴  taskCB->stackPointer    = HalTskStackInit(taskCB->taskID, taskInitParam->uwStackSize, topOfStack); 
  3.     taskCB->arg             = taskInitParam->uwArg; 
  4.     taskCB->topOfStack      = (UINT32)(UINTPTR)topOfStack; 
  5.     taskCB->stackSize       = taskInitParam->uwStackSize; 
  6.     taskCB->taskSem         = NULL
  7.     taskCB->taskMux         = NULL
  8. ⑵  taskCB->taskStatus      = OS_TASK_STATUS_SUSPEND; 
  9.     taskCB->priority        = taskInitParam->usTaskPrio; 
  10.     taskCB->timeSlice       = 0; 
  11.     taskCB->waitTimes       = 0; 
  12.     taskCB->taskEntry       = taskInitParam->pfnTaskEntry; 
  13.     taskCB->event.uwEventID = OS_NULL_INT; 
  14.     taskCB->eventMask       = 0; 
  15.     taskCB->taskName        = taskInitParam->pcName; 
  16.     taskCB->msg             = NULL
  17.     SET_SORTLIST_VALUE(&taskCB->sortList, OS_SORT_LINK_INVALID_TIME); 
  18.     return LOS_OK; 

 3.1.2 刪除任務UINT32 LOS_TaskDelete()

該函數根據傳入的參數UINT32 taskId刪除任務。我們分析下刪除任務的源代碼,⑴處檢驗傳入的參數,⑵處如果任務還未創建,返回錯誤碼。⑶處如果刪除的任務正在運行,又處于鎖任務調度情況下,打印信息,告訴用戶不推薦在鎖任務調度期間進行任務刪除,然后執行⑷,把全局變量賦值0來解鎖任務調度。

⑸處調用函數處理任務狀態,如果處于就緒狀態設置為非就緒狀態,并從就緒隊列刪除。如果處于阻塞狀態,從阻塞隊列中刪除。如果任務處于超時等待狀態,從超時排序鏈表中刪除。⑹恢復任務控制塊事件相關的成員信息。⑺如果任務正在運行,設置任務為未使用狀態,接著調用函數OsRunningTaskDelete()把任務放入回收鏈表,然后主動觸發任務調度,稍后詳細分析該函數。如果刪除的任務不是出于運行狀態,則執行⑻,設置任務為未使用狀態,接著把任務回收到空閑任務鏈表里,然后獲取任務棧的棧頂指針,調用內存釋放函數釋放任務棧的內存。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID); 
  4.     UINTPTR stackPtr; 
  5.  
  6. ⑴  UINT32 ret = OsCheckTaskIDValid(taskID); 
  7.     if (ret != LOS_OK) { 
  8.         return ret; 
  9.     } 
  10.  
  11.     intSave = LOS_IntLock(); 
  12.  
  13. ⑵  if ((taskCB->taskStatus) & OS_TASK_STATUS_UNUSED) { 
  14.         LOS_IntRestore(intSave); 
  15.         return LOS_ERRNO_TSK_NOT_CREATED; 
  16.     } 
  17.  
  18.     /* If the task is running and scheduler is locked then you can not delete it */ 
  19. ⑶  if (((taskCB->taskStatus) & OS_TASK_STATUS_RUNNING) && (g_losTaskLock != 0)) { 
  20.         PRINT_INFO("In case of task lock, task deletion is not recommended\n"); 
  21. ⑷      g_losTaskLock = 0; 
  22.     } 
  23.  
  24.     OsHookCall(LOS_HOOK_TYPE_TASK_DELETE, taskCB); 
  25. ⑸  OsSchedTaskExit(taskCB); 
  26.  
  27. ⑹  taskCB->event.uwEventID = OS_NULL_INT; 
  28.     taskCB->eventMask = 0; 
  29. #if (LOSCFG_BASE_CORE_CPUP == 1) 
  30.     // Ignore the return code when matching CSEC rule 6.6(4). 
  31.     (VOID)memset_s((VOID *)&g_cpup[taskCB->taskID], sizeof(OsCpupCB), 0, sizeof(OsCpupCB)); 
  32. #endif 
  33.     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { 
  34. ⑺      taskCB->taskStatus = OS_TASK_STATUS_UNUSED; 
  35.         OsRunningTaskDelete(taskID, taskCB); 
  36.         LOS_IntRestore(intSave); 
  37.         LOS_Schedule(); 
  38.         return LOS_OK; 
  39.     } else { 
  40. ⑻       taskCB->taskStatus = OS_TASK_STATUS_UNUSED; 
  41.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  42. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  43.         stackPtr = taskCB->topOfStack - OS_TASK_STACK_PROTECT_SIZE; 
  44. #else 
  45.         stackPtr = taskCB->topOfStack; 
  46. #endif 
  47.         (VOID)LOS_MemFree(OS_TASK_STACK_ADDR, (VOID *)stackPtr); 
  48.         taskCB->topOfStack = (UINT32)NULL
  49.     } 
  50.  
  51.     LOS_IntRestore(intSave); 
  52.     return LOS_OK; 

 我們看下函數OsRunningTaskDelete()的源碼。⑴處把當前運行的任務放入待回收鏈表里,然后執行⑵把當前運行的任務放入任務池的最后一個位置g_taskCBArray[g_taskMaxNum]。為什么這么操作呢?等后續分析源碼的時候再來解答。

  1. LITE_OS_SEC_TEXT_INIT STATIC_INLINE VOID OsRunningTaskDelete(UINT32 taskID, LosTaskCB *taskCB) 
  2. ⑴  LOS_ListTailInsert(&g_taskRecyleList, &taskCB->pendList); 
  3. ⑵  g_losTask.runTask = &g_taskCBArray[g_taskMaxNum]; 
  4.     g_losTask.runTask->taskID = taskID; 
  5.     g_losTask.runTask->taskStatus = taskCB->taskStatus | OS_TASK_STATUS_RUNNING; 
  6.     g_losTask.runTask->topOfStack = taskCB->topOfStack; 
  7.     g_losTask.runTask->taskName = taskCB->taskName; 

 3.2 控制任務狀態

3.2.1 恢復掛起的任務LOS_TaskResume()

恢復掛起的任務,使該任務進入就緒狀態,和下文中的LOS_TaskSuspend()成對使用。⑴處獲取任務的TCB,⑵處對任務狀態進行判斷,如果任務未創建或者非阻塞狀態,則返回錯誤碼。執行⑶設置任務狀態為非掛起狀態。⑶處獲取任務的狀態進行判斷,如果任務沒有創建或者不是掛起狀態,則返回相應的錯誤碼。 ⑷檢查任務狀態是否為OS_CHECK_TASK_BLOCK,即(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND | OS_TASK_STATUS_SUSPEND)中的一種,這幾個狀態影響恢復掛起的任務。如果非上述幾個狀態,執行⑸調用函數,把任務狀態改為就緒狀態,插入任務就緒隊列。如果支持支持調度,則執行⑹觸發調度。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 tempStatus; 
  5.     UINT32 retErr = OS_ERROR; 
  6.  
  7.     if (taskID > LOSCFG_BASE_CORE_TSK_LIMIT) { 
  8.         return LOS_ERRNO_TSK_ID_INVALID; 
  9.     } 
  10.  
  11. ⑴  taskCB = OS_TCB_FROM_TID(taskID); 
  12.     intSave = LOS_IntLock(); 
  13.     tempStatus = taskCB->taskStatus; 
  14.  
  15. ⑵  if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  16.         retErr = LOS_ERRNO_TSK_NOT_CREATED; 
  17.         OS_GOTO_ERREND(); 
  18.     } else if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) { 
  19.         retErr = LOS_ERRNO_TSK_NOT_SUSPENDED; 
  20.         OS_GOTO_ERREND(); 
  21.     } 
  22.  
  23. ⑶  taskCB->taskStatus &= (~OS_TASK_STATUS_SUSPEND); 
  24. ⑷  if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) { 
  25. ⑸      OsSchedTaskEnQueue(taskCB); 
  26.         if (g_taskScheduled) { 
  27.             LOS_IntRestore(intSave); 
  28. ⑹          LOS_Schedule(); 
  29.             return LOS_OK; 
  30.         } 
  31.     } 
  32.  
  33.     LOS_IntRestore(intSave); 
  34.     return LOS_OK; 
  35.  
  36. LOS_ERREND: 
  37.     LOS_IntRestore(intSave); 
  38.     return retErr; 

 3.2.2 掛起指定的任務LOS_TaskSuspend()

函數用于掛起指定的任務。⑴處獲取任務的TCB,⑵處開始獲取任務的狀態進行判斷,如果任務沒有創建、任務已經掛起,返回相應的錯誤碼。⑶處如果任務是運行狀態,并且鎖任務調度時,跳轉到LOS_ERREND結束掛起操作。⑷處如果任務是就緒狀態,調用函數從就緒隊列出隊,并取消任務的就緒狀態。⑸處語句設置任務狀態為阻塞狀態。⑹如果掛起的是當前運行的任務,則會主動觸發調度。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 tempStatus; 
  5.     UINT32 retErr; 
  6.  
  7.     retErr = OsCheckTaskIDValid(taskID); 
  8.     if (retErr != LOS_OK) { 
  9.         return retErr; 
  10.     } 
  11.  
  12. ⑴  taskCB = OS_TCB_FROM_TID(taskID); 
  13.     intSave = LOS_IntLock(); 
  14. ⑵  tempStatus = taskCB->taskStatus; 
  15.     if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  16.         retErr = LOS_ERRNO_TSK_NOT_CREATED; 
  17.         OS_GOTO_ERREND(); 
  18.     } 
  19.  
  20.     if (tempStatus & OS_TASK_STATUS_SUSPEND) { 
  21.         retErr = LOS_ERRNO_TSK_ALREADY_SUSPENDED; 
  22.         OS_GOTO_ERREND(); 
  23.     } 
  24.  
  25. ⑶  if ((tempStatus & OS_TASK_STATUS_RUNNING) && (g_losTaskLock != 0)) { 
  26.         retErr = LOS_ERRNO_TSK_SUSPEND_LOCKED; 
  27.         OS_GOTO_ERREND(); 
  28.     } 
  29.  
  30. ⑷  if (tempStatus & OS_TASK_STATUS_READY) { 
  31.         OsSchedTaskDeQueue(taskCB); 
  32.     } 
  33.  
  34. ⑸  taskCB->taskStatus |= OS_TASK_STATUS_SUSPEND; 
  35.     OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB); 
  36. ⑹  if (taskID == g_losTask.runTask->taskID) { 
  37.         LOS_IntRestore(intSave); 
  38.         LOS_Schedule(); 
  39.         return LOS_OK; 
  40.     } 
  41.  
  42.     LOS_IntRestore(intSave); 
  43.     return LOS_OK; 
  44.  
  45. LOS_ERREND: 
  46.     LOS_IntRestore(intSave); 
  47.     return retErr; 

 3.2.3 任務延時等待LOS_TaskDelay()

任務延時等待,釋放CPU,等待時間到期后該任務會重新進入就緒狀態。

⑴處代碼判斷系統處于中斷,如果是,則返回錯誤碼,不允許任務延時等待。

⑵如果處于鎖任務調度期間,則返回錯誤碼。

⑶處如果延遲的時間為0,則執行讓權操作,否則執行。

⑷調用函數OsSchedDelay()把當前任務設置為延時等待狀態,然后調用LOS_Schedule()觸發調度。

  1. LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick) 
  2.     UINTPTR intSave; 
  3.  
  4. ⑴  if (OS_INT_ACTIVE) { 
  5.         return LOS_ERRNO_TSK_DELAY_IN_INT; 
  6.     } 
  7.  
  8. ⑵  if (g_losTaskLock != 0) { 
  9.         return LOS_ERRNO_TSK_DELAY_IN_LOCK; 
  10.     } 
  11.  
  12.     OsHookCall(LOS_HOOK_TYPE_TASK_DELAY, tick); 
  13. ⑶  if (tick == 0) { 
  14.         return LOS_TaskYield(); 
  15.     } else { 
  16.         intSave = LOS_IntLock(); 
  17. ⑷      OsSchedDelay(g_losTask.runTask, tick); 
  18.         OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTODELAYEDLIST, g_losTask.runTask); 
  19.         LOS_IntRestore(intSave); 
  20.         LOS_Schedule(); 
  21.     } 
  22.  
  23.     return LOS_OK; 

 另外還提供了函數LOS_Msleep()和LOS_UDelay(),前者以毫秒為單位進行延遲等待。后者也是以毫秒為單位進行延遲等待,但是不會觸發任務調度,當前任務不會釋放CPU。

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_Msleep(UINT32 mSecs) 
  2.     UINT32 interval; 
  3.  
  4.     if (OS_INT_ACTIVE) { 
  5.         return
  6.     } 
  7.  
  8.     if (mSecs == 0) { 
  9.         interval = 0; 
  10.     } else { 
  11.         interval = LOS_MS2Tick(mSecs); 
  12.         if (interval == 0) { 
  13.             interval = 1; 
  14.         } 
  15.     } 
  16.  
  17.     (VOID)LOS_TaskDelay(interval); 
  18.  
  19. VOID LOS_UDelay(UINT64 microseconds) 
  20.     UINT64 endTime; 
  21.  
  22.     if (microseconds == 0) { 
  23.         return
  24.     } 
  25.  
  26.     endTime = (microseconds / OS_SYS_US_PER_SECOND) * OS_SYS_CLOCK + 
  27.             (microseconds % OS_SYS_US_PER_SECOND) * OS_SYS_CLOCK / OS_SYS_US_PER_SECOND; 
  28.     endTime = LOS_SysCycleGet() + endTime; 
  29.     while (LOS_SysCycleGet() < endTime) { 
  30.     } 
  31.  
  32.     return

 3.2.4 任務讓權LOS_TaskYield()

讓權函數通過把當前任務時間片設置為0,釋放CPU占用,重新調度給其他高優先級任務執行。⑴處調用函數把當前任務時間片設置為0,然后執行⑵主動觸發任務調度。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5. ⑴  OsSchedYield(); 
  6.     LOS_IntRestore(intSave); 
  7. ⑵  LOS_Schedule(); 
  8.     return LOS_OK; 

 接下來看下函數OsSchedYield()的源碼。代碼很簡單,獲取當前運行的任務,然后把其時間片設置為0,如下:

  1. VOID OsSchedYield(VOID) 
  2.     LosTaskCB *runTask = g_losTask.runTask; 
  3.  
  4.     runTask->timeSlice = 0; 

 3.3 控制任務調度

3.3.1 鎖任務調度LOS_TaskLock()

鎖任務調度LOS_TaskLock()比較簡單,把任務鎖調度計數器全局變量增加1即可,代碼如下。

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskLock(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5.     g_losTaskLock++; 
  6.     LOS_IntRestore(intSave); 

 3.3.2 解鎖任務調度LOS_TaskUnlock()

我們看看解鎖任務調度函數LOS_TaskUnlock(),⑴處如果任務鎖調度計數器全局變量數值大于0,對其減1。⑵處如果任務鎖調度計數器等于0,則執行⑶處觸發調度。代碼如下:

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskUnlock(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5. ⑴  if (g_losTaskLock > 0) { 
  6.         g_losTaskLock--; 
  7. ⑵      if (g_losTaskLock == 0) { 
  8.             LOS_IntRestore(intSave); 
  9. ⑶          LOS_Schedule(); 
  10.             return
  11.         } 
  12.     } 
  13.  
  14.     LOS_IntRestore(intSave); 

 3.4 控制任務優先級

LiteOS-M內核支持動態設置任務的優先級,提供了一些操作。

3.4.1 設置指定任務的優先級LOS_TaskPriSet

支持設置指定任務Id的優先級,也支持對當前運行任務進行優先級設置。⑴處開始,做些基礎校驗,包含檢驗傳入的優先級參數taskPrio,指定任務的Id,任務是否未創建等,如果沒有通過參數校驗,則返回錯誤碼。⑵處調用函數設置任務優先級,稍后分析該函數。如果任務處于就緒狀態或者運行狀態,則會執行⑶主動觸發任務調度。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskPriSet(UINT32 taskID, UINT16 taskPrio) 
  2.     BOOL isReady = FALSE
  3.     UINTPTR intSave; 
  4.     LosTaskCB *taskCB = NULL
  5.     UINT16 tempStatus; 
  6.  
  7. ⑴  if (taskPrio > OS_TASK_PRIORITY_LOWEST) { 
  8.         return LOS_ERRNO_TSK_PRIOR_ERROR; 
  9.     } 
  10.  
  11.     if (taskID == g_idleTaskID) { 
  12.         return LOS_ERRNO_TSK_OPERATE_IDLE; 
  13.     } 
  14.  
  15.     if (taskID == g_swtmrTaskID) { 
  16.         return LOS_ERRNO_TSK_OPERATE_SWTMR; 
  17.     } 
  18.  
  19.     if (OS_CHECK_TSK_PID_NOIDLE(taskID)) { 
  20.         return LOS_ERRNO_TSK_ID_INVALID; 
  21.     } 
  22.  
  23.     taskCB = OS_TCB_FROM_TID(taskID); 
  24.     intSave = LOS_IntLock(); 
  25.     tempStatus = taskCB->taskStatus; 
  26.     if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  27.         LOS_IntRestore(intSave); 
  28.         return LOS_ERRNO_TSK_NOT_CREATED; 
  29.     } 
  30.  
  31. ⑵  isReady = OsSchedModifyTaskSchedParam(taskCB, taskPrio); 
  32.     LOS_IntRestore(intSave); 
  33.     if (isReady) { 
  34. ⑶      LOS_Schedule(); 
  35.     } 
  36.  
  37.     return LOS_OK; 

 接下來,我們分析下函數OsSchedModifyTaskSchedParam()。⑴處如果任務處于就緒狀態,需要先出隊設置優先級,然后入隊就緒隊列。如果非就緒狀態,可以直接執行⑵處語句修改任務優先級。如果任務正在運行,需要返回TRUE,標記下需要任務調度。

  1. BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 priority) 
  2.     if (taskCB->taskStatus & OS_TASK_STATUS_READY) { 
  3. ⑴      OsSchedTaskDeQueue(taskCB); 
  4.         taskCB->priority = priority; 
  5.         OsSchedTaskEnQueue(taskCB); 
  6.         return TRUE
  7.     } 
  8.  
  9. ⑵  taskCB->priority = priority; 
  10.     OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority); 
  11.     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { 
  12.         return TRUE
  13.     } 
  14.  
  15.     return FALSE

 3.4.2 獲取指定任務的優先級LOS_TaskPriGet

獲取指定任務的優先級LOS_TaskPriGet()代碼比較簡單,⑴處如果任務編號無效,返回錯誤碼。⑵處如果任務未創建返回錯誤碼。如果參數校驗通過,執行⑶獲取任務的優先級數值。

  1. LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 priority; 
  5.  
  6. ⑴  if (OS_CHECK_TSK_PID_NOIDLE(taskID)) { 
  7.         return (UINT16)OS_INVALID; 
  8.     } 
  9.  
  10.     taskCB = OS_TCB_FROM_TID(taskID); 
  11.  
  12.     intSave = LOS_IntLock(); 
  13.  
  14. ⑵  if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { 
  15.         LOS_IntRestore(intSave); 
  16.         return (UINT16)OS_INVALID; 
  17.     } 
  18.  
  19. ⑶  priority = taskCB->priority; 
  20.     LOS_IntRestore(intSave); 
  21.     return priority; 

 3.5 任務阻塞和喚醒

最后,我們分析下函數OsSchedTaskWait()和OsSchedTaskWake(),這2個函數定義在文件kernel\src\los_sched.c中。任務在申請互斥鎖、信號量、出入隊列、讀寫事件時,都可能導致任務進入阻塞狀態,對應地也需要任務喚醒重新進入就緒隊列狀態。這2個函數就負責任務的阻塞和喚醒,我們分析下他們的代碼。

3.5.1 任務阻塞

我們分析下任務阻塞的函數OsSchedTaskWait(),需要2個參數:LOS_DL_LIST *list是互斥鎖等資源的阻塞鏈表,阻塞的任務會掛這個鏈表里;UINT32 ticks是任務阻塞的時間。分析下具體代碼:

⑴獲取正在請求互斥鎖等資源的當前任務,⑵設置任務狀態為阻塞狀態。⑶把任務插入互斥鎖等資源的阻塞鏈表的尾部。⑷如果不是永久阻塞等待,任務的狀態還需要設置為:

  1. VOID OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks) 
  2. ⑴  LosTaskCB *runTask = g_losTask.runTask; 
  3.  
  4. ⑵  runTask->taskStatus |= OS_TASK_STATUS_PEND; 
  5. ⑶  LOS_ListTailInsert(list, &runTask->pendList); 
  6.  
  7.     if (ticks != LOS_WAIT_FOREVER) { 
  8. ⑷      runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME; 
  9.         runTask->waitTimes = ticks; 
  10.     } 

 3.5.2 任務喚醒

我們分析下任務喚醒的函數OsSchedTaskWake(),需要1個參數:LosTaskCB *resumedTask是需要喚醒的任務;任務喚醒函數會從阻塞鏈表里刪除并加入就緒隊列,下面分析下具體代碼:

⑴把要喚醒的任務從所在的阻塞隊列中刪除,然后更改狀態不再為阻塞狀態。⑵如果任務不是永久等待,需要從定時器排序鏈表中刪除,并設置狀態不再是等待超時。⑶如果任務是阻塞狀態,改為就緒狀態并加入就緒隊列。

  1. VOID OsSchedTaskWake(LosTaskCB *resumedTask) 
  2. ⑴  LOS_ListDelete(&resumedTask->pendList); 
  3.     resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND; 
  4.  
  5. ⑵  if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) { 
  6.         OsDeleteSortLink(&resumedTask->sortList, OS_SORT_LINK_TASK); 
  7.         resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME; 
  8.     } 
  9.  
  10. ⑶  if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPEND)) { 
  11.         OsSchedTaskEnQueue(resumedTask); 
  12.     } 

 小結

本文帶領大家一起剖析了鴻蒙輕內核任務模塊的源代碼,包含任務模塊的結構體,任務初始化過程源代碼,任務常用操作的源代碼。后續也會陸續推出更多的分享文章,敬請期待。

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2021-05-20 09:50:20

鴻蒙HarmonyOS應用

2021-05-13 09:47:08

鴻蒙HarmonyOS應用

2021-05-12 09:45:20

鴻蒙HarmonyOS應用

2021-05-10 15:05:56

鴻蒙HarmonyOS應用

2022-01-10 15:31:44

鴻蒙HarmonyOS應用

2022-01-12 10:50:23

鴻蒙HarmonyOS應用

2021-06-04 09:57:49

鴻蒙HarmonyOS應用

2024-10-25 09:26:56

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-06-04 14:15:10

鴻蒙HarmonyOS應用

2021-05-08 15:14:50

鴻蒙HarmonyOS應用

2021-05-25 09:28:34

鴻蒙HarmonyOS應用

2021-10-20 16:08:57

鴻蒙HarmonyOS應用

2021-05-31 20:30:55

鴻蒙HarmonyOS應用

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-03 18:28:28

Harmony進程任務管理模塊

2021-07-06 09:45:03

鴻蒙HarmonyOS應用

2021-09-22 14:36:32

鴻蒙HarmonyOS應用

2021-05-11 09:54:55

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文在线a在线 | 8x国产精品视频一区二区 | 久草资源在线视频 | 黄色免费观看 | 欧美激情a∨在线视频播放 成人免费共享视频 | 超碰在线网站 | 999re5这里只有精品 | 日韩精品av一区二区三区 | 天天干,夜夜操 | 波多野结衣一区二区 | a级大毛片 | 国产色爽 | 成人二区 | 99国产精品视频免费观看一公开 | 国产精品久久久久久久久久久久久 | 欧美激情一区二区 | 欧美在线一区视频 | 中文字幕日韩av | 午夜寂寞影院在线观看 | 日韩免费一级 | 国产乱码精品一品二品 | 波多野结衣精品 | 不卡一区 | 男人的天堂一级片 | 精品欧美一区免费观看α√ | 亚洲精品乱码 | 日韩av在线免费 | 男女激情网| 蜜桃视频在线观看免费视频网站www | 午夜在线 | av日韩在线播放 | 色综合久| 欧美一区在线视频 | 日韩精品免费在线 | 爱高潮www亚洲精品 中文字幕免费视频 | 国产精品久久久久久久久久三级 | 午夜无码国产理论在线 | 国产精品成人一区二区 | 一级毛片观看 | 天天干成人网 | 熟女毛片 |