自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

鴻蒙輕內(nèi)核M核源碼分析系列五-時(shí)間管理

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

[[398138]]

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

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

https://harmonyos.51cto.com

 在鴻蒙輕內(nèi)核源碼分析上一篇文章中,我們剖析了中斷的源碼,簡單提到了Tick中斷。本文會繼續(xù)分析Tick和時(shí)間相關(guān)的源碼,給讀者介紹鴻蒙輕內(nèi)核的時(shí)間管理模塊。

時(shí)間管理模塊以系統(tǒng)時(shí)鐘為基礎(chǔ),可以分為2部分,一部分是SysTick中斷,為任務(wù)調(diào)度提供必要的時(shí)鐘節(jié)拍;另外一部分是,給應(yīng)用程序提供所有和時(shí)間有關(guān)的服務(wù),如時(shí)間轉(zhuǎn)換、統(tǒng)計(jì)功能。

系統(tǒng)時(shí)鐘是由定時(shí)器/計(jì)數(shù)器產(chǎn)生的輸出脈沖觸發(fā)中斷產(chǎn)生的,一般定義為整數(shù)或長整數(shù)。輸出脈沖的周期叫做一個(gè)“時(shí)鐘滴答”,也稱為時(shí)標(biāo)或者Tick。Tick是操作系統(tǒng)的基本時(shí)間單位,由用戶配置的每秒Tick數(shù)決定。如果用戶配置每秒的Tick數(shù)目為1000,則1個(gè)Tick等于1ms的時(shí)長。另外一個(gè)計(jì)時(shí)單位是Cycle,這是系統(tǒng)最小的計(jì)時(shí)單位。Cycle的時(shí)長由系統(tǒng)主時(shí)鐘頻率決定,系統(tǒng)主時(shí)鐘頻率就是每秒鐘的Cycle數(shù),對于216 MHz的CPU,1秒產(chǎn)生216000000個(gè)cycles。

用戶以秒、毫秒為單位計(jì)時(shí),而操作系統(tǒng)以Tick為單位計(jì)時(shí),當(dāng)用戶需要對系統(tǒng)進(jìn)行操作時(shí),例如任務(wù)掛起、延時(shí)等,此時(shí)可以使用時(shí)間管理模塊對Tick和秒/毫秒進(jìn)行轉(zhuǎn)換。

下面,我們剖析下時(shí)間管理模塊的源代碼,若涉及開發(fā)板部分,以開發(fā)板工程targets\cortex-m7_nucleo_f767zi_gcc\為例進(jìn)行源碼分析。

1、時(shí)間管理初始化和啟動

我們先看下時(shí)間管理模塊的相關(guān)配置,然后再剖析如何初始化,如何啟動。

1.1 時(shí)間管理相關(guān)的配置

時(shí)間管理模塊涉及3個(gè)配置項(xiàng),系統(tǒng)時(shí)鐘OS_SYS_CLOCK、每秒Tick數(shù)目LOSCFG_BASE_CORE_TICK_PER_SECOND兩個(gè)配置選項(xiàng),還有宏LOSCFG_BASE_CORE_TICK_HW_TIME。LOSCFG_BASE_CORE_TICK_HW_TIME默認(rèn)關(guān)閉,開啟時(shí),需要提供定制函數(shù)VOID platform_tick_handler(VOID),在Tick中斷處理函數(shù)中執(zhí)行定制操作。這些配置項(xiàng)在模板開發(fā)板工程目錄的文件target_config.h中定義,如文件targets\cortex-m7_nucleo_f767zi_gcc\target_config.h中定義如下:

  1. #define OS_SYS_CLOCK                                        96000000 
  2. #define LOSCFG_BASE_CORE_TICK_PER_SECOND                    (1000UL) 
  3. #define LOSCFG_BASE_CORE_TICK_HW_TIME                       0 

 1.2 時(shí)間管理初始化和啟動

函數(shù)INT32 main(VOID)會調(diào)用kernel\src\los_init.c中的函數(shù)UINT32 LOS_Start(VOID)啟動系統(tǒng),該函數(shù)會調(diào)用啟動調(diào)度函數(shù)UINT32 HalStartSchedule(OS_TICK_HANDLER handler)。源碼如下:

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID) 
  2.     return HalStartSchedule(OsTickHandler); 

 函數(shù)UINT32 HalTickStart(OS_TICK_HANDLER *handler)定義在kernel\arch\arm\cortex-m7\gcc\los_context.c,源碼如下。其中函數(shù)參數(shù)為Tick中斷處理函數(shù)OsTickHandler(),后文會分析該tick中斷處理函數(shù)。⑴處代碼繼續(xù)調(diào)用函數(shù)進(jìn)一步調(diào)用函數(shù)HalTickStart(handler)來設(shè)置Tick中斷啟動。⑵處會調(diào)用匯編函數(shù)HalStartToRun開始運(yùn)行系統(tǒng),后續(xù)任務(wù)調(diào)度系列再詳細(xì)分析該匯編函數(shù)。

  1. LITE_OS_SEC_TEXT_INIT UINT32 HalStartSchedule(OS_TICK_HANDLER handler) 
  2.     UINT32 ret; 
  3. ⑴  ret = HalTickStart(handler); 
  4.     if (ret != LOS_OK) { 
  5.         return ret; 
  6.     } 
  7. ⑵  HalStartToRun(); 
  8.     return LOS_OK; /* never return */ 

 函數(shù)HalTickStart(handler)定義在文件kernel\arch\arm\cortex-m7\gcc\los_timer.c,源碼如下,我們分析下函數(shù)的代碼實(shí)現(xiàn)。⑴處校驗(yàn)下時(shí)間管理模塊的配置項(xiàng)的合法性。在開啟宏LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT時(shí),會使用系統(tǒng)定義的中斷。會執(zhí)行⑵處的代碼,調(diào)用定義在文件kernel\arch\arm\cortex-m7\gcc\los_interrupt.c中的函數(shù)OsSetVector()設(shè)置中斷向量,該函數(shù)在中斷系列會詳細(xì)分析。⑶處設(shè)置全局變量g_sysClock為系統(tǒng)時(shí)鐘,g_cyclesPerTick為每tick對應(yīng)的cycle數(shù)目,g_ullTickCount初始化為0,表示系統(tǒng)tick中斷發(fā)生次數(shù)。⑷處調(diào)用定義在targets\cortex-m7_nucleo_f767zi_gcc\Drivers\CMSIS\Include\core_cm7.h文件中的內(nèi)聯(lián)函數(shù)uint32_t SysTick_Config(uint32_t ticks),初始化、啟動系統(tǒng)定時(shí)器Systick和中斷。

  1. WEAK UINT32 HalTickStart(OS_TICK_HANDLER *handler) 
  2.     UINT32 ret; 
  3.  
  4. ⑴  if ((OS_SYS_CLOCK == 0) || 
  5.         (LOSCFG_BASE_CORE_TICK_PER_SECOND == 0) || 
  6.         (LOSCFG_BASE_CORE_TICK_PER_SECOND > OS_SYS_CLOCK)) { 
  7.         return LOS_ERRNO_TICK_CFG_INVALID; 
  8.     } 
  9.  
  10. #if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1) 
  11. #if (OS_HWI_WITH_ARG == 1) 
  12.     OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler, NULL); 
  13. #else 
  14. ⑵  OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler); 
  15. #endif 
  16. #endif 
  17.  
  18. ⑶  g_sysClock = OS_SYS_CLOCK; 
  19.     g_cyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND; 
  20.     g_ullTickCount = 0; 
  21.  
  22. ⑷  ret = SysTick_Config(g_cyclesPerTick); 
  23.     if (ret == 1) { 
  24.         return LOS_ERRNO_TICK_PER_SEC_TOO_SMALL; 
  25.     } 
  26.  
  27.     return LOS_OK; 

 1.3 Tick中斷處理函數(shù)OsTickHandler()

文件kernel\src\los_tick.c定義的函數(shù)VOID OsTickHandler(VOID),是時(shí)間管理模塊中執(zhí)行最頻繁的函數(shù),每當(dāng)Tick中斷發(fā)生時(shí)就會調(diào)用該函數(shù)。我們分析下該函數(shù)的源碼,⑴處如果開啟宏LOSCFG_BASE_CORE_TICK_HW_TIME,會調(diào)用定制的tick處理函數(shù)platform_tick_handler(),默認(rèn)不開啟。⑵處會更新全局變量g_ullTickCount,⑶處如果開啟宏LOSCFG_BASE_CORE_TIMESLICE,會檢查當(dāng)前運(yùn)行任務(wù)的時(shí)間片,在后續(xù)任務(wù)模塊會詳細(xì)分析下函數(shù)OsTimesliceCheck()。⑷處會遍歷任務(wù)的排序鏈表,檢查是否有超時(shí)的任務(wù)。⑸處如果支持定時(shí)器特性,會檢查定時(shí)器是否超時(shí)。

源碼如下:

  1. LITE_OS_SEC_TEXT VOID OsTickHandler(VOID) 
  2. #if (LOSCFG_BASE_CORE_TICK_HW_TIME == 1) 
  3. ⑴  platform_tick_handler(); 
  4. #endif 
  5.  
  6. ⑵  g_ullTickCount++; 
  7.  
  8. #if (LOSCFG_BASE_CORE_TIMESLICE == 1) 
  9. ⑶  OsTimesliceCheck(); 
  10. #endif 
  11.  
  12. ⑷   OsTaskScan();  // task timeout scan 
  13.  
  14. #if (LOSCFG_BASE_CORE_SWTMR == 1) 
  15. ⑸  (VOID)OsSwtmrScan(); 
  16. #endif 

 2、LiteOS內(nèi)核時(shí)間管理常用操作

時(shí)間管理提供下面幾種功能,時(shí)間轉(zhuǎn)換、時(shí)間統(tǒng)計(jì)等,這些函數(shù)定義在文件kernel\src\los_tick.c,我們剖析下這些操作的源代碼實(shí)現(xiàn)。

2.1 時(shí)間轉(zhuǎn)換操作

2.1.1 毫秒轉(zhuǎn)換成Tick

函數(shù)UINT32 LOS_MS2Tick(UINT32 millisec)把輸入?yún)?shù)毫秒數(shù)UINT32 millisec可以轉(zhuǎn)化為Tick數(shù)目。代碼中OS_SYS_MS_PER_SECOND,即1秒等于1000毫秒。時(shí)間轉(zhuǎn)換也比較簡單,知道一秒多少Tick,除以O(shè)S_SYS_MS_PER_SECOND,得出1毫秒多少Tick,然后乘以millisec,計(jì)算出Tick數(shù)目的結(jié)果值并返回。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec) 
  2.     if (millisec == OS_NULL_INT) { 
  3.         return OS_NULL_INT; 
  4.     } 
  5.  
  6.     return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND; 

 2.1.2 Tick轉(zhuǎn)化為毫秒

函數(shù)UINT32 LOS_Tick2MS(UINT32 tick)把輸入?yún)?shù)Tick數(shù)目轉(zhuǎn)換為毫秒數(shù)。時(shí)間轉(zhuǎn)換也比較簡單,ticks數(shù)目除以每秒多少Tick數(shù)值LOSCFG_BASE_CORE_TICK_PER_SECOND,計(jì)算出多少秒,然后轉(zhuǎn)換成毫秒,計(jì)算出結(jié)果值并返回。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 ticks) 
  2.     return ((UINT64)ticks * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND; 

 2.1.3 Cycle數(shù)目轉(zhuǎn)化為毫秒

介紹轉(zhuǎn)換函數(shù)之前,先看下一個(gè)CpuTick結(jié)構(gòu)體,結(jié)構(gòu)體比較簡單,就2個(gè)成員,分別表示一個(gè)UINT64類型數(shù)據(jù)的高、低32位數(shù)值。

  1. typedef struct tagCpuTick { 
  2.     UINT32 cntHi; /* < 一個(gè)64位數(shù)值的高32位 */ 
  3.     UINT32 cntLo; /* < 一個(gè)64位數(shù)值的低32位 */ 
  4. } CpuTick; 

 繼續(xù)看轉(zhuǎn)換函數(shù)OsCpuTick2MS(),它可以把CpuTick類型表示的cycle數(shù)目轉(zhuǎn)換為對應(yīng)的毫秒數(shù),輸出毫秒數(shù)據(jù)的高、低32位數(shù)值??聪戮唧w的代碼,⑴處校驗(yàn)參數(shù)是否為空指針,⑵處檢查系統(tǒng)時(shí)鐘是否配置。⑶處把CpuTick結(jié)構(gòu)體表示的cycle數(shù)目轉(zhuǎn)化為UINT64類型數(shù)據(jù)。⑷處進(jìn)行數(shù)值計(jì)算,(DOUBLE)g_sysClock / OS_SYS_MS_PER_SECOND得到每毫秒多少個(gè)cycle數(shù),然后和tmpCpuTick做除法運(yùn)算,得到cycle數(shù)目對應(yīng)的毫秒數(shù)目。⑸處把DOUBLE類型轉(zhuǎn)換為UINT64類型,然后執(zhí)行⑹,分別把結(jié)果數(shù)值的高、低64位賦值給*msLo、*msHi。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2MS(CpuTick *cpuTick, UINT32 *msHi, UINT32 *msLo) 
  2.     UINT64 tmpCpuTick; 
  3.     DOUBLE temp
  4.  
  5. ⑴  if ((cpuTick == NULL) || (msHi == NULL) || (msLo == NULL)) { 
  6.         return LOS_ERRNO_SYS_PTR_NULL; 
  7.     } 
  8.  
  9. ⑵  if (g_sysClock == 0) { 
  10.         return LOS_ERRNO_SYS_CLOCK_INVALID; 
  11.     } 
  12. ⑶  tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo; 
  13. ⑷  temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_MS_PER_SECOND); 
  14.  
  15.     tmpCpuTick = (UINT64)temp
  16.  
  17.     *msLo = (UINT32)tmpCpuTick; 
  18.     *msHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT); 
  19.  
  20.     return LOS_OK; 

 2.1.4 Cycle數(shù)目轉(zhuǎn)化為微秒

轉(zhuǎn)換函數(shù)OsCpuTick2US(),它可以把CpuTick類型表示的cycle數(shù)目轉(zhuǎn)換為對應(yīng)的毫秒數(shù),輸出毫秒數(shù)據(jù)的高、低32位數(shù)值。該函數(shù)和OsCpuTick2MS()類似,自行閱讀即可。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2US(CpuTick *cpuTick, UINT32 *usHi, UINT32 *usLo) 
  2.     UINT64 tmpCpuTick; 
  3.     DOUBLE temp
  4.  
  5.     if ((cpuTick == NULL) || (usHi == NULL) || (usLo == NULL)) { 
  6.         return LOS_ERRNO_SYS_PTR_NULL; 
  7.     } 
  8.  
  9.     if (g_sysClock == 0) { 
  10.         return LOS_ERRNO_SYS_CLOCK_INVALID; 
  11.     } 
  12.     tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo; 
  13.     temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_US_PER_SECOND); 
  14.  
  15.     tmpCpuTick = (UINT64)temp
  16.  
  17.     *usLo = (UINT32)tmpCpuTick; 
  18.     *usHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT); 
  19.  
  20.     return LOS_OK; 

 2.2 時(shí)間統(tǒng)計(jì)操作

2.2.1 獲取每個(gè)Tick等于多少Cycle數(shù)

函數(shù)UINT32 LOS_CyclePerTickGet(VOID)計(jì)算1個(gè)tick等于多少cycle。g_sysClock系統(tǒng)時(shí)鐘表示1秒多少cycle,LOSCFG_BASE_CORE_TICK_PER_SECOND一秒多少tick,相除計(jì)算出1 tick多少cycle數(shù),即g_cyclesPerTick = g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID) 
  2.     return g_cyclesPerTick; 

 2.2.2 獲取自系統(tǒng)啟動以來的Tick數(shù)

UINT64 LOS_TickCountGet(VOID)函數(shù)計(jì)算自系統(tǒng)啟動以來的Tick中斷的次數(shù)。需要注意,在關(guān)中斷的情況下不進(jìn)行計(jì)數(shù),不能作為準(zhǔn)確時(shí)間使用。每次Tick中斷發(fā)生時(shí),在函數(shù)VOID OsTickHandler(VOID)中會更新g_ullTickCount數(shù)據(jù)。

  1. LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID) 
  2.     return g_ullTickCount; 

 2.2.3 獲取系統(tǒng)時(shí)鐘

UINT32 LOS_SysClockGet(VOID)函數(shù)獲取配置的系統(tǒng)時(shí)鐘。

  1. UINT32 LOS_SysClockGet(VOID) 
  2.     return g_sysClock; 

 2.2.4 獲取系統(tǒng)啟動以來的Cycle數(shù)

函數(shù)VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo)定義在文件kernel\arch\arm\cortex-m7\gcc\los_timer.c中,該函數(shù)獲取系統(tǒng)啟動以來的Cycle數(shù)。返回結(jié)果按高、低32位的無符號數(shù)值UINT32 *cntHi, UINT32 *cntLo分別返回。

我們看下該函數(shù)的源碼。先關(guān)中斷,然后⑴處獲取啟動啟動以來的Tick數(shù)目。⑵處通過讀取當(dāng)前值寄存器SysTick Current Value Register,獲取hwCycle。⑶處表示中斷控制和狀態(tài)寄存器Interrupt Control and State Register的第TICK_CHECK位為1時(shí),表示掛起systick中斷,tick沒有計(jì)數(shù),需要加1校準(zhǔn)。⑷處根據(jù)swTick、g_cyclesPerTick和hwCycle計(jì)算出自系統(tǒng)啟動以來的Cycle數(shù)。⑸處獲取Cycle數(shù)的高、低32位的無符號數(shù)值,然后開中斷、返回。

  1. LITE_OS_SEC_TEXT_MINOR VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo) 
  2.     UINT64 swTick; 
  3.     UINT64 cycle; 
  4.     UINT32 hwCycle; 
  5.     UINTPTR intSave; 
  6.  
  7.     intSave = LOS_IntLock(); 
  8.  
  9. ⑴  swTick = g_ullTickCount; 
  10. ⑵  hwCycle = SysTick->VAL; 
  11.  
  12. ⑶  if ((SCB->ICSR & TICK_CHECK) != 0) { 
  13.         hwCycle = SysTick->VAL; 
  14.         swTick++; 
  15.     } 
  16.  
  17. ⑷  cycle = (((swTick) * g_cyclesPerTick) + (g_cyclesPerTick - hwCycle)); 
  18.  
  19. ⑸  *cntHi = cycle >> SHIFT_32_BIT; 
  20.     *cntLo = cycle & CYCLE_CHECK; 
  21.  
  22.     LOS_IntRestore(intSave); 
  23.  
  24.     return

 小結(jié)

本文帶領(lǐng)大家一起剖析了鴻蒙輕內(nèi)核的時(shí)間管理模塊的源代碼。時(shí)間管理模塊為任務(wù)調(diào)度提供必要的時(shí)鐘節(jié)拍,會向應(yīng)用程序提供所有和時(shí)間有關(guān)的服務(wù),如時(shí)間轉(zhuǎn)換、統(tǒng)計(jì)、延遲功能。后續(xù)也會陸續(xù)推出更多的分享文章,敬請期待,為了更容易找到鴻蒙輕內(nèi)核代碼倉,建議訪問 https://gitee.com/openharmony/kernel_liteos_m ,謝謝。

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

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

https://harmonyos.51cto.com

 

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

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2022-03-11 20:23:14

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

2022-03-03 18:28:28

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

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2021-06-04 14:15:10

鴻蒙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-04-13 11:02:12

鴻蒙事件模塊事件Event

2021-07-06 09:45:03

鴻蒙HarmonyOS應(yīng)用

2021-09-22 14:36:32

鴻蒙HarmonyOS應(yīng)用

2021-06-09 09:48:01

鴻蒙HarmonyOS應(yīng)用

2021-05-21 09:25:11

鴻蒙HarmonyOS應(yīng)用

2021-05-27 09:43:56

鴻蒙HarmonyOS應(yīng)用

2021-05-11 09:54:55

鴻蒙HarmonyOS應(yīng)用

2022-03-31 16:26:49

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

2022-01-14 08:39:47

鴻蒙HarmonyOS應(yīng)用

2021-05-10 15:05:56

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

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