SIEMENS天津市 西门子代理商——西门子华北一级总代理
5 FreeRTOS任务调度相关源码
5.1 任务控制块TCB_t
FreeRTOS对各个任务进行调度,首先需要一种方式来访问和控制各个任务,任务控制块就可以实现这种功能,它本质是一个结构体,记录了任务的堆栈指针、任务当前状态、任务优先级等。
ListItem_t xStateListItem; /*标记任务状态的列表(Ready, Blocked, Suspended ) */ ListItem_t xEventListItem; /*任务的事件列表 */ UBaseType_t uxPriority; /*任务优先级 */ StackType_t *pxStack; /*任务栈起始地址 */ char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*创建时给任务的描述性名称,便于调试 */ #if(...省略部分) ...省略部分 #endif
} tskTCB;typedef tskTCB TCB_t;5.2 阻塞延时vTaskDelay
当某个任务需要延时,调用vTaskDelay(),则该任务进入阻塞态,此时调度器会从就绪列表中找到优先级最高的就绪任务开始执行。
那vTaskDelay()里面具体执行了哪些内容你呢?
/*delay时间为0则强制进行任务切换 */ if( xTicksToDelay > ( TickType_t ) 0U ) { configASSERT( uxSchedulerSuspended == 0 ); /*停止任务调度*/ vTaskSuspenvdAll(); { traceTASK_DELAY();
/* 在调度器被挂起时从事件列表中删除的任务,在恢复调度器之前,不会被放置在就绪列表中或从阻塞列表中删除 此任务不能出现在事件列表中,因为它是当前正在执行的任务。*/ prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE ); } xAlreadyYielded = xTaskResumeAll(); } else { mtCOVERAGE_TEST_MARKER(); }
/* 如果xTaskResumeAll没有进行任务切换,则强制进行任务切换 */ if( xAlreadyYielded == pdFALSE ) { portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } }#endif /* INCLUDE_vTaskDelay */
vTaskDelay的延时参数是以tick为单位的,即vTaskDelay(1)延时1ms。
当延时参数不为0时,即正常调用延时函数时,先停止任务调度,将当前任务添加至延时列表中,再恢复任务调度。
当延时参数为0时,会强制进行任务切换(portYIELD_WITHIN_API)(疑问:如果当前任务的优先级是最高的,虽然强制切换,但由于该任务的优先级最高,所起其实没有切换到其它任务?如果真的是强制切换到另一个任务,那上面时候这个最高优先级的任务再抢会CPU的使用权呢?)。
5.2.1添加任务到延时列表#if( INCLUDE_xTaskAbortDelay == 1 ) //...省略部分 #endif
/* 在将任务添加到阻塞列表前先将其从就绪列表中移除*/ if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) { /* 当前任务必定在就绪列表中, 所以无需检测, 并且port reset macro 可以被立即调用 */ portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority ); } else { mtCOVERAGE_TEST_MARKER(); }
#if ( INCLUDE_vTaskSuspend == 1 ) { if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ) { /* 为确保不是被定时器事件唤醒,添加任务到挂起列表而不是延时列表. 它将会无定期的阻塞*/ vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); } else { /* 如果事件没有发生,计算任务应该被唤醒的时间。这可能会溢出,但这无关紧要,内核会正确地管理它*/ xTimeToWake = xConstTickCount + xTicksToWait;
/* 列表项将按唤醒顺序插入 */ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount ) { /* 唤醒时间已溢出,将该项放入溢出列表 */ vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); } else { /* 唤醒时间未溢出,所以当前的阻塞列表被使用. */ vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
/* 如果进入阻塞状态的任务被放置在阻塞任务列表的顶部,那么xNextTaskUnblockTime也需要更新 */ if( xTimeToWake < xNextTaskUnblockTime ) { xNextTaskUnblockTime = xTimeToWake; } else { mtCOVERAGE_TEST_MARKER(); } } } } #else /* INCLUDE_vTaskSuspend */ //...省略部分 #endif /* INCLUDE_vTaskSuspend */}
展开全文
相关产品