【RTOS】RTOS源码基础之队列结构体
前言
以下 RTOS 是基于 FreeRTOS 源码分析。
建议直接看源码去了解。
李柱明博客:https://www.cnblogs.com/lizhuming/p/15487239.html
IPC
本人认为在学习 RTOS 任务间通信时必须了解的一个结构体就是 struct QueueDefinition
,其源码参考 附件-源码。
该结构体被运用到消息队列、二进制信号量、计数信号量、互斥量和递归互斥量等等关于任务间通信的控件。
这些控件在系统中都是由 控制块 + 存储区 组成,而该结构体就是控制块的角色,管理其对应的存储区。
成员剖析
在成员剖析时默认按消息队列的作用去剖析。
int8_t *pcHead;
:
/* 该队列存储区的起始位置,对应第一个消息空间。*/
int8_t *pcHead;
int8_t *pcTail;
:
/* 消息队列存储区的结尾位置。
* 结合 pcHead 指针就是整个存储区合法区域。*/
int8_t *pcHead;
int8_t *pcWriteTo;
:
/* 写指针,指向存储区中下一个空闲的空间。
* 队列下次写数据的位置,需要入队时调用该指针写入数据。*/
int8_t *pcWriteTo;
int8_t *pcReadFrom;
:
/* 读指针,指向存储区中下一个有效数据的空间。
* 队列下次读取数据的位置,需要出队时调用该指针写入数据。*/
int8_t *pcReadFrom;
UBaseType_t uxRecursiveCallCount;
:
/* 递归次数。
* 用于互斥量时使用,与 pcReadFrom 为联合体。
* 记录递归互斥量被调用的次数。 */
UBaseType_t uxRecursiveCallCount;
List_t xTasksWaitingToSend;
:
/* 等待发送的任务列表。
* 当队列存储区满时,需要发送消息的任务阻塞时记录到该链表。
* 按任务优先级排序。 */
List_t xTasksWaitingToSend;
List_t xTasksWaitingToReceive;
:
/* 等待接收的任务列表。
* 当队列存储区为空时,需要获取消息的任务阻塞时记录到该链表。
* 按任务优先级排序。 */
List_t xTasksWaitingToReceive;
volatile UBaseType_t uxMessagesWaiting;
:
/* 当前消息节点的个数。
* 即是当前有效消息数量。
* 二值信号量、互斥信号量时:表示有无信号量可用。
* 计数信号量时:有效信号量个数。 */
volatile UBaseType_t uxMessagesWaiting;
UBaseType_t uxLength;
:
/* 当前队列最大节点总数。
* 即是最多能存放多少个消息。
* 二值信号量、互斥信号量时:最大为1。
* 计数信号量时:最大的信号量个数。 */
UBaseType_t uxLength;
UBaseType_t uxItemSize;
:
/* 单个节点的大小。
* 单个消息的大小。
* 二值信号量、互斥信号量时:0。
* 计数信号量时:0。 */
UBaseType_t uxItemSize;
volatile int8_t cRxLock;
:
/* 记录出队的数据项个数。
* 即是需要解除多少个阻塞在接收等待列表中的任务。 */
volatile int8_t cRxLock;
volatile int8_t cTxLock;
:
/* 记录入队的数据项个数。
* 即是需要解除多少个阻塞在发送等待列表中的任务。 */
volatile int8_t cTxLock;
cRxLock 和 cTxLock
当中断服务程序操作队列并且导致阻塞的任务解除阻塞时。
首先判断该队列是否上锁:
- 如果没有上锁,则解除被阻塞的任务,还会根据需要设置上下文切换请求标志;
- 如果队列已经上锁,则不会解除被阻塞的任务,取而代之的是,将 xRxLock 或 xTxLock 加 1,表示队列上锁期间出队或入队的数目,也表示有任务可以解除阻塞了。
cRxLock
对应待出队的个数。
cTxLock
对应待入队的个数。
触发解除阻塞
触发解除阻塞的方式:
-
收发消息。
- 即是数据项出入队时,会触发阻塞的任务解除阻塞。
-
超时。
- 超时也会触发对应的阻塞任务解除阻塞。
-
解锁后处理上锁时未处理的出入队。
- cRxLock 和 cTxLock。
附件-源码
/*
* Definition of the queue used by the scheduler.
* Items are queued by copy, not reference. See the following link for the
* rationale: http://www.freertos.org/Embedded-RTOS-Queues.html
*/
typedef struct QueueDefinition
{
int8_t *pcHead; /*< Points to the beginning of the queue storage area. */
int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
int8_t *pcWriteTo; /*< Points to the free next place in the storage area. */
union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */
{
int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */
UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */
} u;
List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
List_t xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */
UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */
volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
#endif
#if ( configUSE_QUEUE_SETS == 1 )
struct QueueDefinition *pxQueueSetContainer;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
} xQUEUE;