? ? 第一部分? ? ? 移除掛起等待列表中的任務? ? ?
????????????????while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )//循環尋找直到為空,把全部任務掃描一遍
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );//獲取掛起等待列表中的任務的控制塊指針
?? ??? ??? ??? ??? ?( void ) uxListRemove( &( pxTCB->xEventListItem ) );? //從事件列表中刪除
?? ??? ??? ??? ??? ?( void ) uxListRemove( &( pxTCB->xStateListItem ) );//從掛起列表中刪除
?? ??? ??? ??? ??? ?prvAddTaskToReadyList( pxTCB ); //加入就緒列表
?? ??? ??? ??? ??? ?/* If the moved task has a priority higher than the current
?? ??? ??? ??? ??? ?task then a yield must be performed. */
?? ??? ??? ??? ??? ?if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?xYieldPending = pdTRUE;? //如果恢復的等待列表中的此任務優先級大于當前任務,使能切換
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?mtCOVERAGE_TEST_MARKER();
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
第二部分 補齊錯過的systick計數以及相應的處理
UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */
?? ??? ??? ??? ??? ?if( uxPendedCounts > ( UBaseType_t ) 0U )
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?do
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?if( xTaskIncrementTick() != pdFALSE ) //xTaskIncrementTick()函數用于是否有延時到期的任務,并將其恢復到就緒列表,如果其優先級比當前任務高,則同時使能切換標志,注意僅僅是使能標志,未實際切換。并將切換標志返回
?? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ?xYieldPending = pdTRUE; //需要任務切換
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ??? ?mtCOVERAGE_TEST_MARKER();
?? ??? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ??? ?--uxPendedCounts;
?? ??? ??? ??? ??? ??? ?} while( uxPendedCounts > ( UBaseType_t ) 0U ); //循環補齊systick計數,才能找到所有到期任務,因為循環一次xConstTickCount只能加一次,加到跟當前TickCount值相同才能找處所有xNextTaskUnblockTime到期的任務
?? ??? ??? ??? ??? ??? ?uxPendedTicks = 0;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?mtCOVERAGE_TEST_MARKER();
?? ??? ??? ??? ??? ?}
第三部分 判斷是否需要切換任務
if( xYieldPending != pdFALSE )? //如果xYieldPending為1,在上面兩部分得到的值
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?#if( configUSE_PREEMPTION != 0 )
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?xAlreadyYielded = pdTRUE;? ?//感覺邏輯上應該把下一句切換移到這個條件編譯里面,如果configUSE_PREEMPTION 定義為 0,就不進行任務切換同時xAlreadyYielded也不賦值為1,就是記錄為沒切換過,可能是因為這種情況下taskYIELD_IF_USING_PREEMPTION()未定義(如下圖所示),默認為taskYIELD_IF_USING_PREEMPTION()不起作用,所以不對xAlreadyYielded進行賦值
另外我的理解configUSE_PREEMPTION 定義為 0時,xYieldPending 不可能等于pdTRUE?因為如果configUSE_PREEMPTION == 0任務不可能在延時列表,也不可能在掛起等待就緒列表,進入掛起等待就緒列表是從延時列表進入的
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?#endif
?? ??? ??? ??? ??? ?taskYIELD_IF_USING_PREEMPTION();? // 進行實際的任務切換,這一條很關鍵,也就是說xTaskResumeAll( )函數是能進行實際的任務切換的,不只是判斷是否認該切換,上面有個#if并不是if,很容易理解成此語句不執行
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?mtCOVERAGE_TEST_MARKER();
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?mtCOVERAGE_TEST_MARKER();
?? ??? ?}
?? ?}
?? ?taskEXIT_CRITICAL();
?? ?return xAlreadyYielded;//? 返回是否切換過的標志,如果未切換過,出去后是一定要切換的,因為將當前任務加到等待插入列表,以及延時列表之后,當前任務要處于阻塞狀態,是一定要切換到其他任務的
?四 若未發生實際任務切換的處理
以下函數是xTaskResumeAll() 的調用函數,是將消息加入隊列的一個函數
???if( prvIsQueueFull( pxQueue ) != pdFALSE )
?? ??? ??? ?{
?? ??? ??? ??? ?traceBLOCKING_ON_QUEUE_SEND( pxQueue );
?? ??? ??? ??? ?vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
?? ??? ??? ??? ?if( xTaskResumeAll() == pdFALSE ) //如果xTaskResumeAll()內未發生實際切換
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?portYIELD_WITHIN_API();? // 強制進行任務切換,也就是說一定要切換一次
?? ??? ??? ??? ?}