xQueueReceive without a buffer?

jorick23 wrote on Friday, April 17, 2009:

I have an interesting problem that I don’t think I’ve seen in the forum.

I have a task that’s sending a buffer of data to another task via a queue.  The buffer is 200 bytes long and is sent very infrequently. 

Due to space constraints, both the sending and receiving tasks allocate buffers to hold their data and free them as soon as possible.  For the sending task, that’s not a problem.  It allocates a buffer, fills it, sends it via an xQueueSend, and then frees the buffer.

The problem is with the receiving task.  It’s blocked waiting for the queue, and it doesn’t have a buffer waiting because it takes up too much space.

Ideally, when the task becomes unblocked, it would allocate a buffer to hold the data and then receive it.  This could be done with xQueuePeek to wait for the queue to come in, and then the task could allocate a buffer and use xQueueReceive to retrieve the data into the newly allocated buffer.

But the problem is that xQueuePeek also requires a buffer pointer, and the buffer hasn’t been allocated at this point.  I can’t send it a null pointer because that would point to the exception vector table in RAM and blow it out of the water.

So I have a few things I could do:

1.  Ask the denizens of the FreeRTOS forum if I’m missing something and there’s a simple way of doing this.

2.  Add one line of code to Queue.c that would check for a null pointer right before the copy and skip the copy if null.  This would let me use xQueuePeek to wait for a queue without wasting valuable resources.  This would also let me use xQueueReceive to discard an unwanted queue item using a null pointer (a very nice feature!).

3.  If there isn’t an easier way to do this, ask Richard Barry if he would be so kind as to add this feature into the next release.

I suppose I could send xQueuePeek a pointer to the start of ROM so that it would dump the data into the bit bucket.  But I don’t think that’s a very good idea since it would waste the cycles performing the copy.

I’ve already checked the xQueueReceive code (which also handles xQueuePeek) and it does the copy regardless.  I even checked the implementation of memcpy in IAR EWARM v4.42 and it does the copy as well (expected, since I moved the exception vector table to address 0 in RAM using memcpy).

I’m currently using FreeRTOS version 5.0.0.



alainm3 wrote on Friday, April 17, 2009:

Just my humble opinion:

greate a queue of pointers (2/4 bytes), allocate the buffer it in the sender thread and dealocate it in the receiving thread.

Pros: only one buffer *total*, important as you said that memory is small.

Cons: it looks like this is frowned upon in embeddeds… but if used with care it is no problem.


davedoors wrote on Friday, April 17, 2009:

I agree with Alain with the added reason that doing that way (queueing pointers) is also much faster.

richard_damon wrote on Friday, April 17, 2009:

As others have said, normally only small items should be passed on a queue since they are passed by value.

I would also add that if you are so low on available memory that the receiving task can’t have a buffer available sounds like that buffer really shouldn’t be dynamically allocated (unless the total lose of that data packet is ok). Dynamic memory allocations in a tight memory situation is fraught with peril as it is very hard to prove ahead of time that a needed memory block will always be available. Pre-allocating the blocks helps to make sure you always have it when you need it, then you just need to prove that the block gets back to you in time.

jorick23 wrote on Friday, April 17, 2009:

Thanks for the help from everyone.  Sending the pointer solved the problem.