浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现
来源:互联网 发布:淘宝到第三层级 编辑:程序博客网 时间:2024/06/14 12:52
文章来源:http://gliethttp.cublog.cn[转载请声明出处
void vTaskDelay( portTickType xTicksToDelay)
{
portTickType xTimeToWake;
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
if( xTicksToDelay>( portTickType) 0)
{
//真的是要延时
vTaskSuspendAll();//那么锁住调度器
{
//在调度器锁定期间,如果因为IRQ中断之类,引起了,某个task从事件等待状态
//变为了可运行状态,在IRQ中,调用了xQueueGenericSendFromISR()事件函数,
//并不会直接将该task从Event事件队列链表中摘除,
//该task会被临时放到xPendingReadyList队列链表上,当调度器解锁的时候,
//会将xPendingReadyList队列链表上所有暂时被登记的tasks们,添加到就绪运行队列链表
//pxReadyTasksLists[x],同时将tasks们依次从他们对应的Event事件链表上摘下
//能够调用vTaskDelay()的task肯定没有等待Event事件,否则不会执行到这里,
//所以仅仅对task的xGenericListItem进行操作,即可,不用理会xEventListItem
//下面计算从当前系统滴答xTickCount开始,经过xTicksToDelay延时之后数据为多少,可能溢出,
//如果会发生时间上的溢出,那么把本task添加到溢出时间队列链表上,否则添加到当前时间
//队列链表上,比如:xTickCount现在等于0xfffffffe,xTicksToDelay的值定义为延时10个ticks滴答,
//那么xTimeToWake最后因为溢出将会等于8,所以在溢出时间队列链表上的第8个ticks滴答
//会唤醒本task(gliethttp)
xTimeToWake = xTickCount + xTicksToDelay;
//task把自己从就绪运行队列链表pxReadyTasksLists[x]中摘掉,这之后本task已经不在就绪运行队列链表中,
//因为调度器在就绪运行队列链表中,再也找不本task的信息,进而调度器也就不会调度本task了
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem));
//xGenericListItem的xItemValue用来存放延时ticks值xTimeToWake
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem), xTimeToWake);
if( xTimeToWake< xTickCount)
{
//说明发生了时间溢出,所以把本task添加到pxOverflowDelayedTaskList队列,
//当vTaskIncrementTick()执行系统滴答时,发现xTickCount == 0时,FreeRTOS会自动
//将pxOverflowDelayedTaskList切换为当前时间队列链表,同时当前时间链表会作为下一个
//溢出时间链表被置到后台,
//即:
//pxTemp = pxDelayedTaskList;
//pxDelayedTaskList = pxOverflowDelayedTaskList;//将后台的时间队列链表置到前台,正式使用
//pxOverflowDelayedTaskList = pxTemp;//将正在使用的时间队列链表置到后台,等待下一次时间溢出时使用.
vListInsert( ( xList * ) pxOverflowDelayedTaskList,( xListItem*) &( pxCurrentTCB->xGenericListItem));
}
else
{
//延时时间计算之后,并没有发生溢出现象,那么将本task挂接到前台正在使用中的时间队列链表
//pxDelayedTaskList上
vListInsert( ( xList * ) pxDelayedTaskList,( xListItem*) &( pxCurrentTCB->xGenericListItem));
}
}
//ok,我们已经将task从就绪运行队列链表中摘下来,并且把自己放到了时间队列链表上,
//现在执行xTaskResumeAll(),
//1.看看,在我们执行上面代码期间内是否有其他task
//发生了调度申请,也就是xPendingReadyList队列链表上是否有task了,
//如果有task登记到xPendingReadyList队列链表上,那么
//分别把他们从相应的Event事件队列链表上摘下
//(因为IRQ中发现调度器锁住之后,不会进行摘除工作,仅仅把task添加到xPendingReadyList队列链表上),
//同时把他们也从等待的时间队列链表pxDelayedTaskList或者pxOverflowDelayedTaskList上摘下来,
//之后把他们添加到就绪运行队列链表pxReadyTasksLists[x]上,如果添加的task的优先级比当前运行
//的task的优先级高,那么标示随后需要内核调度器调度.
//2.看看,在我们执行上面代码期间内是否有发生了系统tick滴答,
//如果发生了,那么模拟定时器,连续调用vTaskIncrementTick()函数uxMissedTicks次,补上错过的uxMissedTicks个
//系统tick滴答,之后需要调度,所以调用taskYIELD()产生调度,
//3.看看,是否因为内核被锁住而有些tasks暂时被推迟调度的现象,
//3.1>是否已经有task申请了内核调度vTaskSwitchContext()或者
//3.2>prvUnlockQueue()发现有优先级高于当前正在运行的task的被唤醒,
//进而通过vTaskMissedYield()登记需要执行内核调度器.
//只要上面有一个条件符合,那么xTaskResumeAll()函数中就会执行taskYIELD()调度,
//进而本task被抢占,直到恢复获得cpu时,xAlreadyYielded将等于true,所以下面的
//调度语句taskYIELD(),就不用再执行了,因为本task刚刚才获得cpu使用权(gliethttp).
xAlreadyYielded = xTaskResumeAll();
}
if(!xAlreadyYielded)
{
//如果在xTaskResumeAll()中没有发生调度,没有发生其他task抢占本task的现象,
//本task没能切换出去,进而让出cpu,
//那么这里将调用taskYIELD(),本task自己主动让出cpu,供其他task使用(gliethttp).
taskYIELD();
}
}
阅读全文
0 0
- 浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现
- 浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现
- 浅析FreeRTOS_v4.5.0的任务切换原理和栈结构
- vTaskDelay
- vTaskDelay
- vTaskDelay
- Twisted的延时处理机制
- linux内核的延时机制
- Atlas 实现机制浅析
- Atlas 实现机制浅析
- handler消息机制实现延时显示或延时关闭
- 精确延时的实现
- jquery的ready事件的实现机制浅析
- Atlas 实现机制浅析 [1]
- Atlas 实现机制浅析 [2]
- Atlas 实现机制浅析 [3]
- PB多线程的缺陷与实现机制浅析
- 系统的延时及定时机制
- SQL(高级查询)
- 收藏经典云计算blog---持续发现、持续更新
- XML解析2(SAX)
- Redis之集群原理和配置
- java线程同步,等待,2线程切换轮流执行 笔记
- 浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现
- java之File用法
- HTML5基础,第3部分:HTML5 API的威力
- Map Graticule——地图坐标网
- Renesas CS+ for ca cx入门(一)
- TensorFlow 1.0源码编译安装
- C语言实现三子棋
- tomcat无法正常启动的原因
- Android ORM 框架:GreenDao 数据库升级