文章目录
任务
任务状态
运行态、就绪态、阻塞态、挂起态
任务控制块
每个任务均有一些属性,RTOS将任务抽象成任务控制块结构体
里面存储有任务的堆栈指针,临界区信息,任务优先级,任务的状态和事件列表项等
任务的创建流程
- 关闭中断
- 创建任务 xTaskCreate()
- 开启中断
动态创建:程序自动分配内存,初始化控制块
静态创建:用户自行分配内存
任务创建函数 xTaskCreate
- 申请堆栈内存和TCB内存
- 初始化新任务 prvInitialiseNewTask
- 将新任务加入到就绪列表中 prvAddNewTaskToReadyList
初始化新任务 prvInitialiseNewTask
- 初始化堆栈
- 保存任务名
- 判断任务优先级是否合法
- 初始化优先级
- 互斥量相关参数初始化
- 列表项初始化——状态和事件列表项(设置pvOwner为当前TCB)
- 事件列表项的value值初始化为configMAX_PRIORITIES - uxPriority
- 初始化堆栈 pxPortInitialiseStack
- 任务句柄赋值为当前TCB指针
堆栈初始化 pxPortInitialiseStack
- 将xPSR寄存器要初始化的值和任务函数地址压入栈中——xPSR寄存器和PC初始化值
- 将prvTaskExitError压入栈中——LR的值初始化为prvTaskExitError
- 跳过4个寄存器,R12,R3,R2,R1;栈顶指针减5
- 将输入参数指针压入栈中——R0初始化为输入参数
- 跳过8个寄存器,R11, R10, R9, R8, R7, R6, R5 and R4;栈顶指针减8
- 更新栈顶指针
堆栈结构示例(STM32 M3)
添加新任务到就绪列表
列表项
/* Lists for ready and blocked tasks. --------------------*/
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];/*< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1; /*< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
列表数组pxReadyTasksLists[]为任务就绪列表,数组中的每个列表表示相同优先级的就绪任务列表
pxDelayedTaskList为延时列表,pxOverflowDelayedTaskList为延时溢出列表这两个指向xDelayedTaskList1和xDelayedTaskList2,实现溢出处理
xPendingReadyList唤醒任务列表
prvAddNewTaskToReadyList
- 关中断 taskENTER_CRITICAL
- 判断当前任务TCB,如果没有则将新任务TCB赋给pxCurrentTCB
- 如果是第一个任务,初始化相应的列表 prvInitialiseTaskLists——ListItem_t结构体的初始化
- 如果当前任务控制块有有任务,且未开启任务调度器,比较优先级,选择优先级高的赋值给pxCurrentTCB
- 任务ID赋值 pxNewTCB->uxTCBNumber = uxTaskNumber;
- 将当前TCB添加到就绪列表中 prvAddTaskToReadyList
- 开中断
- 如果开启了任务调度器,比较新任务的优先级和当前任务的优先级,新任务的优先级大于当前任务的优先级,进行任务切换 taskYIELD_IF_USING_PREEMPTION
prvAddTaskToReadyList
#define prvAddTaskToReadyList( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
行2:空
行3:将优先级存储进uxReadyPriorities的位图中
行4:将(pxTCB )->xStateListItem 一个列表项插入到pxReadyTasksLists[ ( pxTCB )->uxPriority ]列表的末尾
行5:空
任务删除流程 vTaskDelete
- 关中断 taskENTER_CRITICAL
- 从就绪列表中移除列表项pxTCB->xStateListItem uxListRemove( &( pxTCB->xStateListItem ) )
- 判断其是否在等待某个事件,在某个事件列表中,是的话删除 listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL
- 判断是否正在运行 pxTCB == pxCurrentTCB
- 将其加入到等待删除的列表中 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
- 释放内存的任务数量加一,任务资源会在空闲任务中释放
- 要删除的任务并未运行则直接释放资源 prvDeleteTCB
- 更新下一任务的解锁事件——还有多久到下一任务 prvResetNextTaskUnblockTime
- 开中断 taskEXIT_CRITICAL
- 如果任务调度器开启并且要删除的任务正在执行pxTCB == pxCurrentTCB,执行任务切换
任务挂起流程 vTaskSuspend
- 关中断 taskENTER_CRITICAL
- 从就绪列表中移除列表项pxTCB->xStateListItem uxListRemove( &( pxTCB->xStateListItem ) )
- 判断是否在等待某个事件,如果在某个事件的等待列表中,则移除它
- 将其插入到挂起列表的末端 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
- 开中断
- 更新下一任务的解锁事件——还有多久到下一任务 prvResetNextTaskUnblockTime
- 如果任务调度器开启了且要挂起的任务为当前任务,进行一次任务切换;如果任务调度器关闭了,但是当前任务为要挂起的任务,手动寻找下一个要运行的任务并进行切换
任务恢复流程 vTaskResume
- 获取任务控制块
- 关中断 taskENTER_CRITICAL
- 判断任务是否被挂起 prvTaskIsTaskSuspended
- 从挂起的列表中移除列表项 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
- 将其添加到就绪列表中 prvAddTaskToReadyList( pxTCB );
- 根据优先级决定是否进行任务切换,如果恢复的任务优先级较当前任务优先级更高则任务切换,反之不切换
- 开中断 taskEXIT_CRITICAL