
[导读] 学习梳理一下FreeRTOS任务管理单元实现思路,代码分析基于V10.4.3。从本文开始计划写个图解freeRTOS内核系列笔记分享给朋友们,希望大家喜欢。文章中或有错误,也请留言交流指正,或加本人微信进行交流~ 本文主要学习梳理FreeRTOS任务管理器的基本原理,大体框架。 内核任务管理器需求先来对比一下裸奔系统与RTOS应用系统的编程模型,看看两种编程的不同画风。 裸奔系统在不用RTOS的单片机应用开发时,编程模型大概是这样的画风: ![]()
在一个基于RTOS应用系统中,其编程模型大致是下面这样一个画风,有多个并行的任务在相对长的宏观时间维度看起来,多个任务是并行运行的,但对于常规单片机而言(一般都是单核),任一时刻只有一个任务或中断函数在独占CPU核。 ![]()
对于单片机而言,一般只有一个核,所有RTOS为了方便理解,可以看成是最最主要的目就是通过软件方法将硬件CPU核程序运行环境抽象为每一个应用任务虚拟出一个软核。这样从时间维度上看起来多任务是并行的,而事实上这种并行是伪并行。 ![]() 上图仅仅为理解RTOS作用方便,这种虚拟核本质上并不存在,只是将硬件CPU核的运行时上下文(PC指针、状态寄存器等寄存器组、任务运行时临时变量等)通过快照保存切入切出而实现多任务的伪并行运行。 FreeRTOS任务管理器需求从前文看出,任务管理要实现任务的切入、切出,则首先需要对任务进行抽象描述,以实现在CPU上能够实现切换。根据阅读代码以及文献加上自己的理解,将内核任务管理器的主要功能需求大致梳理成下面这样一张用例图Use case Diagram,仅仅为理解方便,或许并不严谨。 ![]() 从上图,大致可以看出FreeRTOS任务调度器需要以下一些功能需求:
对于其中几项必须的关键数据域描述一下其抽象作用:
其他的数据域,可裁剪实现一些更丰富的功能,比如主要用于防治优先级反转的优先级继承机制,trace追踪功能等。限于篇幅,也主要梳理任务管理器的主要原理,就不展开了。 任务创建删除管理FreeRTOS为用户提供一组函数集用于任务的创建、删除等管理,先看任务的创建API: BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,4 g9 }) u [8 g1 nconst char * const pcName, const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters,! V0 E' Z6 e+ |& n: `2 R UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;) Q. s' P' c3 ] TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,' v6 T7 G ^% W4 t3 U$ A const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority,$ H$ j' w. B* w0 B! ` StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; 7 K% D s$ i! M: k e a0 S BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION; BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t * pxCreatedTask ) PRIVILEGED_FUNCTION;
这几个任务创建函数都是用于任务创建,任务一旦创建就会被插入任务就绪链表中,当调度器调度启动后就按任务状态机根据调度策略以及外部输入事件进行调度接管。这里以xTaskCreate绘制一下其内在干了些啥: ![]() 再看看另外两个函数: void vTaskAllocateMPURegions( TaskHandle_t xTask,: D" o) d; T R3 ^const MemoryRegion_t * const pxRegions ) PRIVILEGED_FUNCTION;% [6 Q! d( T4 G! d/ n void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION; BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;0 ~$ q( Z+ w7 B* F' [/ z# V1 Z9 y UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;1 g6 O; e! }8 G1 X, X( } UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;, s$ g9 Q5 P6 @7 c" }# K eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; void vTaskGetInfo( TaskHandle_t xTask,9 s$ r! t) o8 J6 O& K. j% A TaskStatus_t * pxTaskStatus, BaseType_t xGetFreeStackSpace,( r% j. P- \- q# u; z! r" V eTaskState eState ) PRIVILEGED_FUNCTION; void vTaskPrioritySet( TaskHandle_t xTask,4 n) Z- p( C& h5 W UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION; void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;/ j! g. c7 t; Q& ]5 }, Q* u/ J void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; 这一系列的API接口操作集主要用于对任务进行挂起延时、获取优先级、自中断函数获取优先级、挂起、恢复运行等操作。基本从其函数名就可以看出其作用。比如:
这里需要注意的是有的函数在中断函数体里面不可以调用,需要使用专用版本,具体可以看看手册或注释。 调度器控制接口void vTaskStartScheduler( void ) PRIVILEGED_FUNCTION;void vTaskEndScheduler( void ) PRIVILEGED_FUNCTION; void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;/ T0 E8 q) ` q' c$ u( g/ y! B/ r1 C BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION; 这一组函数API集主要用于调度器的启动、停止控制:
我根据代码及注释及自己理解,将这些API归类到杂项API集合: TickType_t xTaskGetTickCountFromISR( void ) PRIVILEGED_FUNCTION;UBaseType_t uxTaskGetNumberOfTasks( void ) PRIVILEGED_FUNCTION; char * pcTaskGetName( TaskHandle_t xTaskToQuery ) PRIVILEGED_FUNCTION; TaskHandle_t xTaskGetHandle( const char * pcNameToQuery ) PRIVILEGED_FUNCTION; UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction ) PRIVILEGED_FUNCTION;) K2 T3 M( ~) ^3 i, T" w TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;3 j# ?3 \( _7 G: { t8 d3 Y. [ void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void * pvValue ) PRIVILEGED_FUNCTION;/ x9 `6 V! V, D8 O3 a void * pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery,4 |. F) H; x5 x% Z. V1 K void vApplicationStackOverflowHook( TaskHandle_t xTask,( F. Y I0 C- \. G3 |. E9 s+ r char * pcTaskName ); void vApplicationTickHook( void ); 8 Q3 p/ [ M: [6 h ...... BaseType_t xTaskGenericNotifyStateClear( TaskHandle_t xTask, UBaseType_t uxIndexToClear ) PRIVILEGED_FUNCTION;9 Q3 P. l+ Q1 @+ f3 m0 y uint32_t ulTaskGenericNotifyValueClear( TaskHandle_t xTask,/ L3 Q2 ?& u7 @0 `) ^ UBaseType_t uxIndexToClear, uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;( \( S" P: ^! R void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut,8 }* g- r, H* c0 f. t3 @ TickType_t * const pxTicksToWait ) PRIVILEGED_FUNCTION;" U" u4 {' X/ x' b0 r BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION;+ N1 n" |, O$ s3 X; W 这些函数具体作用就不赘述,这里仅仅梳理分类,用到时候查手册即可。 跨平台移植接口BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;3 P) R6 w9 ^7 Y3 i. X5 I& u$ e svoid vTaskPlaceOnEventList( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;/ W% m ]; T- t: [' F" w void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xItemValue, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;, i# l; ]; D# e [ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, E2 N( C; b8 Q+ }8 j TickType_t xTicksToWait,* A: M4 v, }) i* n6 I) ^0 u const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;4 V# Z: h( F% d BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION; void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,; G/ m4 v) c2 ~0 P: J const TickType_t xItemValue ) PRIVILEGED_FUNCTION; 3 L1 e" V2 _: I( p, t portDONT_DISCARD void vTaskSwitchContext( void ) PRIVILEGED_FUNCTION;7 w. n3 m: D0 I4 k TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION; TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION; void vTaskMissedYield( void ) PRIVILEGED_FUNCTION;$ a# R: |' R" H5 o4 ] BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION; BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;. A# N% m3 `, A/ s* j, a BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION; void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder,* Z9 [% Y7 H5 P; j! ~; [$ E6 ? UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;, O6 Y D: A9 G9 r b void vTaskSetTaskNumber( TaskHandle_t xTask, const UBaseType_t uxHandle ) PRIVILEGED_FUNCTION;6 g3 c7 Y" V+ @0 E9 U) p) ~ void vTaskStepTick( const TickType_t xTicksToJump ) PRIVILEGED_FUNCTION;7 P$ f+ X+ S) n6 ?% }: Y 1 h. @3 Q0 z2 Z* h, I eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION; TaskHandle_t pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION; 4 Z8 k. x. ~( k( h, b; n" q7 [9 r! g void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION; 这些接口不同硬件平台需要做具化的移植,做差异化的处理,但是对于FreeRTOS统一了内部调用的接口。这样的思路在应用开发时也可以考虑使用,对于公共部分可以抽象出统一的接口,这样在不同平台上可以很方便的进行移植。对于这些接口后面有机会学习整理分享。 对于用例图中的其他部分,核心调度部分以及上下文切换,篇幅所限留在后面学习整理分享。 总结一下本文基本学习梳理了一下对于FreeRTOS任务调度器外部接口、以及大体作用,基本组成情况,水平所限,文章中错误难免,欢迎交流指正。 4 |" X2 p# u' X& @/ G |