FreeRTOS源码理解(三)——任务

FreeRTOS源码理解(一)——FreeRTOS思路梳理

FreeRTOS源码理解(二)——中断和列表项

FreeRTOS源码理解(三)——任务

FreeRTOS源码理解(四)——任务调度器

FreeRTOS源码理解(五)——任务切换

FreeRTOS源码理解(六)——时间管理

FreeRTOS源码理解(七)——队列

FreeRTOS源码理解(八)——信号量

FreeRTOS源码理解(九)——事件组和任务通知

FreeRTOS源码理解(十)——软件定时器和空闲任务

FreeRTOS源码理解(十一)——内存管理

FreeRTOS源码理解(十二)——汇总

任务

任务状态

运行态、就绪态、阻塞态、挂起态

任务控制块

每个任务均有一些属性,RTOS将任务抽象成任务控制块结构体

里面存储有任务的堆栈指针,临界区信息,任务优先级,任务的状态和事件列表项等

任务的创建流程

  1. 关闭中断
  2. 创建任务 xTaskCreate()
  3. 开启中断

动态创建:程序自动分配内存,初始化控制块

静态创建:用户自行分配内存

任务创建函数 xTaskCreate

  1. 申请堆栈内存和TCB内存
  2. 初始化新任务 prvInitialiseNewTask
  3. 将新任务加入到就绪列表中 prvAddNewTaskToReadyList

初始化新任务 prvInitialiseNewTask

  1. 初始化堆栈
  2. 保存任务名
  3. 判断任务优先级是否合法
  4. 初始化优先级
  5. 互斥量相关参数初始化
  6. 列表项初始化——状态和事件列表项(设置pvOwner为当前TCB)
  7. 事件列表项的value值初始化为configMAX_PRIORITIES - uxPriority
  8. 初始化堆栈 pxPortInitialiseStack
  9. 任务句柄赋值为当前TCB指针
堆栈初始化 pxPortInitialiseStack
  1. 将xPSR寄存器要初始化的值和任务函数地址压入栈中——xPSR寄存器和PC初始化值
  2. 将prvTaskExitError压入栈中——LR的值初始化为prvTaskExitError
  3. 跳过4个寄存器,R12,R3,R2,R1;栈顶指针减5
  4. 将输入参数指针压入栈中——R0初始化为输入参数
  5. 跳过8个寄存器,R11, R10, R9, R8, R7, R6, R5 and R4;栈顶指针减8
  6. 更新栈顶指针

堆栈结构示例(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
  1. 关中断 taskENTER_CRITICAL
  2. 判断当前任务TCB,如果没有则将新任务TCB赋给pxCurrentTCB
  3. 如果是第一个任务,初始化相应的列表 prvInitialiseTaskLists——ListItem_t结构体的初始化
  4. 如果当前任务控制块有有任务,且未开启任务调度器,比较优先级,选择优先级高的赋值给pxCurrentTCB
  5. 任务ID赋值 pxNewTCB->uxTCBNumber = uxTaskNumber;
  6. 将当前TCB添加到就绪列表中 prvAddTaskToReadyList
  7. 开中断
  8. 如果开启了任务调度器,比较新任务的优先级和当前任务的优先级,新任务的优先级大于当前任务的优先级,进行任务切换 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

  1. 关中断 taskENTER_CRITICAL
  2. 从就绪列表中移除列表项pxTCB->xStateListItem uxListRemove( &( pxTCB->xStateListItem ) )
  3. 判断其是否在等待某个事件,在某个事件列表中,是的话删除 listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL
  4. 判断是否正在运行 pxTCB == pxCurrentTCB
    1. 将其加入到等待删除的列表中 vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
    2. 释放内存的任务数量加一,任务资源会在空闲任务中释放
  5. 要删除的任务并未运行则直接释放资源 prvDeleteTCB
  6. 更新下一任务的解锁事件——还有多久到下一任务 prvResetNextTaskUnblockTime
  7. 开中断 taskEXIT_CRITICAL
  8. 如果任务调度器开启并且要删除的任务正在执行pxTCB == pxCurrentTCB,执行任务切换

任务挂起流程 vTaskSuspend

  1. 关中断 taskENTER_CRITICAL
  2. 从就绪列表中移除列表项pxTCB->xStateListItem uxListRemove( &( pxTCB->xStateListItem ) )
  3. 判断是否在等待某个事件,如果在某个事件的等待列表中,则移除它
  4. 将其插入到挂起列表的末端 vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
  5. 开中断
  6. 更新下一任务的解锁事件——还有多久到下一任务 prvResetNextTaskUnblockTime
  7. 如果任务调度器开启了且要挂起的任务为当前任务,进行一次任务切换;如果任务调度器关闭了,但是当前任务为要挂起的任务,手动寻找下一个要运行的任务并进行切换

任务恢复流程 vTaskResume

  1. 获取任务控制块
  2. 关中断 taskENTER_CRITICAL
  3. 判断任务是否被挂起 prvTaskIsTaskSuspended
  4. 从挂起的列表中移除列表项 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
  5. 将其添加到就绪列表中 prvAddTaskToReadyList( pxTCB );
  6. 根据优先级决定是否进行任务切换,如果恢复的任务优先级较当前任务优先级更高则任务切换,反之不切换
  7. 开中断 taskEXIT_CRITICAL

文档汇总

文档汇总

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值