队列必须掌握,这是其它的基石,不理解这个,其它的源码也看不懂。
queue.c、queue.h
队列结构体:
typedef struct QueueDefinition
{
int8_t *pcHead; // 队列存储区开始地址
int8_t *pcWriteTo; // 指向存储区下一个空闲区域
union
{
QueuePointers_t xQueue; // 作为队列时的值
SemaphoreData_t xSemaphore; // 作为信号量时的值
} u;
List_t xTasksWaitingToSend; // 写阻塞链表,按优先级存储
List_t xTasksWaitingToReceive; // 读阻塞链表,按优先级存储
volatile UBaseType_t uxMessagesWaiting; // 目前队列中的消息数量
UBaseType_t uxLength; // 队列的长度
UBaseType_t uxItemSize; // 队列元素的字节大小
volatile int8_t cRxLock; // 队列上锁后,出队列的元素个数,没上锁则为queueUNLOCKED
volatile int8_t cTxLock; // 队列上锁后,入队列的元素个数,没上锁则为queueUNLOCKED
#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;
typedef xQUEUE Queue_t;动态方式创建队列
静态方式创建队列
队列写消息
注意结构体中的读写阻塞列表
先不考虑队列集:
BaseType_t xQueueGenericSend(QueueHandle_t xQueue, // 队列
const void *const pvItemToQueue, //
TickType_t xTicksToWait, // 超时时间
const BaseType_t xCopyPosition) //
{
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
TimeOut_t xTimeOut;
Queue_t *const pxQueue = xQueue;
for (;;)
{
taskENTER_CRITICAL();
{
// 1.判断是否有剩余空间 2.如果队列采用覆写方式则不用管是否已满
if ((pxQueue->uxMessagesWaiting < pxQueue->uxLength) || (xCopyPosition == queueOVERWRITE))
{
// 值拷贝到队列中
xYieldRequired = prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);
// 判断是否有任务在读等待队列消息而阻塞
if (listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE)
{ // 有任务在等待
// 取消任务阻塞,添加任务到就绪列表
xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive));
}
else if (xYieldRequired != pdFALSE)
{
/* This path is a special case that will only get
* executed if the task was holding multiple mutexes and
* the mutexes were given back in an order that is
* different to that in which they were taken. */
queueYIELD_IF_USING_PREEMPTION();
}
taskEXIT_CRITICAL();
return pdPASS;
}
else // 如果队列满了
{
if (xTicksToWait == (TickType_t)0)
{
// 阻塞超时为0则直接返回
taskEXIT_CRITICAL();
// traceQUEUE_SEND_FAILED(pxQueue);
return errQUEUE_FULL;
}
else if (xEntryTimeSet == pdFALSE) // 如果没有设置过期时间
{
// 阻塞时间不为0则初始化超时时间结构体
vTaskInternalSetTimeOutState(&xTimeOut);
xEntryTimeSet = pdTRUE;
}
}
}
taskEXIT_CRITICAL();
/* Interrupts and other tasks can send to and receive from the queue
* now the critical section has been exited. */
// 关闭任务调度
vTaskSuspendAll();
// 队列上锁
prvLockQueue(pxQueue);
// 更新时间并检查是否超时
if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE)
{ // 未超时
if (prvIsQueueFull(pxQueue) != pdFALSE)
{ // 队列满了
// traceBLOCKING_ON_QUEUE_SEND(pxQueue);
/* 将当前任务的事件列表项加入到队列的等待发送列表中 */
/* 将当前任务的状态列表项从就绪列表中移除,将其加入到延时列表中 */
vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToSend), xTicksToWait);
/* Unlocking the queue means queue events can effect the
* event list. It is possible that interrupts occurring now
* remove this task from the event list again - but as the
* scheduler is suspended the task will go onto the pending
* ready list instead of the actual ready list. */
// 队列解锁
prvUnlockQueue(pxQueue);
/* Resuming the scheduler will move tasks from the pending
* ready list into the ready list - so it is feasible that this
* task is already in the ready list before it yields - in which
* case the yield will not cause a context switch unless there
* is also a higher priority task in the pending ready list. */
// 恢复任务调度
if (xTaskResumeAll() == pdFALSE)
{
portYIELD_WITHIN_API();
}
}
else
{
// 解锁,再试一次
prvUnlockQueue(pxQueue);
(void)xTaskResumeAll();
}
}
else
{
// 超时
prvUnlockQueue(pxQueue);
(void)xTaskResumeAll();
return errQUEUE_FULL;
}
} // For End
} // Function End值拷贝函数 prvCopyDataToQueue 的实现: