時(shí)鐘概念
時(shí)間是非常重要的概念,我們整個(gè)學(xué)生階段有個(gè)東西很重要,就是校園鈴聲. 它控制著上課,下課,吃飯,睡覺(jué)的節(jié)奏.沒(méi)有它學(xué)校的管理就亂套了,老師拖課想拖多久就多久,那可不行,下課鈴聲一響就是在告訴老師時(shí)間到了,該停止了讓學(xué)生HAPPY去了.
操作系統(tǒng)也一樣,需要通過(guò)時(shí)間來(lái)規(guī)范其任務(wù)的執(zhí)行,操作系統(tǒng)中最小的時(shí)間單位是時(shí)鐘節(jié)拍 (OS Tick)。任何操作系統(tǒng)都需要提供一個(gè)時(shí)鐘節(jié)拍,以供系統(tǒng)處理所有和時(shí)間有關(guān)的事件,如線程的延時(shí)、線程的時(shí)間片輪轉(zhuǎn)調(diào)度以及定時(shí)器超時(shí)等。時(shí)鐘節(jié)拍是特定的周期性中斷,這個(gè)中斷可以看做是系統(tǒng)心跳,中斷之間的時(shí)間間隔取決于不同的應(yīng)用,一般是 1ms–100ms,時(shí)鐘節(jié)拍率越快,系統(tǒng)的實(shí)時(shí)響應(yīng)越快,但是系統(tǒng)的額外開(kāi)銷就越大,從系統(tǒng)啟動(dòng)開(kāi)始計(jì)數(shù)的時(shí)鐘節(jié)拍數(shù)稱為系統(tǒng)時(shí)間。
在鴻蒙內(nèi)核中,時(shí)鐘節(jié)拍的長(zhǎng)度可以根據(jù) LOSCFG_BASE_CORE_TICK_PER_SECOND 的定義來(lái)調(diào)整,等于 1/LOSCFG_BASE_CORE_TICK_PER_SECOND 秒。
時(shí)鐘節(jié)拍的實(shí)現(xiàn)方式
時(shí)鐘節(jié)拍由配置為中斷觸發(fā)模式的硬件定時(shí)器產(chǎn)生,當(dāng)中斷到來(lái)時(shí),將調(diào)用一次:void OsTickHandler(void),通知操作系統(tǒng)已經(jīng)過(guò)去一個(gè)系統(tǒng)時(shí)鐘;不同硬件定時(shí)器中斷實(shí)現(xiàn)都不同,
/** * @ingroup los_config * Number of Ticks in one second */ #ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND #define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 //默認(rèn)每秒100次觸發(fā),當(dāng)然這是可以改的 #endif
每秒100個(gè)tick,時(shí)間單位為10毫秒, 即每秒調(diào)用時(shí)鐘中斷處理程序100次.
/* * Description : Tick interruption handler *///節(jié)拍中斷處理函數(shù) ,鴻蒙默認(rèn)10ms觸發(fā)一次 LITE_OS_SEC_TEXT VOID OsTickHandler(VOID) { //... OsTimesliceCheck();//進(jìn)程和任務(wù)的時(shí)間片檢查 OsTaskScan(); /* task timeout scan *///任務(wù)掃描 #if (LOSCFG_BASE_CORE_SWTMR == YES) OsSwtmrScan();//定時(shí)器掃描,看是否有超時(shí)的定時(shí)器 #endif }
它主要干了三件事情
第一:檢查當(dāng)前任務(wù)的時(shí)間片,任務(wù)執(zhí)行一次分配多少時(shí)間呢?答案是2個(gè)時(shí)間片,即 20ms.
#ifndef LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT #define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 2 //2個(gè)時(shí)間片,20ms #endif //檢查進(jìn)程和任務(wù)的時(shí)間片,如果沒(méi)有時(shí)間片了直接調(diào)度 LITE_OS_SEC_TEXT VOID OsTimesliceCheck(VOID) { LosTaskCB *runTask = NULL; LosProcessCB *runProcess = OsCurrProcessGet();//獲取當(dāng)前進(jìn)程 if (runProcess->policy != LOS_SCHED_RR) {//進(jìn)程調(diào)度算法是否是搶占式 goto SCHED_TASK;//進(jìn)程不是搶占式調(diào)度直接去檢查任務(wù)的時(shí)間片 } if (runProcess->timeSlice != 0) {//進(jìn)程還有時(shí)間片嗎? runProcess->timeSlice--;//進(jìn)程時(shí)間片減少一次 if (runProcess->timeSlice == 0) {//沒(méi)有時(shí)間片了 LOS_Schedule();//進(jìn)程時(shí)間片用完,發(fā)起調(diào)度 } } SCHED_TASK: runTask = OsCurrTaskGet();//獲取當(dāng)前任務(wù) if (runTask->policy != LOS_SCHED_RR) {//任務(wù)調(diào)度算法是否是搶占式 return;//任務(wù)不是搶占式調(diào)度直接結(jié)束檢查 } if (runTask->timeSlice != 0) {//任務(wù)還有時(shí)間片嗎? runTask->timeSlice--;//任務(wù)時(shí)間片也減少一次 if (runTask->timeSlice == 0) {//沒(méi)有時(shí)間片了 LOS_Schedule();//任務(wù)時(shí)間片用完,發(fā)起調(diào)度 } } }
第二:掃描任務(wù),主要是檢查被阻塞的任務(wù)是否可以被重新調(diào)度
LITE_OS_SEC_TEXT VOID OsTaskScan(VOID) { SortLinkList *sortList = NULL; LosTaskCB *taskCB = NULL; BOOL needSchedule = FALSE; UINT16 tempStatus; LOS_DL_LIST *listObject = NULL; SortLinkAttribute *taskSortLink = NULL; taskSortLink = &OsPercpuGet()->taskSortLink;//獲取任務(wù)的排序鏈表 taskSortLink->cursor = (taskSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK; listObject = taskSortLink->sortLink + taskSortLink->cursor;//只處理這個(gè)游標(biāo)上的鏈表,因?yàn)橄到y(tǒng)對(duì)超時(shí)任務(wù)都已經(jīng)規(guī)鏈表了. //當(dāng)任務(wù)因超時(shí)而掛起時(shí),任務(wù)塊處于超時(shí)排序鏈接上,(每個(gè)cpu)和ipc(互斥鎖、掃描電鏡等)的塊同時(shí)被喚醒 /*不管是超時(shí)還是相應(yīng)的ipc,它都在等待?,F(xiàn)在使用synchronize sortlink precedure,因此整個(gè)任務(wù)掃描需要保護(hù),防止另一個(gè)核心同時(shí)刪除sortlink。 * When task is pended with timeout, the task block is on the timeout sortlink * (per cpu) and ipc(mutex,sem and etc.)'s block at the same time, it can be waken * up by either timeout or corresponding ipc it's waiting. * * Now synchronize sortlink preocedure is used, therefore the whole task scan needs * to be protected, preventing another core from doing sortlink deletion at same time. */ LOS_SpinLock(&g_taskSpin); if (LOS_ListEmpty(listObject)) { LOS_SpinUnlock(&g_taskSpin); return; } sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);//拿本次Tick對(duì)應(yīng)鏈表的SortLinkList的第一個(gè)節(jié)點(diǎn)sortLinkNode ROLLNUM_DEC(sortList->idxRollNum);//滾動(dòng)數(shù)-- while (ROLLNUM(sortList->idxRollNum) == 0) {//找到時(shí)間到了節(jié)點(diǎn),注意這些節(jié)點(diǎn)都是由定時(shí)器產(chǎn)生的, LOS_ListDelete(&sortList->sortLinkNode); taskCB = LOS_DL_LIST_ENTRY(sortList, LosTaskCB, sortList);//拿任務(wù),這里的任務(wù)都是超時(shí)任務(wù) taskCB->taskStatus &= ~OS_TASK_STATUS_PEND_TIME; tempStatus = taskCB->taskStatus; if (tempStatus & OS_TASK_STATUS_PEND) { taskCB->taskStatus &= ~OS_TASK_STATUS_PEND; #if (LOSCFG_KERNEL_LITEIPC == YES) taskCB->ipcStatus &= ~IPC_THREAD_STATUS_PEND; #endif taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT; LOS_ListDelete(&taskCB->pendList); taskCB->taskSem = NULL; taskCB->taskMux = NULL; } else { taskCB->taskStatus &= ~OS_TASK_STATUS_DELAY; } if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) { OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, OS_PROCESS_STATUS_PEND); needSchedule = TRUE; } if (LOS_ListEmpty(listObject)) { break; } sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); } LOS_SpinUnlock(&g_taskSpin); if (needSchedule != FALSE) {//需要調(diào)度 LOS_MpSchedule(OS_MP_CPU_ALL);//核間通訊,給所有CPU發(fā)送調(diào)度信號(hào) LOS_Schedule();//開(kāi)始調(diào)度 } }
第三:定時(shí)器掃描,看是否有超時(shí)的定時(shí)器
/* * Description: Tick interrupt interface module of software timer * Return : LOS_OK on success or error code on failure *///OsSwtmrScan 由系統(tǒng)時(shí)鐘中斷處理函數(shù)調(diào)用 LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)//掃描定時(shí)器,如果碰到超時(shí)的,就放入超時(shí)隊(duì)列 { SortLinkList *sortList = NULL; SWTMR_CTRL_S *swtmr = NULL; SwtmrHandlerItemPtr swtmrHandler = NULL; LOS_DL_LIST *listObject = NULL; SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;//拿到當(dāng)前CPU的定時(shí)器鏈表 swtmrSortLink->cursor = (swtmrSortLink->cursor + 1) & OS_TSK_SORTLINK_MASK; listObject = swtmrSortLink->sortLink + swtmrSortLink->cursor; //由于swtmr是在特定的sortlink中,所以需要很小心的處理它,但其他CPU Core仍然有機(jī)會(huì)處理它,比如停止計(jì)時(shí)器 /* * it needs to be carefully coped with, since the swtmr is in specific sortlink * while other cores still has the chance to process it, like stop the timer. */ LOS_SpinLock(&g_swtmrSpin); if (LOS_ListEmpty(listObject)) { LOS_SpinUnlock(&g_swtmrSpin); return; } sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); ROLLNUM_DEC(sortList->idxRollNum); while (ROLLNUM(sortList->idxRollNum) == 0) { sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); LOS_ListDelete(&sortList->sortLinkNode); swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList); swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);//取出一個(gè)可用的軟時(shí)鐘處理項(xiàng) if (swtmrHandler != NULL) { swtmrHandler->handler = swtmr->pfnHandler; swtmrHandler->arg = swtmr->uwArg; if (LOS_QueueWrite(OsPercpuGet()->swtmrHandlerQueue, swtmrHandler, sizeof(CHAR *), LOS_NO_WAIT)) { (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandler); } } if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) { OsSwtmrDelete(swtmr); if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) { swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT; } else { swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT; } } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) { swtmr->ucState = OS_SWTMR_STATUS_CREATED; } else { swtmr->ucOverrun++; OsSwtmrStart(swtmr); } if (LOS_ListEmpty(listObject)) { break; } sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); } LOS_SpinUnlock(&g_swtmrSpin); }
最后看調(diào)度算法的實(shí)現(xiàn)
//調(diào)度算法的實(shí)現(xiàn) VOID OsSchedResched(VOID) { LosTaskCB *runTask = NULL; LosTaskCB *newTask = NULL; LosProcessCB *runProcess = NULL; LosProcessCB *newProcess = NULL; LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//必須持有任務(wù)自旋鎖,自旋鎖是不是進(jìn)程層面去搶鎖,而是CPU各自核之間去爭(zhēng)奪鎖 if (!OsPreemptableInSched()) {//是否置了重新調(diào)度標(biāo)識(shí)位 return; } runTask = OsCurrTaskGet();//獲取當(dāng)前任務(wù) newTask = OsGetTopTask();//獲取優(yōu)先級(jí)最最最高的任務(wù) /* always be able to get one task */ LOS_ASSERT(newTask != NULL);//不能沒(méi)有需調(diào)度的任務(wù) if (runTask == newTask) {//當(dāng)前任務(wù)就是最高任務(wù),那還調(diào)度個(gè)啥的,直接退出. return; } runTask->taskStatus &= ~OS_TASK_STATUS_RUNNING;//當(dāng)前任務(wù)狀態(tài)位置成不在運(yùn)行狀態(tài) newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//最高任務(wù)狀態(tài)位置成在運(yùn)行狀態(tài) runProcess = OS_PCB_FROM_PID(runTask->processID);//通過(guò)進(jìn)程ID索引拿到進(jìn)程實(shí)體 newProcess = OS_PCB_FROM_PID(newTask->processID);//同上 OsSchedSwitchProcess(runProcess, newProcess);//切換進(jìn)程,里面主要涉及進(jìn)程空間的切換,也就是MMU的上下文切換. #if (LOSCFG_KERNEL_SMP == YES)//CPU多核的情況 /* mask new running task's owner processor */ runTask->currCpu = OS_TASK_INVALID_CPUID;//當(dāng)前任務(wù)不占用CPU newTask->currCpu = ArchCurrCpuid();//讓新任務(wù)占用CPU #endif (VOID)OsTaskSwitchCheck(runTask, newTask);//切換task的檢查 #if (LOSCFG_KERNEL_SCHED_STATISTICS == YES) OsSchedStatistics(runTask, newTask); #endif if ((newTask->timeSlice == 0) && (newTask->policy == LOS_SCHED_RR)) {//沒(méi)有時(shí)間片且是搶占式調(diào)度的方式,注意 非搶占式都不需要時(shí)間片的. newTask->timeSlice = LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT;//給新任務(wù)時(shí)間片 默認(rèn) 20ms } OsCurrTaskSet((VOID*)newTask);//設(shè)置新的task為CPU核的當(dāng)前任務(wù) if (OsProcessIsUserMode(newProcess)) {//用戶模式下會(huì)怎么樣? OsCurrUserTaskSet(newTask->userArea);//設(shè)置task??臻g } /* do the task context switch */ OsTaskSchedule(newTask, runTask);//切換任務(wù)上下文,注意OsTaskSchedule是一個(gè)匯編函數(shù) 見(jiàn)于 los_dispatch.s }
編輯:hfy
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6889瀏覽量
123708 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3255瀏覽量
115313 -
系統(tǒng)時(shí)鐘
+關(guān)注
關(guān)注
1文章
30瀏覽量
9354 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2638瀏覽量
66676
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論