之前介绍的和FreeRTOS任务调度相关的数据结构即内存分配实现。xLIST、heap_4、TCB结构体。任务调度就是基于这些结构体实现。这次介绍调度相关的主要变量。
代码在FreeRTOSMini.c文件签名部分。
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = (UBaseType_t)0U;
PRIVILEGED_DATA TCB_t* volatile pxCurrentTCB = NULL;
PRIVILEGED_DATA static List_t pxReadyTasksLists[configMAX_PRIORITIES];
PRIVILEGED_DATA static List_t xDelayedTaskList1;
PRIVILEGED_DATA static List_t xDelayedTaskList2;
PRIVILEGED_DATA static List_t* volatile pxDelayedTaskList;
PRIVILEGED_DATA static List_t* volatile pxOverflowDelayedTaskList;
PRIVILEGED_DATA static List_t xPendingReadyList;
PRIVILEGED_DATA static volatile TickType_t xTickCount = (TickType_t)0;
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = (TickType_t)0U;
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = (UBaseType_t)pdFALSE;
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = (TickType_t)0U;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = (UBaseType_t)0U;
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = (BaseType_t)0;
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;
uxCurrentNumberOfTasks是无符号long类型,每创建一个任务就把该私有变量加1,把这个数字设置到创建的任务的TCB里,作为任务唯一号,该变量就是记录唯一号增加的用处。
pxCurrentTCB很重要,该变量存当前运行的任务的TCB,调度任务就是在systick中断判断是否需要换任务运行。如果需要切换任务,那么触发PendSV中断。在PendSV中断函数里先按pxCurrentTCB的栈顶指针压栈保存上下文,然后调用切换任务逻辑,切换任务逻辑按优先级找到要运行的TCB设置到pxCurrentTCB。然后按pxCurrentTCB出栈寄存器值恢复pxCurrentTCB指向的新TCB的上下文,退出PendSV后按新上下文执行切换后的新任务。都是通过pxCurrentTCB变量。
pxReadyTasksLists是优先级个数的xLIST数组。该数组可以保存每个优先级的对应列表。创建任务时候就把创建的任务加入对应优先级位置的就绪列表上。优先级对应pxReadyTasksLists的数组索引,具体TCB的xStateListItem状态列表项挂接到对应位置列表中。调度时候也是按最高优先级往低优先级任务调度执行。相同优先级的任务轮流共享时间片。高优先级任务可以抢占低优先级任务时间片。
xDelayedTaskList1和xDelayedTaskList2用了存调用vTaskDelay进行延时的任务。按解除时间排序。为什么需要两个列表来存延迟任务。因为延时后的解块时间是按OS当前系统节拍xTickCount加上调用延迟函数延迟的节拍数(都是以系统节拍数为参考),既然系统节拍数是个整数,那么总有溢出的时候,溢出后又从0开始。如果一个任务调用延时函数延迟10个节拍。没溢出的情况下该任务解除延时节拍应该在xTickCount+10。如果xTickCount+10>xTickCount那么没溢出,该任务放入没溢出的延迟列表。如果xTickCount+10<xTickCount那么解块时候OS节拍溢出了。对于这些任务该方法溢出延迟列表。OS节拍执行到xTickCount=0时候对调xDelayedTaskList1和xDelayedTaskList2列表。这样就完美解决了溢出问题。pxDelayedTaskList和pxOverflowDelayedTaskList指针正好来回在xDelayedTaskList1和xDelayedTaskList2对调。
xPendingReadyList我目前还没使用。
xTickCount是系统节拍数,每次Systick中断都给该值加一。代表整个系统时钟节拍,延迟到期解除都依据系统节拍计数。
xNextTaskUnblockTime记录最近解除延时的系统节拍。有任务调用延时函数时候都计算更新该值。延迟列表变动时候就把下次最近出块时间算好,避免每次从整个延迟列表计算出块时间,减少性能开销用的。
uxSchedulerSuspended标志调度器是否被挂起。
xSchedulerRunning标志任务调度器是否在运行。
xYieldPending是否要执行上下文切换。在程序中主动设置该变量让OS任务调度进行任务切换。其他切换是按时间片和任务优先级切换。该变量进行主动切换。
uxTaskNumber记录系统的任务数量。
xNumOfOverflows记录溢出的节拍数,目前我还没用到。
xIdleTaskHandle空闲任务句柄,执行空闲任务的TCB。没有任务时候就调用该句柄。
uxTopReadyPriority记录运行最高任务优先级。把要运行的最高优先级记录在该变量。防止每次遍历整个就绪任务数组导致开销大。任务调度后及时更新该变量的值。
uxTopUsedPriority记录创建和使用的最高优先级任务。比该位置高的优先级数组就不需要检查了,减少调度开销。
这些就是任务调度要用到的主要变量,创建任务和调度任务都会用到这些变量。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)