Is portMAX_DELAY required to be 0xFFFFFFFF for a 32-bit tick? What happens if this timeout is actually reached for an xQueueReceive() call?
Here's the background:
I have several tasks that call xQueueRecieve on a queue with a timeout of portMAX_DELAY. One task (a console processor) is expected to routinely reach the 32-bit timeout, others are expected to never reach it. I was testing that the one that is routinely supposed to reach the portMAX_DELAY timeout work correctly. A portMAX_DELAY of 0xFFFFFFFF is 49.7 days for me. I didn't want to wait that long for my test, so I set it to 10 minutes (600000 ticks). When I ran my app, ALL of my tasks that call xQueueReceive() with portMAX_DELAY locked up, even the ones that were successfully receiving from the queue for the entire 10 minutes. The one task that I was testing (the one that was blocked for the entire 10 minutes) is stuck in vListInsert() in the iteration loop. I'm guessing that's why the other tasks stopped working, and I'm also assuming all my other tasks have stopped working too. The only thing I can see running are raw console messages from within ISRs saying that none of my ISTs are running... I have a lot of experience with causing tasks to get stuck in vListInsert(), but not like this.
The behaviour of a block time of portMAX_DELAY depends on the setting of INCLUDE_vTaskSuspend() in FreeRTOSConfig.h. If the configuration constant is set to 1, then portMAX_DELAY will cause the task to block indefinitely. This means a function call that uses a block time of portMAX_DELAY need not check the return type of the blocking function call, because if the call returns, the task is guaranteed that the event it was waiting for has occurred. For examples:
xQueueReceive( xQueue, &buffer, portMAX_DELAY );
ProceessReceivedData( buffer );
is guaranteed to have something in buffer when ProcessReceivedData() is called.
If INCLUDE_vTaskSuspend is set to 0, then portMAX_DELAY is just a delay as any other. That means you have to check the return type of the blocking function call to determine if the function returned because the event occurred, or because the timeout occurred. Therefore you would write you code as follows:
while( xQueueReceive( xQueue, &buffer, portMAX_DELAY ) != pdPASS );
ProcessReceivedData( buffer );
if you wanted to wait indefinitely, or
xReturned = xQueueReceive( xQueue, &buffer, portMAX_DELAY );
if( xReturned == pdTRUE )
ProcessReceivedData( buffer );
if you didn't want to wait indefinitely.
“he one task that I was testing (the one that was blocked for the entire 10 minutes) is stuck in vListInsert() ”
Have you checked the items on the following FAQ page:
“I'm guessing that's why the other tasks stopped working, and I'm also assuming all my other tasks have stopped working too. ”
It depends on which vListInsert() you are talking about, but if it is one of the ones in tasks.c, if a task was spinning in it, then other tasks would not execute.
I understand how the portMAX_DELAY is supposed to work. My question is more related to choosing a different value for it, instead of 0xFFFFFFFF. Is this allowed? What impact will it have on how timeouts are handled?
I'm mostly interested in verifying the FreeRTOS kernel behavior at the boundary condition where portMAX_DELAY is reached. Are there test cases already written that verify this? If not, how would the test cases go about testing it, waiting for 50 days or modifying the portMAX_DELAY value?
I know that xQueueReceive() is supposed to be guaranteed not to return if you use portMAX_DELAY, but I would like to see it with my own eyes (preferably without waiting for 50 days).
This was tested and analysed quite extensively when SafeRTOS was created. Although that was some time ago the details of that part of the code has not changed. If you look back through the change history (several years) you may be able to identify the two version numbers where a change was made to correct a corner case that was not handled quite correctly (that had about a one in several billion billion chance of occurring because it only happened when the tick count overflowed). The change history is http://www.FreeRTOS.org/History.txt.
With regards to manually modifying the tick count/delay periods: Static module tests are much easier because you can manually crank the tick count over at the fastest speed your computer can run, rather than having to wait the actual amount of time (this is how most testing is done). If you want to manually change the tick count value then do it before you make the blocking call, so the wake time is relative to the (manually) modified tick count. I don't see any reason why the tick count value could not be initialised to a high number rather than 0 in the first place (writing without actually trying it).