偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

鴻蒙輕內(nèi)核M核源碼分析系列六 任務(wù)及任務(wù)調(diào)度(3)任務(wù)調(diào)度模塊

開發(fā)
文章由鴻蒙社區(qū)產(chǎn)出,想要了解更多內(nèi)容請前往:51CTO和華為官方戰(zhàn)略合作共建的鴻蒙技術(shù)社區(qū)https://harmonyos.51cto.com

[[400426]]

想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

調(diào)度,Schedule也稱為Dispatch,是操作系統(tǒng)的一個重要模塊,它負責(zé)選擇系統(tǒng)要處理的下一個任務(wù)。調(diào)度模塊需要協(xié)調(diào)處于就緒狀態(tài)的任務(wù)對資源的競爭,按優(yōu)先級策略從就緒隊列中獲取高優(yōu)先級的任務(wù),給予資源使用權(quán)。

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

1、調(diào)度模塊的重要函數(shù)

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

1.1 調(diào)度初始化函數(shù)

調(diào)度初始化函數(shù)UINT32 OsSchedInit(VOID)在任務(wù)初始化函數(shù)UINT32 OsTaskInit(VOID)中調(diào)用。⑴處會初始化任務(wù)就緒隊列,⑵處初始化任務(wù)排序鏈表,⑶處初始化調(diào)度響應(yīng)時間全局變量為最大值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 任務(wù)調(diào)度函數(shù)

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

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

 1.3 開啟調(diào)度函數(shù)

函數(shù)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)函數(shù)依次調(diào)用,在系統(tǒng)初始化時開啟任務(wù)調(diào)度。我們看下該函數(shù)的源碼,⑴處調(diào)用函數(shù)獲取就緒隊列中優(yōu)先級最高的任務(wù),⑵把該任務(wù)狀態(tài)設(shè)置為運行狀態(tài),接著把當(dāng)前運行任務(wù)和新任務(wù)都設(shè)置為就緒隊列中優(yōu)先級最高的那個任務(wù)。⑶處設(shè)置任務(wù)調(diào)度啟動狀態(tài)全局變量為1,標(biāo)記任務(wù)調(diào)度已經(jīng)開啟。⑷處設(shè)置新任務(wù)的開始運行時間,然后把新任務(wù)從就緒隊列中出隊。⑸處設(shè)置全局變量。⑹處調(diào)用函數(shù)設(shè)置該任務(wù)的運行過期時間。

  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 任務(wù)調(diào)度切換函數(shù)

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

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

  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、調(diào)度模塊匯編函數(shù)

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

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

 2.1 HalStartToRun匯編函數(shù)

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

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

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

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

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

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

  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匯編函數(shù)

匯編函數(shù)HalTaskSchedule實現(xiàn)新老任務(wù)的切換調(diào)度。從上文可以知道,被任務(wù)調(diào)度函數(shù)VOID LOS_Schedule(VOID)調(diào)用。我們看看這個匯編函數(shù)的源代碼,首先往中斷控制狀態(tài)寄存器OS_NVIC_INT_CTRL中的OS_NVIC_PENDSVSET位置1,觸發(fā)PendSV異常。執(zhí)行完畢HalTaskSchedule函數(shù),返回上層調(diào)用函數(shù)。PendSV異常的回調(diào)函數(shù)是HalPendSV匯編函數(shù),下文會分析此函數(shù)。匯編函數(shù)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匯編函數(shù)

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

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

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

  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 

 小結(jié)

本文帶領(lǐng)大家一起剖析了鴻蒙輕內(nèi)核調(diào)度模塊的源代碼,包含調(diào)用接口及底層的匯編函數(shù)實現(xiàn)。

想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

 

責(zé)任編輯:jianghua 來源: 鴻蒙社區(qū)
相關(guān)推薦

2021-05-13 09:47:08

鴻蒙HarmonyOS應(yīng)用

2021-05-14 10:34:29

鴻蒙HarmonyOS應(yīng)用

2021-05-12 09:45:20

鴻蒙HarmonyOS應(yīng)用

2021-05-10 15:05:56

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2021-05-25 09:28:34

鴻蒙HarmonyOS應(yīng)用

2021-10-20 16:08:57

鴻蒙HarmonyOS應(yīng)用

2021-05-08 15:14:50

鴻蒙HarmonyOS應(yīng)用

2021-06-04 14:15:10

鴻蒙HarmonyOS應(yīng)用

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2021-05-31 20:30:55

鴻蒙HarmonyOS應(yīng)用

2023-05-08 16:38:46

任務(wù)調(diào)度分布式任務(wù)調(diào)度

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-03 18:28:28

Harmony進程任務(wù)管理模塊

2021-05-13 12:00:51

cron調(diào)度任務(wù)系統(tǒng)運維

2013-12-17 10:15:19

OpenMP任務(wù)調(diào)度

2020-04-01 16:10:02

PythonAPScheduler調(diào)度

2023-12-26 07:44:00

Spring定時調(diào)度
點贊
收藏

51CTO技術(shù)棧公眾號