讀了一下下freeRTOS的代碼,結合代碼過一下freeRTOS調度器是怎麼工作的。
vTaskStartScheduler
創建完用戶的各種任務之後,調用函數vTaskStartScheduler便進入了任務調度,任務地阿杜這個函數做了三件事。
- 創建 idle 任務 , 以下便是這部分代碼
可以看出idle task的任務優先級被設置爲
portPRIVILEGE_BIT
, 而portPRIVILEGE_BIT
被定義爲0x00,也就是最低優先級(freeRTOS中數字越大優先級越高)。換句話說,idle task的回調函數只有在系統“無事可做”的時候會被調用。
// The Idle task is created using user provided RAM
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
// Create the idle task
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
configIDLE_TASK_NAME,
ulIdleTaskStackSize,
( void * ) NULL,
portPRIVILEGE_BIT,
pxIdleTaskStackBuffer,
pxIdleTaskTCBBuffer );
- 創建 timer task
if( xReturn == pdPASS )
{
xReturn = xTimerCreateTimerTask();
}
- 啓動timer task 和 最高優先級task ,即調用
xPortStartScheduler
if( xPortStartScheduler() != pdFALSE )
然後進入xPortStartScheduler
,這個函數並不在freeRTOS的三大源碼文件中,而是屬於port的一部分,以下代碼來自MSVC-MingW的實現(此代碼可運行於windows上)。
-
啓動 tick 中斷
pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, CREATE_SUSPENDED, NULL ); if( pvHandle != NULL ) { SetThreadPriority( pvHandle, portSIMULATED_TIMER_THREAD_PRIORITY ); SetThreadPriorityBoost( pvHandle, TRUE ); SetThreadAffinityMask( pvHandle, 0x01 ); ResumeThread( pvHandle ); }
-
啓動最高優先級任務
ResumeThread( pxThreadState->pvThread );
- 調用函數
ProcessSimulatedInterrupts
至此在此層函數範圍內程序不在往下執行,即程序進入函數·
ProcessSimulatedInterrupts
便不再出來了,ProcessSimulatedInterrupts
的主題是一個死循環,完成任務的調度,如以下代碼。
static void prvProcessSimulatedInterrupts( void )
{
...
for(;;)
{
...
for( i = 0; i < portMAX_INTERRUPTS; i++ )
{
...
if( ulIsrHandler[ i ]() != pdFALSE )
...
}
if( ulSwitchRequired != pdFALSE )
{
void *pvOldCurrentTCB;
pvOldCurrentTCB = pxCurrentTCB;
vTaskSwitchContext();
/* If the task selected to enter the running state is not the task
that is already in the running state. */
if( pvOldCurrentTCB != pxCurrentTCB )
{
pxThreadState = ( ThreadState_t *) *( ( size_t * ) pvOldCurrentTCB );
SuspendThread( pxThreadState->pvThread );
xContext.ContextFlags = CONTEXT_INTEGER;
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
ResumeThread( pxThreadState->pvThread );
}
}
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
SetEvent( pxThreadState->pvYieldEvent );
ReleaseMutex( pvInterruptEventMutex );
}
}