wordpress mvc百度seo排名優(yōu)化提高流量
往期知識(shí)點(diǎn)記錄:
- 鴻蒙(HarmonyOS)應(yīng)用層開發(fā)(北向)知識(shí)點(diǎn)匯總
- 持續(xù)更新中……
在鴻蒙輕內(nèi)核源碼分析上一篇文章中,我們剖析了中斷的源碼,簡單提到了Tick
中斷。本文會(huì)繼續(xù)分析Tick
和時(shí)間相關(guān)的源碼,給讀者介紹鴻蒙輕內(nèi)核的時(shí)間管理模塊。本文中所涉及的源碼,以OpenHarmony LiteOS-M
內(nèi)核為例,均可以在開源站點(diǎn)https://gitee.com/openharmony/kernel_liteos_m 獲取。
時(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ù),對(duì)于216 MHz
的CPU
,1秒產(chǎn)生216000000個(gè)cycles
。
用戶以秒、毫秒為單位計(jì)時(shí),而操作系統(tǒng)以Tick
為單位計(jì)時(shí),當(dāng)用戶需要對(duì)系統(tǒng)進(jìn)行操作時(shí),例如任務(wù)掛起、延時(shí)等,此時(shí)可以使用時(shí)間管理模塊對(duì)Tick
和秒/毫秒進(jìn)行轉(zhuǎn)換。
下面,我們剖析下時(shí)間管理模塊的源代碼,若涉及開發(fā)板部分,以開發(fā)板工程targets\cortex-m7_nucleo_f767zi_gcc\
為例進(jìn)行源碼分析。
1、時(shí)間管理初始化和啟動(dòng)
我們先看下時(shí)間管理模塊的相關(guān)配置,然后再剖析如何初始化,如何啟動(dòng)。
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
中定義如下:
#define OS_SYS_CLOCK 96000000
#define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL)
#define LOSCFG_BASE_CORE_TICK_HW_TIME 0
1.2 時(shí)間管理初始化和啟動(dòng)
函數(shù)INT32 main(VOID)
會(huì)調(diào)用kernel\src\los_init.c
中的函數(shù)UINT32 LOS_Start(VOID)
啟動(dòng)系統(tǒng),該函數(shù)會(huì)調(diào)用啟動(dòng)調(diào)度函數(shù)UINT32 HalStartSchedule(OS_TICK_HANDLER handler)
。源碼如下:
LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
{return HalStartSchedule(OsTickHandler);
}
函數(shù)UINT32 HalTickStart(OS_TICK_HANDLER *handler)
定義在kernel\arch\arm\cortex-m7\gcc\los_context.c
,源碼如下。其中函數(shù)參數(shù)為Tick
中斷處理函數(shù)OsTickHandler()
,后文會(huì)分析該tick
中斷處理函數(shù)。⑴處代碼繼續(xù)調(diào)用函數(shù)進(jìn)一步調(diào)用函數(shù)HalTickStart(handler)
來設(shè)置Tick
中斷啟動(dòng)。⑵處會(huì)調(diào)用匯編函數(shù)HalStartToRun
開始運(yùn)行系統(tǒng),后續(xù)任務(wù)調(diào)度系列再詳細(xì)分析該匯編函數(shù)。
LITE_OS_SEC_TEXT_INIT UINT32 HalStartSchedule(OS_TICK_HANDLER handler)
{UINT32 ret;
⑴ ret = HalTickStart(handler);if (ret != LOS_OK) {return ret;}
⑵ HalStartToRun();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í),會(huì)使用系統(tǒng)定義的中斷。會(huì)執(zhí)行⑵處的代碼,調(diào)用定義在文件kernel\arch\arm\cortex-m7\gcc\los_interrupt.c
中的函數(shù)OsSetVector()
設(shè)置中斷向量,該函數(shù)在中斷系列會(huì)詳細(xì)分析。⑶處設(shè)置全局變量g_sysClock
為系統(tǒng)時(shí)鐘,g_cyclesPerTick
為每tick
對(duì)應(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)
,初始化、啟動(dòng)系統(tǒng)定時(shí)器Systick
和中斷。
WEAK UINT32 HalTickStart(OS_TICK_HANDLER *handler)
{UINT32 ret;⑴ if ((OS_SYS_CLOCK == 0) ||(LOSCFG_BASE_CORE_TICK_PER_SECOND == 0) ||(LOSCFG_BASE_CORE_TICK_PER_SECOND > OS_SYS_CLOCK)) {return LOS_ERRNO_TICK_CFG_INVALID;}#if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1)
#if (OS_HWI_WITH_ARG == 1)OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler, NULL);
#else
⑵ OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler);
#endif
#endif⑶ g_sysClock = OS_SYS_CLOCK;g_cyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND;g_ullTickCount = 0;⑷ ret = SysTick_Config(g_cyclesPerTick);if (ret == 1) {return LOS_ERRNO_TICK_PER_SEC_TOO_SMALL;}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í)就會(huì)調(diào)用該函數(shù)。我們分析下該函數(shù)的源碼,⑴處如果開啟宏LOSCFG_BASE_CORE_TICK_HW_TIME
,會(huì)調(diào)用定制的tick
處理函數(shù)platform_tick_handler()
,默認(rèn)不開啟。⑵處會(huì)更新全局變量g_ullTickCount
,⑶處如果開啟宏LOSCFG_BASE_CORE_TIMESLICE
,會(huì)檢查當(dāng)前運(yùn)行任務(wù)的時(shí)間片,在后續(xù)任務(wù)模塊會(huì)詳細(xì)分析下函數(shù)OsTimesliceCheck()
。⑷處會(huì)遍歷任務(wù)的排序鏈表,檢查是否有超時(shí)的任務(wù)。⑸處如果支持定時(shí)器特性,會(huì)檢查定時(shí)器是否超時(shí)。
源碼如下:
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == 1)
⑴ platform_tick_handler();
#endif⑵ g_ullTickCount++;#if (LOSCFG_BASE_CORE_TIMESLICE == 1)
⑶ OsTimesliceCheck();
#endif⑷ OsTaskScan(); // task timeout scan#if (LOSCFG_BASE_CORE_SWTMR == 1)
⑸ (VOID)OsSwtmrScan();
#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
,除以OS_SYS_MS_PER_SECOND
,得出1毫秒多少Tick
,然后乘以millisec
,計(jì)算出Tick
數(shù)目的結(jié)果值并返回。
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{if (millisec == OS_NULL_INT) {return OS_NULL_INT;}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é)果值并返回。
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 ticks)
{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ù)值。
typedef struct tagCpuTick {UINT32 cntHi; /* < 一個(gè)64位數(shù)值的高32位 */UINT32 cntLo; /* < 一個(gè)64位數(shù)值的低32位 */
} CpuTick;
繼續(xù)看轉(zhuǎn)換函數(shù)OsCpuTick2MS()
,它可以把CpuTick
類型表示的cycle
數(shù)目轉(zhuǎn)換為對(duì)應(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ù)目對(duì)應(yīng)的毫秒數(shù)目。⑸處把DOUBLE
類型轉(zhuǎn)換為UINT64
類型,然后執(zhí)行⑹,分別把結(jié)果數(shù)值的高、低64位賦值給*msLo
、*msHi
。
LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2MS(CpuTick *cpuTick, UINT32 *msHi, UINT32 *msLo)
{UINT64 tmpCpuTick;DOUBLE temp;⑴ if ((cpuTick == NULL) || (msHi == NULL) || (msLo == NULL)) {return LOS_ERRNO_SYS_PTR_NULL;}⑵ if (g_sysClock == 0) {return LOS_ERRNO_SYS_CLOCK_INVALID;}
⑶ tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo;
⑷ temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_MS_PER_SECOND);tmpCpuTick = (UINT64)temp;*msLo = (UINT32)tmpCpuTick;*msHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT);return LOS_OK;
}
2.1.4 Cycle數(shù)目轉(zhuǎn)化為微秒
轉(zhuǎn)換函數(shù)OsCpuTick2US()
,它可以把CpuTick
類型表示的cycle
數(shù)目轉(zhuǎn)換為對(duì)應(yīng)的毫秒數(shù),輸出毫秒數(shù)據(jù)的高、低32位數(shù)值。該函數(shù)和OsCpuTick2MS()
類似,自行閱讀即可。
LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2US(CpuTick *cpuTick, UINT32 *usHi, UINT32 *usLo)
{UINT64 tmpCpuTick;DOUBLE temp;if ((cpuTick == NULL) || (usHi == NULL) || (usLo == NULL)) {return LOS_ERRNO_SYS_PTR_NULL;}if (g_sysClock == 0) {return LOS_ERRNO_SYS_CLOCK_INVALID;}tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo;temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_US_PER_SECOND);tmpCpuTick = (UINT64)temp;*usLo = (UINT32)tmpCpuTick;*usHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT);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
。
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{return g_cyclesPerTick;
}
2.2.2 獲取自系統(tǒng)啟動(dòng)以來的Tick數(shù)
UINT64 LOS_TickCountGet(VOID)
函數(shù)計(jì)算自系統(tǒng)啟動(dòng)以來的Tick
中斷的次數(shù)。需要注意,在關(guān)中斷的情況下不進(jìn)行計(jì)數(shù),不能作為準(zhǔn)確時(shí)間使用。每次Tick
中斷發(fā)生時(shí),在函數(shù)VOID OsTickHandler(VOID)
中會(huì)更新g_ullTickCount
數(shù)據(jù)。
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{return g_ullTickCount;
}
2.2.3 獲取系統(tǒng)時(shí)鐘
UINT32 LOS_SysClockGet(VOID)
函數(shù)獲取配置的系統(tǒng)時(shí)鐘。
UINT32 LOS_SysClockGet(VOID)
{return g_sysClock;
}
2.2.4 獲取系統(tǒng)啟動(dòng)以來的Cycle數(shù)
函數(shù)VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo)
定義在文件kernel\arch\arm\cortex-m7\gcc\los_timer.c
中,該函數(shù)獲取系統(tǒng)啟動(dòng)以來的Cycle
數(shù)。返回結(jié)果按高、低32位的無符號(hào)數(shù)值UINT32 *cntHi, UINT32 *cntLo
分別返回。
我們看下該函數(shù)的源碼。先關(guān)中斷,然后⑴處獲取啟動(dòng)啟動(dòng)以來的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)啟動(dòng)以來的Cycle
數(shù)。⑸處獲取Cycle
數(shù)的高、低32位的無符號(hào)數(shù)值,然后開中斷、返回。
LITE_OS_SEC_TEXT_MINOR VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo)
{UINT64 swTick;UINT64 cycle;UINT32 hwCycle;UINTPTR intSave;intSave = LOS_IntLock();⑴ swTick = g_ullTickCount;
⑵ hwCycle = SysTick->VAL;⑶ if ((SCB->ICSR & TICK_CHECK) != 0) {hwCycle = SysTick->VAL;swTick++;}⑷ cycle = (((swTick) * g_cyclesPerTick) + (g_cyclesPerTick - hwCycle));⑸ *cntHi = cycle >> SHIFT_32_BIT;*cntLo = cycle & CYCLE_CHECK;LOS_IntRestore(intSave);return;
}
小結(jié)
本文帶領(lǐng)大家一起剖析了鴻蒙輕內(nèi)核的時(shí)間管理模塊的源代碼。時(shí)間管理模塊為任務(wù)調(diào)度提供必要的時(shí)鐘節(jié)拍,會(huì)向應(yīng)用程序提供所有和時(shí)間有關(guān)的服務(wù),如時(shí)間轉(zhuǎn)換、統(tǒng)計(jì)、延遲功能。后續(xù)也會(huì)陸續(xù)推出更多的分享文章,敬請(qǐng)期待,也歡迎大家分享學(xué)習(xí)、使用鴻蒙輕內(nèi)核的心得,有任何問題、建議,都可以留言給我們: https://gitee.com/openharmony/kernel_liteos_m/issues 。為了更容易找到鴻蒙輕內(nèi)核代碼倉,建議訪問 https://gitee.com/openharmony/kernel_liteos_m,關(guān)注Watch
、點(diǎn)贊Star
、并Fork
到自己賬戶下,謝謝。
寫在最后
如果你覺得這篇內(nèi)容對(duì)你還蠻有幫助,我想邀請(qǐng)你幫我三個(gè)小忙:
- 點(diǎn)贊,轉(zhuǎn)發(fā),有你們的 『點(diǎn)贊和評(píng)論』,才是我創(chuàng)造的動(dòng)力。
- 關(guān)注小編,同時(shí)可以期待后續(xù)文章ing🚀,不定期分享原創(chuàng)知識(shí)。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)資源,請(qǐng)看下圖提示: