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

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

開(kāi)發(fā)
本文帶領(lǐng)大家一起學(xué)習(xí)了鴻蒙輕內(nèi)核的任務(wù)棧、任務(wù)上下文的基礎(chǔ)概念,剖析了任務(wù)棧初始化的代碼。

[[399126]]

 想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://harmonyos.51cto.com

繼續(xù)分析鴻蒙輕內(nèi)核源碼,我們本文開(kāi)始要分析下任務(wù)及任務(wù)調(diào)度模塊。首先,我們介紹下任務(wù)棧的基礎(chǔ)概念。任務(wù)棧是高地址向低地址生長(zhǎng)的遞減棧,棧指針指向即將入棧的元素位置。初始化后未使用過(guò)的??臻g初始化的內(nèi)容為宏OS_TASK_STACK_INIT代表的數(shù)值0xCACACACA,棧頂初始化為宏OS_TASK_MAGIC_WORD代表的數(shù)值0xCCCCCCCC。一個(gè)任務(wù)棧的示意圖如下,其中,棧底指針是棧的最大的內(nèi)存地址,棧頂指針,是棧的最小的內(nèi)存地址,棧指針從棧底向棧頂方向生長(zhǎng)。

任務(wù)上下文(Task Context)是任務(wù)及任務(wù)調(diào)度模塊的另外一個(gè)重要的概念,它指的是任務(wù)運(yùn)行的環(huán)境,例如包括程序計(jì)數(shù)器、堆棧指針、通用寄存器等內(nèi)容。在多任務(wù)調(diào)度中,任務(wù)上下文切換(Task Context Switching)屬于核心內(nèi)容,是多個(gè)任務(wù)運(yùn)行在同一CPU核上的基礎(chǔ)。在任務(wù)調(diào)度時(shí),保存退出運(yùn)行狀態(tài)的任務(wù)使用的寄存器信息到任務(wù)棧,還會(huì)從進(jìn)入運(yùn)行狀態(tài)的任務(wù)的棧中讀取上下文信息,恢復(fù)寄存器信息。

下面,我們剖析下任務(wù)棧、任務(wù)棧初始化的源代碼,若涉及開(kāi)發(fā)板部分,以開(kāi)發(fā)板工程targets\cortex-m7_nucleo_f767zi_gcc\為例進(jìn)行源碼分析。首先,看下任務(wù)上下文結(jié)構(gòu)體。

1、TaskContext上下文結(jié)構(gòu)體定義

在文件kernel\arch\arm\cortex-m7\gcc\los_arch_context.h中,定義的上下文的結(jié)構(gòu)體如下,主要是浮點(diǎn)寄存器,通用寄存器。

  1. typedef struct TagTskContext { 
  2. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  3.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  4.     UINT32 S16; 
  5.     UINT32 S17; 
  6.     UINT32 S18; 
  7.     UINT32 S19; 
  8.     UINT32 S20; 
  9.     UINT32 S21; 
  10.     UINT32 S22; 
  11.     UINT32 S23; 
  12.     UINT32 S24; 
  13.     UINT32 S25; 
  14.     UINT32 S26; 
  15.     UINT32 S27; 
  16.     UINT32 S28; 
  17.     UINT32 S29; 
  18.     UINT32 S30; 
  19.     UINT32 S31; 
  20. #endif 
  21.     UINT32 uwR4; 
  22.     UINT32 uwR5; 
  23.     UINT32 uwR6; 
  24.     UINT32 uwR7; 
  25.     UINT32 uwR8; 
  26.     UINT32 uwR9; 
  27.     UINT32 uwR10; 
  28.     UINT32 uwR11; 
  29.     UINT32 uwPriMask; 
  30.     UINT32 uwR0; 
  31.     UINT32 uwR1; 
  32.     UINT32 uwR2; 
  33.     UINT32 uwR3; 
  34.     UINT32 uwR12; 
  35.     UINT32 uwLR; 
  36.     UINT32 uwPC; 
  37.     UINT32 uwxPSR; 
  38. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  39.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  40.     UINT32 S0; 
  41.     UINT32 S1; 
  42.     UINT32 S2; 
  43.     UINT32 S3; 
  44.     UINT32 S4; 
  45.     UINT32 S5; 
  46.     UINT32 S6; 
  47.     UINT32 S7; 
  48.     UINT32 S8; 
  49.     UINT32 S9; 
  50.     UINT32 S10; 
  51.     UINT32 S11; 
  52.     UINT32 S12; 
  53.     UINT32 S13; 
  54.     UINT32 S14; 
  55.     UINT32 S15; 
  56.     UINT32 FPSCR; 
  57.     UINT32 NO_NAME; 
  58. #endif 
  59. } TaskContext; 

 2、任務(wù)棧相關(guān)函數(shù)

2.1 任務(wù)棧初始化函數(shù)

在文件kernel\arch\arm\cortex-m7\gcc\los_context.c中定義了任務(wù)棧初始化函數(shù)VOID *HalTskStackInit(t()。該函數(shù)被文件kernel\src\los_task.c中的函數(shù)UINT32 OsNewTaskInit()調(diào)用完成任務(wù)初始化,并進(jìn)一步在創(chuàng)建任務(wù)函數(shù)UINT32 LOS_TaskCreateOnly()中調(diào)用,完成新創(chuàng)建任務(wù)的任務(wù)棧初始化。

該函數(shù)使用3個(gè)參數(shù),一個(gè)是任務(wù)編號(hào)UINT32 taskID,一個(gè)是初始化的棧的大小UINT32 stackSize,第3個(gè)參數(shù)是棧頂指針VOID *topStack。⑴處代碼把棧內(nèi)容初始化為OS_TASK_STACK_INIT,⑵處把棧頂初始化為OS_TASK_MAGIC_WORD。

⑶處代碼獲取任務(wù)上下文的指針地址TaskContext *context。對(duì)于新創(chuàng)建任務(wù),從棧的底部開(kāi)始,大小為sizeof(TaskContext)的??臻g存放上下文的數(shù)據(jù)。⑷處如果支持浮點(diǎn)數(shù)計(jì)算,需要初始化浮點(diǎn)數(shù)相關(guān)的寄存器。⑸初始化通用寄存器,其中.uwLR初始化為(UINT32)(UINTPTR)HalSysExit。.uwPC初始化為(UINT32)(UINTPTR)OsTaskEntry,這是CPU首次執(zhí)行該任務(wù)時(shí)運(yùn)行的第一條指令的位置。這2個(gè)函數(shù)下文會(huì)分析。

⑹處返回值是指針(VOID *)taskContext,這個(gè)就是任務(wù)初始化后的棧指針,注意不是從棧底開(kāi)始了,棧底保存的是上下文,棧指針要減去上下文占用的棧大小。在棧中,從TaskContext *context指針增加的方向,依次保存上下文結(jié)構(gòu)體的第一個(gè)成員,第二個(gè)成員…另外,初始化棧的時(shí)候,除了特殊的幾個(gè)寄存器,不同寄存器的初始值雖然沒(méi)有什么意義,也有些初始化的規(guī)律。比如R2寄存器初始化為0x02020202L,R12寄存器初始化為0x12121212L初始化的內(nèi)容和寄存器編號(hào)有關(guān)聯(lián),其余類(lèi)似。

  1. LITE_OS_SEC_TEXT_INIT VOID *HalTskStackInit(UINT32 taskID, UINT32 stackSize, VOID *topStack) 
  2.     TaskContext *context = NULL
  3.     errno_t result; 
  4.  
  5.     /* initialize the task stack, write magic num to stack top */ 
  6. ⑴  result = memset_s(topStack, stackSize, (INT32)(OS_TASK_STACK_INIT & 0xFF), stackSize); 
  7.     if (result != EOK) { 
  8.         printf("memset_s is failed:%s[%d]\r\n", __FUNCTION__, __LINE__); 
  9.     } 
  10. ⑵  *((UINT32 *)(topStack)) = OS_TASK_MAGIC_WORD; 
  11.  
  12. ⑶  context = (TaskContext *)(((UINTPTR)topStack + stackSize) - sizeof(TaskContext)); 
  13.  
  14. #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ 
  15.      (defined(__FPU_USED) && (__FPU_USED == 1U))) 
  16. ⑷  context->S16 = 0xAA000010; 
  17.     context->S17 = 0xAA000011; 
  18.     context->S18 = 0xAA000012; 
  19.     context->S19 = 0xAA000013; 
  20.     context->S20 = 0xAA000014; 
  21.     context->S21 = 0xAA000015; 
  22.     context->S22 = 0xAA000016; 
  23.     context->S23 = 0xAA000017; 
  24.     context->S24 = 0xAA000018; 
  25.     context->S25 = 0xAA000019; 
  26.     context->S26 = 0xAA00001A; 
  27.     context->S27 = 0xAA00001B; 
  28.     context->S28 = 0xAA00001C; 
  29.     context->S29 = 0xAA00001D; 
  30.     context->S30 = 0xAA00001E; 
  31.     context->S31 = 0xAA00001F; 
  32.     context->S0 = 0xAA000000; 
  33.     context->S1 = 0xAA000001; 
  34.     context->S2 = 0xAA000002; 
  35.     context->S3 = 0xAA000003; 
  36.     context->S4 = 0xAA000004; 
  37.     context->S5 = 0xAA000005; 
  38.     context->S6 = 0xAA000006; 
  39.     context->S7 = 0xAA000007; 
  40.     context->S8 = 0xAA000008; 
  41.     context->S9 = 0xAA000009; 
  42.     context->S10 = 0xAA00000A; 
  43.     context->S11 = 0xAA00000B; 
  44.     context->S12 = 0xAA00000C; 
  45.     context->S13 = 0xAA00000D; 
  46.     context->S14 = 0xAA00000E; 
  47.     context->S15 = 0xAA00000F; 
  48.     context->FPSCR = 0x00000000; 
  49.     context->NO_NAME = 0xAA000011; 
  50. #endif 
  51.  
  52. ⑸  context->uwR4 = 0x04040404L; 
  53.     context->uwR5 = 0x05050505L; 
  54.     context->uwR6 = 0x06060606L; 
  55.     context->uwR7 = 0x07070707L; 
  56.     context->uwR8 = 0x08080808L; 
  57.     context->uwR9 = 0x09090909L; 
  58.     context->uwR10 = 0x10101010L; 
  59.     context->uwR11 = 0x11111111L; 
  60.     context->uwPriMask = 0; 
  61.     context->uwR0 = taskID; 
  62.     context->uwR1 = 0x01010101L; 
  63.     context->uwR2 = 0x02020202L; 
  64.     context->uwR3 = 0x03030303L; 
  65.     context->uwR12 = 0x12121212L; 
  66.     context->uwLR = (UINT32)(UINTPTR)HalSysExit; 
  67.     context->uwPC = (UINT32)(UINTPTR)OsTaskEntry; 
  68.     context->uwxPSR = 0x01000000L; 
  69.  
  70. ⑹  return (VOID *)context; 

 2.2 獲取任務(wù)棧水線函數(shù)

隨著任務(wù)棧入棧、出棧,當(dāng)前棧使用的大小不一定是最大值,UINT32 OsGetTaskWaterLine(UINT32 taskID)可以獲取的棧使用的最大值即水線WaterLine。該函數(shù)定義在文件kernel\src\los_task.c,它需要1個(gè)參數(shù),即UINT32 taskID任務(wù)編號(hào),返回值UINT32 peakUsed表示獲取的水線值,即任務(wù)棧使用的最大值。

我們?cè)敿?xì)看下代碼,⑴處代碼表示如果棧頂?shù)扔谠O(shè)置的魔術(shù)字,說(shuō)明棧沒(méi)有被溢出破壞,從棧頂開(kāi)始棧內(nèi)容被寫(xiě)滿宏OS_TASK_STACK_INIT的部分是沒(méi)有使用過(guò)的棧空間。使用臨時(shí)棧指針stackPtr指針變量依次向棧底方向增加,判斷棧是否被使用過(guò),while循環(huán)結(jié)束,棧指針stackPtr指向最大的未使用過(guò)的棧地址。⑵處代碼獲取最大的使用過(guò)的??臻g大小,即需要的水線。⑶處如果棧頂溢出,則返回?zé)o效值OS_NULL_INT。

該函數(shù)被kernel\base\los_task.c中的函數(shù)LOS_TaskInfoGet(UINT32 taskId, TSK_INFO_S *taskInfo)調(diào)用,獲取任務(wù)的信息。在shell模塊也會(huì)使用來(lái)或者棧信息。

  1. UINT32 OsStackWaterLineGet(const UINTPTR *stackBottom, const UINTPTR *stackTop, UINT32 *peakUsed) 
  2.     UINT32 size
  3.     const UINTPTR *tmp = NULL
  4. ⑴  if (*stackTop == OS_STACK_MAGIC_WORD) { 
  5.         tmp = stackTop + 1; 
  6.         while ((tmp < stackBottom) && (*tmp == OS_STACK_INIT)) { 
  7.             tmp++; 
  8.         } 
  9. ⑵      size = (UINT32)((UINTPTR)stackBottom - (UINTPTR)tmp); 
  10.         *peakUsed = (size == 0) ? size : (size + sizeof(CHAR *)); 
  11.         return LOS_OK; 
  12.     } else { 
  13.         *peakUsed = OS_INVALID_WATERLINE; 
  14.         return LOS_NOK; 
  15.     } 

  1. UINT32 OsGetTaskWaterLine(UINT32 taskID) 
  2.     UINT32 *stackPtr = NULL
  3.     UINT32 peakUsed; 
  4.  
  5. ⑴  if (*(UINT32 *)(UINTPTR)OS_TCB_FROM_TID(taskID)->topOfStack == OS_TASK_MAGIC_WORD) { 
  6.         stackPtr = (UINT32 *)(UINTPTR)(OS_TCB_FROM_TID(taskID)->topOfStack + OS_TASK_STACK_TOP_OFFSET); 
  7.         while ((stackPtr < (UINT32 *)(OS_TCB_FROM_TID(taskID)->stackPointer)) && (*stackPtr == OS_TASK_STACK_INIT)) { 
  8.             stackPtr += 1; 
  9.         } 
  10. ⑵      peakUsed = OS_TCB_FROM_TID(taskID)->stackSize - 
  11.             ((UINT32)(UINTPTR)stackPtr - OS_TCB_FROM_TID(taskID)->topOfStack); 
  12.     } else { 
  13. ⑶      PRINT_ERR("CURRENT task %s stack overflow!\n", OS_TCB_FROM_TID(taskID)->taskName); 
  14.         peakUsed = OS_NULL_INT; 
  15.     } 
  16.     return peakUsed; 

 3、任務(wù)進(jìn)入退出函數(shù)

3.1、任務(wù)退出函數(shù)

在初始化上下文的時(shí)候,鏈接寄存器設(shè)置的是函數(shù)(UINT32)(UINTPTR)HalSysExit,該函數(shù)定義在文件kernel\src\los_task.c。函數(shù)代碼里調(diào)用LOS_IntLock()關(guān)中斷,然后進(jìn)入死循環(huán)。在任務(wù)正常調(diào)度期間,該函數(shù)理論上不會(huì)被執(zhí)行。在系統(tǒng)異常時(shí),主動(dòng)調(diào)用LOS_Panic()c觸發(fā)異常時(shí),也會(huì)調(diào)用該函數(shù)。

  1. LITE_OS_SEC_TEXT_MINOR VOID HalSysExit(VOID) 
  2.     LOS_IntLock(); 
  3.     while (1) { 
  4.     } 

 3.2、任務(wù)進(jìn)入函數(shù)

在初始化上下文的時(shí)候,PC寄存器設(shè)置的是函數(shù)VOID OsTaskEntry(UINT32 taskId),該函數(shù)定義在文件kernel\base\los_task.c,我們來(lái)分析下源代碼,⑴處代碼獲取taskCB,然后執(zhí)行⑵調(diào)用任務(wù)的入口函數(shù)。等任務(wù)執(zhí)行完畢后,執(zhí)行⑶刪除任務(wù)。通常任務(wù)入口執(zhí)行函數(shù)都是while循環(huán),任務(wù)不執(zhí)行時(shí),會(huì)調(diào)度到其他任務(wù)或者空閑任務(wù),不會(huì)執(zhí)行到刪除任務(wù)階段。

  1. LITE_OS_SEC_TEXT_INIT VOID OsTaskEntry(UINT32 taskID) 
  2.     UINT32 retVal; 
  3. ⑴  LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID); 
  4.  
  5. ⑵  (VOID)taskCB->taskEntry(taskCB->arg); 
  6.  
  7. ⑶  retVal = LOS_TaskDelete(taskCB->taskID); 
  8.     if (retVal != LOS_OK) { 
  9.         PRINT_ERR("Delete Task[TID: %d] Failed!\n", taskCB->taskID); 
  10.     } 

 小結(jié)

本文帶領(lǐng)大家一起學(xué)習(xí)了鴻蒙輕內(nèi)核的任務(wù)棧、任務(wù)上下文的基礎(chǔ)概念,剖析了任務(wù)棧初始化的代碼。后續(xù)也會(huì)陸續(xù)推出更多的分享文章,敬請(qǐng)期待。

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://harmonyos.51cto.com

 

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

2021-05-20 09:50:20

鴻蒙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)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2021-06-04 14:15:10

鴻蒙HarmonyOS應(yīng)用

2021-05-08 15:14:50

鴻蒙HarmonyOS應(yīng)用

2021-05-25 09:28:34

鴻蒙HarmonyOS應(yīng)用

2021-10-20 16:08:57

鴻蒙HarmonyOS應(yīng)用

2021-05-31 20:30:55

鴻蒙HarmonyOS應(yīng)用

2022-03-11 20:23:14

鴻蒙源碼分析進(jìn)程管理

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-03 18:28:28

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

2021-07-06 09:45:03

鴻蒙HarmonyOS應(yīng)用

2021-09-22 14:36:32

鴻蒙HarmonyOS應(yīng)用

2021-05-11 09:54:55

鴻蒙HarmonyOS應(yīng)用

2021-05-27 09:43:56

鴻蒙HarmonyOS應(yīng)用
點(diǎn)贊
收藏

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