Understanding queue messages

I’m trying to understand how queues work. I have been looking at the code and I see the structure of the queue contains the pointers pcHead, pcWriteTo, and pcReadFrom in addition to a few others.
The queue is created as follows:

pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );
  • and then it moves the pointer pucQueueStorage to the next Queue_t, but why so? aren’t we supposed to have one queue that contains defined number of structs?
pucQueueStorage = ( uint8_t * ) pxNewQueue;
pucQueueStorage += sizeof ( Queue_t ); 
  • for copying to the queue, we have:
( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); 

so it’s copying the pvItemToQueue into the memory pointed to by pcWriteTo but how does it work with structs?

and for reading off the queue:

( void ) memcpy( ( void * ) pvBuffer, ( void* ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); 

so I initialized the buffer of the struct and after calling xQueueSendToBackFromISR(), looks like the contents of the buffer are copied into pcWriteTo, and upon reading off of it into a local struct, I see the buffer gets initialized.

My question is: how does buffer get initialized even though the reference of msg is being passed in?

For a reference, the struct looks like:

typedef struct {
   char buffer[20];
} msg;

I tried a sample program to simulate the behaviour but not sure if it’s working:

You can read a little more about queues here, https://www.freertos.org/Embedded-RTOS-Queues.html, and probably in the free-to-download book.

If each structure is 20 bytes long, and you want to send the whole structure to the queue, then each space in the queue needs to be 20 bytes long. Then the structure is simply copied into the queue storage area when you send to the queue and out of the queue storage area when you read from the queue. This is “queue by copy” - but as described on the link above, you can also queue by reference, in which case you just queue a pointer to the structure. Then each space in the queue should be four bytes (assuming pointers on your MCU are four bytes, as would be the case on an ARM Cortex-M), and you copy a pointer to the structure into and out of the queue instead of copying the entire structure.

Queuing the structures themselves is easier from the application writers point of view as the sender can write over the structure immediately after sending to the queue. Queuing pointers to the structures uses less RAM and is moderately faster, but harder from the application writers point of view as you have to keep track of who ‘owns’ the memory being pointed to.

I think I’m okay with the high level view of queues which is described in the link you shared. I’m more interested in the underlying implementation

Queue_t is metadata about the queue which in addition to other items, contains the following two items:

int8_t *pcHead;       /*< Points to the beginning of the queue storage area. */
int8_t *pcWriteTo;    /*< Points to the free next place in the storage area. */

The memory is allocated both for Queue_t and the Queue items. First, Queue_t is placed followed by Queue items. The following lines initialize the pcHead and pcWriteTo members of Queue_t for a new queue:

The memory layout for a new queue looks like the following:

           Queue_t                 Queue Storage Area
     |                 |         |         |        |         |
     |                 |         |         |        |         |
     |                 |         |         |        |         |

After putting one item in the queue, the memory layout looks like the following:

	       Queue_t                 Queue Storage Area
     |                 |         |         |        |         |
     |                 |  Item1  |         |        |         |
     |                 |         |         |        |         |
	                   ^         ^
					   |         |
	 pcHead------------+         |


Thanks for the detailed response.

So queue storage area is mainly to store the items? what about Queue_t itself?

It is the definition of the Queue used by the scheduler. Here is the definition of Queue_t: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/master/queue.c#L98


The Queue_t is the ‘control’ part of the Queue, it holds the pointers into the data area, and other information needed by the scheduler and other parts to make everything work. It has the same structure for all Queue. After it is the ‘data’ section, where the data that is put on the queue is stored.