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

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

開發
文章由鴻蒙社區產出,想要了解更多內容請前往:51CTO和華為官方戰略合作共建的鴻蒙技術社區https://harmonyos.51cto.com

[[400426]]

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

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

https://harmonyos.51cto.com

調度,Schedule也稱為Dispatch,是操作系統的一個重要模塊,它負責選擇系統要處理的下一個任務。調度模塊需要協調處于就緒狀態的任務對資源的競爭,按優先級策略從就緒隊列中獲取高優先級的任務,給予資源使用權。

下面,我們剖析下任務調度模塊的源代碼,若涉及開發板部分,以開發板工程targets\cortex-m7_nucleo_f767zi_gcc\為例進行源碼分析。

1、調度模塊的重要函數

文件kernel\src\los_sched.c中定義了調度模塊的幾個重要的函數,我們來分析下源碼。

1.1 調度初始化函數

調度初始化函數UINT32 OsSchedInit(VOID)在任務初始化函數UINT32 OsTaskInit(VOID)中調用。⑴處會初始化任務就緒隊列,⑵處初始化任務排序鏈表,⑶處初始化調度響應時間全局變量為最大值OS_SCHED_MAX_RESPONSE_TIME。

  1. UINT32 OsSchedInit(VOID) 
  2.     UINT16 pri; 
  3. ⑴  for (pri = 0; pri < OS_PRIORITY_QUEUE_NUM; pri++) { 
  4.         LOS_ListInit(&g_priQueueList[pri]); 
  5.     } 
  6.     g_queueBitmap = 0; 
  7.  
  8. ⑵  g_taskSortLinkList = OsGetSortLinkAttribute(OS_SORT_LINK_TASK); 
  9.     if (g_taskSortLinkList == NULL) { 
  10.         return LOS_NOK; 
  11.     } 
  12.  
  13.     OsSortLinkInit(g_taskSortLinkList); 
  14. ⑶  g_schedResponseTime = OS_SCHED_MAX_RESPONSE_TIME; 
  15.  
  16.     return LOS_OK; 

 1.2 任務調度函數

任務調度函數VOID LOS_Schedule(VOID)是出鏡率較高的一個函數。當系統完成初始化開始調度,并且沒有鎖任務調度時,會調用函數HalTaskSchedule()進行任務調度。該函數定義在kernel\arch\arm\cortex-m7\gcc\los_dispatch.S,由匯編語言實現,后文會詳細分析。

  1. VOID LOS_Schedule(VOID) 
  2.     if (g_taskScheduled && LOS_CHECK_SCHEDULE) { 
  3.         HalTaskSchedule(); 
  4.     } 

 1.3 開啟調度函數

函數VOID OsSchedStart(VOID)被kernel\src\los_init.c:UINT32 LOS_Start(VOID)-->kernel\arch\arm\cortex-m7\gcc\los_context.c:UINT32 HalStartSchedule(OS_TICK_HANDLER handler)函數依次調用,在系統初始化時開啟任務調度。我們看下該函數的源碼,⑴處調用函數獲取就緒隊列中優先級最高的任務,⑵把該任務狀態設置為運行狀態,接著把當前運行任務和新任務都設置為就緒隊列中優先級最高的那個任務。⑶處設置任務調度啟動狀態全局變量為1,標記任務調度已經開啟。⑷處設置新任務的開始運行時間,然后把新任務從就緒隊列中出隊。⑸處設置全局變量。⑹處調用函數設置該任務的運行過期時間。

  1. VOID OsSchedStart(VOID) 
  2.     (VOID)LOS_IntLock(); 
  3. ⑴  LosTaskCB *newTask = OsGetTopTask(); 
  4.  
  5. ⑵  newTask->taskStatus |= OS_TASK_STATUS_RUNNING; 
  6.     g_losTask.newTask = newTask; 
  7.     g_losTask.runTask = g_losTask.newTask; 
  8.  
  9. ⑶  g_taskScheduled = 1; 
  10. ⑷  newTask->startTime = OsGetCurrSchedTimeCycle(); 
  11.     OsSchedTaskDeQueue(newTask); 
  12.  
  13. ⑸  g_schedResponseTime = OS_SCHED_MAX_RESPONSE_TIME; 
  14.     g_schedResponseID = OS_INVALID; 
  15. ⑹  OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, newTask->startTime + newTask->timeSlice); 
  16.  
  17.     PRINTK("Entering scheduler\n"); 

 1.4 任務調度切換函數

任務切換函數用于實現任務切換,被文件kernel\arch\arm\cortex-m7\gcc\los_dispatch.S中的匯編函數HalPendSV調用。我們分析下該函數的源代碼。

⑴處獲取當前運行的任務,然后調用函數減去其運行的時間片,開始運行時間設置為當前時間。⑵如果任務處于阻塞等待狀態或延遲狀態,則把其加入任務排序鏈表。⑶如果任務不是處于阻塞掛起狀態、不是處于阻塞狀態,則把其加入就緒隊列。⑷處獲取就緒隊列中優先級最高的任務,⑸處如果當前運行任務和就緒隊列匯總優先級最高的任務不是同一個任務,把當前任務狀態設置為非運行狀態,新任務設置為運行狀態,并設置新任務的開始時間為當前任務的開始時間,然后執行⑹標記是否需要任務切換。⑺處把新任務從就緒隊列中出隊,⑻處計算新任務的運行結束時間,然后執行⑼設置任務到期時間。

  1. BOOL OsSchedTaskSwitch(VOID) 
  2.     UINT64 endTime; 
  3.     BOOL isTaskSwitch = FALSE
  4.  ⑴ LosTaskCB *runTask = g_losTask.runTask; 
  5.     OsTimeSliceUpdate(runTask, OsGetCurrSchedTimeCycle()); 
  6.  
  7. ⑵  if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) { 
  8.         OsAdd2SortLink(&runTask->sortList, runTask->startTime, runTask->waitTimes, OS_SORT_LINK_TASK); 
  9.     } else if (!(runTask->taskStatus & (OS_TASK_STATUS_PEND | OS_TASK_STATUS_SUSPEND | OS_TASK_STATUS_UNUSED))) { 
  10. ⑶      OsSchedTaskEnQueue(runTask); 
  11.     } 
  12.  
  13. ⑷  LosTaskCB *newTask = OsGetTopTask(); 
  14.     g_losTask.newTask = newTask; 
  15.  
  16.     if (runTask != newTask) { 
  17. #if (LOSCFG_BASE_CORE_TSK_MONITOR == 1) 
  18.         OsTaskSwitchCheck(); 
  19. #endif 
  20. ⑸      runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING; 
  21.         newTask->taskStatus |= OS_TASK_STATUS_RUNNING; 
  22.         newTask->startTime = runTask->startTime; 
  23. ⑹      isTaskSwitch = TRUE
  24.  
  25.         OsHookCall(LOS_HOOK_TYPE_TASK_SWITCHEDIN); 
  26.     } 
  27.  
  28. ⑺  OsSchedTaskDeQueue(newTask); 
  29.  
  30. ⑻  if (newTask->taskID != g_idleTaskID) { 
  31.         endTime = newTask->startTime + newTask->timeSlice; 
  32.     } else { 
  33.         endTime = OS_SCHED_MAX_RESPONSE_TIME; 
  34.     } 
  35. ⑼   OsSchedSetNextExpireTime(newTask->startTime, newTask->taskID, endTime); 
  36.  
  37.     return isTaskSwitch; 

 2、調度模塊匯編函數

文件kernel\arch\arm\cortex-m7\gcc\los_dispatch.S定義了調度模塊的匯編函數,我們分析下這些調度接口的源代碼。匯編文件中定義了如下幾個宏,見注釋。

  1. .equ OS_NVIC_INT_CTRL,           0xE000ED04     ; Interrupt Control State Register,ICSR 中斷控制狀態寄存器 
  2. .equ OS_NVIC_SYSPRI2,            0xE000ED20     ; System Handler Priority Register 系統優先級寄存器 
  3. .equ OS_NVIC_PENDSV_PRI,         0xF0F00000     ; PendSV異常優先級 
  4. .equ OS_NVIC_PENDSVSET,          0x10000000     ; ICSR寄存器的PENDSVSET位置1時,會觸發PendSV異常 
  5. .equ OS_TASK_STATUS_RUNNING,     0x0010         ; los_task.h中的同名宏定義,數值也一樣,表示任務運行狀態, 

 2.1 HalStartToRun匯編函數

開始運行函數HalStartToRun被文件kernel\arch\arm\cortex-m7\gcc\los_context.c中的開始調度函數HalStartSchedule在系統啟動階段調用。我們接下來分析下該函數的匯編代碼。

⑴處設置PendSV異常優先級為OS_NVIC_PENDSV_PRI,PendSV異常一般設置為最低。⑵處往控制寄存器CONTROL寫入二進制的10,表示使用PSP棧,特權級的線程模式。⑶處把全局變量地址加載到寄存器r1。因為UINT16 taskStatus是LosTaskCB結構體的第二個成員變量,⑷處[r1 , #4]把地址加4個字節來獲取當前運行任務的狀態,此時寄存器r0數值為0x4,即就緒狀態OS_TASK_STATUS_READY。

⑸處把[r0]的值即任務的棧指針taskCB->stackPointer加載到寄存器R12,現在R12指向任務棧的棧指針,任務棧現在保存的是上下文,對應定義在kernel\arch\arm\cortex-m7\gcc\los_arch_context.h中的結構體TaskContext。如果支持浮點寄存器,則執行⑹,把R12加100個字節,其中包含S16到S31共16個4字節,R4到R11及uwPriMask共9個4字節的長度,執行指令后,R12指向任務棧中上下文的UINT32 uwR0位置。

⑺處代碼把任務棧上下文中的UINT32 uwR0-uwR3, UINT32 uwR12; UINT32 uwLR; UINT32 uwPC; UINT32 uwxPSR;共8個成員變量數值分別加載到寄存器R0-R7,其中R5對應UINT32 uwLR,R6對應UINT32 uwPC,此時寄存器R12指向任務棧上下文的UINT32 uwxPSR。然后執行下一個指令,指針繼續加72字節(=18個4字節長度),即對應S0到S15及UINT32 FPSCR; UINT32 NO_NAME等上下文的18個成員。此時,寄存器R12指向任務棧的棧底,緊接著執行⑻把寄存器R12寫入寄存器psp。

如果不支持浮點寄存器,則執行⑼,從棧指針加36字節,然后寄存器R12指向任務棧中上下文的UINT32 uwR0位置。接著把上下文中的寄存器信息加載到寄存器R0-R7,緊接著把寄存器R12寫入寄存器psp。

最后,執行⑽處指令,把寄存器R5寫入lr寄存器,開中斷,然后跳轉到R6對應的上下文的PC對應的函數VOID OsTaskEntry(UINT32 taskID),去執行任務的入口函數。

  1.     .type HalStartToRun, %function 
  2.     .global HalStartToRun 
  3. HalStartToRun: 
  4.     .fnstart 
  5.     .cantunwind 
  6.  
  7. ⑴  ldr     r4, =OS_NVIC_SYSPRI2 
  8.     ldr     r5, =OS_NVIC_PENDSV_PRI 
  9.     str     r5, [r4] 
  10.  
  11. ⑵  mov     r0, #2 
  12.     msr     CONTROL, r0 
  13.  
  14. ⑶  ldr     r1, =g_losTask 
  15. ⑷  ldr     r0, [r1, #4] 
  16. ⑸  ldr     r12, [r0] 
  17. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  18.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  19. ⑹  add     r12, r12, #100 
  20.  
  21. ⑺  ldmfd   r12!, {r0-r7} 
  22.     add     r12, r12, #72 
  23. ⑻  msr     psp, r12 
  24.     vpush   {S0} 
  25.     vpop    {S0} 
  26. #else 
  27. ⑼  add     r12, r12, #36 
  28.  
  29.     ldmfd   r12!, {r0-r7} 
  30.     msr     psp, r12 
  31. #endif 
  32. ⑽   mov     lr, r5 
  33.     //MSR     xPSR, R7 
  34.  
  35.     cpsie   I 
  36.     bx      r6 
  37.  
  38.     .fnend 

 2.2 OsTaskSchedule匯編函數

匯編函數HalTaskSchedule實現新老任務的切換調度。從上文可以知道,被任務調度函數VOID LOS_Schedule(VOID)調用。我們看看這個匯編函數的源代碼,首先往中斷控制狀態寄存器OS_NVIC_INT_CTRL中的OS_NVIC_PENDSVSET位置1,觸發PendSV異常。執行完畢HalTaskSchedule函數,返回上層調用函數。PendSV異常的回調函數是HalPendSV匯編函數,下文會分析此函數。匯編函數HalTaskSchedule如下:

  1.     .type HalTaskSchedule, %function 
  2.     .global HalTaskSchedule 
  3. HalTaskSchedule: 
  4.     .fnstart 
  5.     .cantunwind 
  6.  
  7.     ldr     r0, =OS_NVIC_INT_CTRL 
  8.     ldr     r1, =OS_NVIC_PENDSVSET 
  9.     str     r1, [r0] 
  10.     dsb 
  11.     isb 
  12.     bx      lr 
  13.    .fnend 

 3.4 HalPendSV匯編函數

接下來,我們分析下HalPendSV匯編函數的源代碼。⑴處把寄存器PRIMASK數值寫入寄存器r12,備份中斷的開關狀態,然后執行指令cpsid I屏蔽全局中斷。⑵處把寄存器r12、lr入棧,然后調用上文分析過的任務切換函數OsSchedTaskSwitch。函數執行完畢,執行⑶處指令出棧,恢復寄存器r12、lr數值。⑷處比較寄存器r0即任務切換函數OsSchedTaskSwitch的返回值與0,然后執行⑸使用r0寄存器保存lr寄存器的值,如果⑷處的比較不相等,則執行⑹跳轉到標簽TaskContextSwitch進行任務上下文切換。⑺處恢復中斷狀態,然后返回。

我們來看下需要任務上下文切換的情況,接著看標簽TaskContextSwitch。⑻處從r0寄存器恢復lr寄存器的值。⑼處使用r0寄存器指示棧指針,然后把寄存器r4-r12的數值壓入當前任務棧。如果支持浮點寄存器,還需要執行⑽,把寄存器d8-d15的數值壓入當前任務棧,r0為任務棧指針。

⑾處指令把全局變量g_losTask地址加載到寄存器r5,⑿獲取當前運行任務的棧指針,然后更新當前運行任務的棧指針。⒀處指令獲取新任務newTask的地址,接著的指令把新任務地址賦值給當前運行任務,即runTask = newTask。⒁處指令把r1寄存器表示新任務的棧指針。如果支持浮點,⒂指令把新任務棧中的數據加載到寄存器d8-d15寄存器,繼續執行后續指令繼續加載數據到r4-r12寄存器,然后執行⒃處指令更新psp任務棧指針。⒄處指令恢復中斷狀態,然后執行跳轉指令,后續繼續執行C代碼VOID OsTaskEntry(UINT32 taskId)進入任務執行入口函數。

  1.   .type HalPendSV, %function 
  2.     .global HalPendSV 
  3. HalPendSV: 
  4.     .fnstart 
  5.     .cantunwind 
  6.  
  7. ⑴  mrs     r12, PRIMASK 
  8.     cpsid   I 
  9.  
  10. HalTaskSwitch: 
  11. ⑵  push    {r12, lr} 
  12.     blx     OsSchedTaskSwitch 
  13. ⑶  pop     {r12, lr} 
  14. ⑷  cmp     r0, #0 
  15. ⑸  mov     r0, lr 
  16. ⑹  bne     TaskContextSwitch 
  17. ⑺  msr     PRIMASK, r12 
  18.     bx      lr 
  19.  
  20. TaskContextSwitch: 
  21. ⑻  mov     lr, r0 
  22. ⑼  mrs     r0, psp 
  23.  
  24.     stmfd   r0!, {r4-r12} 
  25.  
  26. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  27.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  28. ⑽   vstmdb   r0!, {d8-d15} 
  29. #endif 
  30. ⑾  ldr     r5, =g_losTask 
  31. ⑿  ldr     r6, [r5] 
  32.     str     r0, [r6] 
  33.  
  34. ⒀  ldr     r0, [r5, #4] 
  35.     str     r0, [r5] 
  36.  
  37. ⒁  ldr     r1, [r0] 
  38.  
  39. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  40.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  41. ⒂  vldmia   r1!, {d8-d15} 
  42. #endif 
  43.     ldmfd   r1!, {r4-r12} 
  44. ⒃  msr     psp,  r1 
  45.  
  46. ⒄  msr     PRIMASK, r12 
  47.  
  48.     bx      lr 
  49.     .fnend 

 小結

本文帶領大家一起剖析了鴻蒙輕內核調度模塊的源代碼,包含調用接口及底層的匯編函數實現。

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

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

https://harmonyos.51cto.com

 

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

2021-05-13 09:47:08

鴻蒙HarmonyOS應用

2021-05-14 10:34:29

鴻蒙HarmonyOS應用

2021-05-12 09:45:20

鴻蒙HarmonyOS應用

2021-05-10 15:05:56

鴻蒙HarmonyOS應用

2021-06-04 09:57:49

鴻蒙HarmonyOS應用

2022-01-10 15:31:44

鴻蒙HarmonyOS應用

2022-01-12 10:50:23

鴻蒙HarmonyOS應用

2021-05-25 09:28:34

鴻蒙HarmonyOS應用

2021-10-20 16:08:57

鴻蒙HarmonyOS應用

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-06-04 14:15:10

鴻蒙HarmonyOS應用

2021-05-08 15:14:50

鴻蒙HarmonyOS應用

2021-05-31 20:30:55

鴻蒙HarmonyOS應用

2023-05-08 16:38:46

任務調度分布式任務調度

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-03 18:28:28

Harmony進程任務管理模塊

2021-05-13 12:00:51

cron調度任務系統運維

2023-12-26 07:44:00

Spring定時調度

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2013-12-17 10:15:19

OpenMP任務調度
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91不卡| 激情网站在线观看 | 男人的天堂久久 | 国产精品伦一区二区三级视频 | 欧美久久久久久久 | 在线观看中文字幕 | 欧美成人精品一区二区男人看 | 999久久久久久久 | 人人艹人人 | 久久久久国产一区二区三区 | 欧美成人影院 | 韩日有码| 99精品视频在线 | 亚洲高清在线 | 99免费精品| 一区二区日韩 | 久久99精品久久久 | 在线看无码的免费网站 | 国产精品一二三区 | 午夜视频一区二区 | 日本精品在线一区 | 午夜精品久久久久久久久久久久久 | 中文一区 | 精品久久久久久久久久久院品网 | 新91视频网| 国产精品久久久久久久久久免费 | 国产成人aⅴ| 久热中文字幕 | 天堂一区二区三区 | 国产精品入口久久 | 国产精品免费大片 | 天堂久久久久久久 | 亚洲第一在线 | 久久国产一区二区三区 | 99视频免费| 久草视频在线播放 | 成人免费看黄 | 久久亚洲一区二区 | 日本在线网址 | 精品国产乱码久久久久久蜜臀 | 视频一区二区三区在线观看 |