大概记录下这个函数的过程以便于继续分析,类似于伪代码
xQueue: 队列句柄,指明要向哪个队列发送数据,创建队列成功以后会返回此队列的 队列句柄。
pvItemToQueue:指向要发送的消息,发送的过程中会将这个消息拷贝到队列中。
xTicksToWait : 阻塞时间。
xCopyPosition: 入队方式
有三种入队方式:
queueSEND_TO_BACK: 后向入队
queueSEND_TO_FRONT: 前向入队
queueOVERWRITE: 覆写入队。
队列结构体主要部分(省略了队列集):
进入临界段后:
uxMessagesWaiting<uxLength 判断队列是否满,(或覆写入队不考虑这个,但是一般不用覆写入队)
1 若队列满,且没有阻塞时间,直接退出临界段返回队列满。
2 若队列未满,则写memcpy入队,分为前入队 后入队 覆写入队 (deemo用的back)
后:写入位置:pcWriteTo //初始化为队列起始pcHead。 随后更新pcWriteTo
前:写入位置:u.pcReadFrom //初始化为队列末尾pcTail(-1)。随后更新u.pcReadFrom
覆写:写入位置:u.pcReadFrom //初始化为队列末尾 ,随后更新u.pcReadFrom并uxMessagesWaiting-- 因为覆写不会改变长度
最后更新uxMessagesWaiting。当前队列中消息数
入队之后,相当于更新了队列,需要判断等待消息阻塞列表 list中 ,有没有在等消息的任务,
有的话,因为刚刚消息已经入队了,可以将其移除并放到就绪任务列表中,判断移除的任务与当前任务的优先级,是否进行任务切换。
(若需要,则立即进行任务切换pendSV,与xTaskIncrementTick不同,这个是执行完之后再切换)
假如此时调度器上锁,则不判断优先级并将其放到挂起就绪列表。//uxSchedulerSuspended判断是否上锁
以上涉及到的几个list:
xTasksWaitingToReceive (xTimerQueue成员)//等待消息阻塞列表 ,或称等待接受消息的任务列表
pxReadyTasksLists(全局)// 就绪列表,注意是加到对应优先级的就绪列表
xPendingReadyList(全局)//挂起就绪列表
从列表中移除任务的过程:先获取TCB,( (&( ( xTasksWaitingToSend )->xListEnd ))->pxNext->pvOwner )
然后链表操作,删除TCB中的事件列表项 xEventListItem(列表项知道自己在那个列表,调度过程中会判断是否在等待某个事件,删除为NULL)
(列表按照升值排列列表项)
在这里退出临界段。
3 若队列满,且设置了阻塞时间,阻塞时间为最大值
任务挂起vTaskSuspendAll,队列上锁,将状态列表项 pxCurrentTCB->xGenericListItem挂到挂起列表xSuspendedTaskList 队列上锁
4若队列满,且设置了阻塞时间,阻塞时间为某个值
任务挂起vTaskSuspendAll,队列上锁,将状态列表项 pxCurrentTCB->xGenericListItem挂到延时列表pxDelayedTaskList, 队列上锁并开始等待
有关延时列表和溢出延时列表暂不展开
等待:检测队列是否满,检测是否到达预定阻塞时间
计时方式:
获取当前xTickCount 以及xNumOfOverflows
判断当前时间是否达到预计时间, 若达到解锁队列,恢复调度器xTaskResumeAll
预计时间xTicksToWait会在每次获取xTickCount 后更新减少。因为后续会会在新的xTickCount 的基础上计算xTimeToWake
xTickCount 是系统滴答定时器会在中断服务里递增。(xTaskIncrementTick)
若在等待的过程中,队列有空闲,解锁队列,恢复调度器(每次进入 入队函数会尝试发送,try again)
以上涉及到的list
挂起列表xSuspendedTaskList
延时列表pxDelayedTaskList
溢出延时列表pxOverflowDelayedTaskList