FreeRTOS调度器挂起与解除
通過分析任務(wù)切換,我們知道任務(wù)切換的兩種方法:系統(tǒng)節(jié)拍器中斷、調(diào)用portYIELD產(chǎn)生PendSV中斷。
在系統(tǒng)節(jié)拍器中斷中,如果調(diào)度器被掛起,僅僅將調(diào)度器掛起時間加一(在解除掛起后需要補償這些節(jié)拍),并不會檢查是否有任務(wù)需要切換。
/* 系統(tǒng)節(jié)拍加一 */ BaseType_t xTaskIncrementTick(void) {BaseType_t xSwitchRequired = pdFALSE;/* 調(diào)度器沒有被掛起 */if(uxSchedulerSuspended == (UBaseType_t)pdFALSE){......}/* 調(diào)度器被掛起 */else{/* 掛起時間加一 */++uxPendedTicks;}/* 前面有程序因為各種原因,要求延遲到現(xiàn)在切換 */if(xYieldPending != pdFALSE){/* 請求切換任務(wù),最終進(jìn)入PendSV異常,是否切換上下文還是在于PendSV */xSwitchRequired = pdTRUE;}return xSwitchRequired; }在PendSV中斷中,如果調(diào)度器被掛起,則不進(jìn)行上下文切換,通過xYieldPending將任務(wù)切換延遲到下一個節(jié)拍。
/* 任務(wù)切換上下文 */ void vTaskSwitchContext(void) {/* 調(diào)度器被掛起 */if(uxSchedulerSuspended != (UBaseType_t)pdFALSE){/* 等到下一次節(jié)拍的時候再切換上下文 */xYieldPending = pdTRUE;}/* 調(diào)度器沒有掛起 */else{......} }也就是說,只要將調(diào)度器掛起,就肯定不會進(jìn)行任務(wù)切換。
?
?
掛起調(diào)度器非常簡單,只要讓uxSchedulerSuspended不等于pdFALSE(0)即可。調(diào)度器可以多次掛起,但是對應(yīng)的也要進(jìn)行多次解除掛起。
/* 掛起調(diào)度器 */ void vTaskSuspendAll(void) {/* 掛起層數(shù)加一 */++uxSchedulerSuspended; }當(dāng)完全解除調(diào)度器掛起時,需要進(jìn)行如下工作:
檢查在調(diào)度器掛起期間是否有任務(wù)進(jìn)入就緒態(tài),有則要將其從掛起期間就緒任務(wù)列表中移除,重新掛接到就緒任務(wù)列表
更新下一個需要解除阻塞的任務(wù),的解除時間
要對之前調(diào)度器掛起期間產(chǎn)生的節(jié)拍進(jìn)行補償
對于延遲切換任務(wù)到下一個節(jié)拍的請求,在這里提供一次切換機會
/* 解除調(diào)度器掛起 */ BaseType_t xTaskResumeAll( void ) {TCB_t *pxTCB = NULL;BaseType_t xAlreadyYielded = pdFALSE;configASSERT(uxSchedulerSuspended);/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 調(diào)度器掛起層數(shù)減一 */--uxSchedulerSuspended;/* 調(diào)度器掛起完全解除 */if(uxSchedulerSuspended == (UBaseType_t)pdFALSE){/* 系統(tǒng)當(dāng)前任務(wù)數(shù)大于0 */if(uxCurrentNumberOfTasks > (UBaseType_t)0U){/* 掛起時進(jìn)入就緒的任務(wù)列表不為空 */while(listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE){/* 從掛起時進(jìn)入就緒的任務(wù)列表中取出一個任務(wù) */pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xPendingReadyList));/* 將任務(wù)從事件列表中移除 */(void)uxListRemove(&(pxTCB->xEventListItem));/* 將任務(wù)從狀態(tài)列表中移除 */(void)uxListRemove(&(pxTCB->xStateListItem));/* 將任務(wù)加入就緒任務(wù)列表 */prvAddTaskToReadyList(pxTCB);/* 如果任務(wù)優(yōu)先級高于當(dāng)前任務(wù)優(yōu)先級,則請求在下一個節(jié)拍時切換 */if(pxTCB->uxPriority >= pxCurrentTCB->uxPriority){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}/* 有任務(wù)在掛起期間就緒 */if(pxTCB != NULL){/* 更新下一個要解除阻塞的時間 */prvResetNextTaskUnblockTime();}{/* 調(diào)度器掛起時間 */UBaseType_t uxPendedCounts = uxPendedTicks;/* 調(diào)度器掛起時間大于1個節(jié)拍 */if(uxPendedCounts > (UBaseType_t)0U){/* 將所有節(jié)拍重新補上 */do{/* 節(jié)拍數(shù)加一,如果需要切換任務(wù),則請求在下一個節(jié)拍時切換 */if(xTaskIncrementTick() != pdFALSE){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}--uxPendedCounts;}while(uxPendedCounts > (UBaseType_t)0U);uxPendedTicks = 0;}else{mtCOVERAGE_TEST_MARKER();}}/* 原來請求在下一個節(jié)拍時切換的任務(wù),在這里直接請求切換 */if(xYieldPending != pdFALSE){#if (configUSE_PREEMPTION != 0){/* 已經(jīng)切換過任務(wù) */xAlreadyYielded = pdTRUE;}#endiftaskYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}}/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 返回是否已經(jīng)切換過任務(wù) */return xAlreadyYielded; }?
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS调度器挂起与解除的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 结不起婚生不起娃的低欲望社会来了?这份自
- 下一篇: makefile之伪目标(6)