/*\r
- FreeRTOS.org V4.0.5 - Copyright (C) 2003-2006 Richard Barry.\r
+ FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.\r
\r
This file is part of the FreeRTOS.org distribution.\r
\r
functions exiting when a block time remains and the function has\r
not completed.\r
\r
+Changes from V4.1.2:\r
+\r
+ + BUG FIX: Removed the call to prvIsQueueEmpty from within xQueueCRReceive\r
+ as it exited with interrupts enabled. Thanks Paul Katz.\r
+\r
+Changes from V4.1.3:\r
+\r
+ + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) \r
+ case whereby a task unblocking due to a temporal event can remove/send an \r
+ item from/to a queue when a higher priority task is still blocked on the \r
+ queue. This modification is a result of the SafeRTOS testing.\r
*/\r
\r
#include <stdlib.h>\r
\r
signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
{\r
-signed portBASE_TYPE xReturn;\r
+signed portBASE_TYPE xReturn = pdPASS;\r
xTimeOutType xTimeOut;\r
\r
/* Make sure other tasks do not access the queue. */\r
{\r
taskYIELD();\r
}\r
+\r
+ /* We want to check to see if the queue is still full\r
+ before leaving the critical section. This is to prevent\r
+ this task placing an item into the queue due to an\r
+ interrupt making space on the queue between critical\r
+ sections (when there might be a higher priority task\r
+ blocked on the queue that cannot run yet because the\r
+ scheduler gets suspended). */\r
+ if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )\r
+ {\r
+ /* We unblocked but there is no space in the queue,\r
+ we probably timed out. */\r
+ xReturn = errQUEUE_FULL;\r
+ }\r
\r
/* Before leaving the critical section we have to ensure\r
exclusive access again. */\r
}\r
}\r
\r
- /* When we are here it is possible that we unblocked as space became\r
- available on the queue. It is also possible that an ISR posted to the\r
- queue since we left the critical section, so it may be that again there\r
- is no space. This would only happen if a task and ISR post onto the\r
- same queue. */\r
- taskENTER_CRITICAL();\r
+ /* If xReturn is errQUEUE_FULL then we unblocked when the queue\r
+ was still full. Don't check it again now as it is possible that\r
+ an interrupt has removed an item from the queue since we left the\r
+ critical section and we don't want to write to the queue in case\r
+ there is a task of higher priority blocked waiting for space to\r
+ be available on the queue. If this is the case the higher priority\r
+ task will execute when the scheduler is unsupended. */\r
+ if( xReturn != errQUEUE_FULL )\r
{\r
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+ /* When we are here it is possible that we unblocked as space became\r
+ available on the queue. It is also possible that an ISR posted to the\r
+ queue since we left the critical section, so it may be that again there\r
+ is no space. This would only happen if a task and ISR post onto the\r
+ same queue. */\r
+ taskENTER_CRITICAL();\r
{\r
- /* There is room in the queue, copy the data into the queue. */ \r
- prvCopyQueueData( pxQueue, pvItemToQueue ); \r
- xReturn = pdPASS;\r
- \r
- /* Update the TxLock count so prvUnlockQueue knows to check for\r
- tasks waiting for data to become available in the queue. */\r
- ++( pxQueue->xTxLock );\r
- }\r
- else\r
- {\r
- xReturn = errQUEUE_FULL;\r
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+ {\r
+ /* There is room in the queue, copy the data into the queue. */ \r
+ prvCopyQueueData( pxQueue, pvItemToQueue ); \r
+ xReturn = pdPASS;\r
+ \r
+ /* Update the TxLock count so prvUnlockQueue knows to check for\r
+ tasks waiting for data to become available in the queue. */\r
+ ++( pxQueue->xTxLock );\r
+ }\r
+ else\r
+ {\r
+ xReturn = errQUEUE_FULL;\r
+ }\r
}\r
+ taskEXIT_CRITICAL();\r
}\r
- taskEXIT_CRITICAL();\r
\r
if( xReturn == errQUEUE_FULL )\r
{\r
\r
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
{\r
-signed portBASE_TYPE xReturn;\r
+signed portBASE_TYPE xReturn = pdTRUE;\r
xTimeOutType xTimeOut;\r
\r
/* This function is very similar to xQueueSend(). See comments within\r
{\r
taskYIELD();\r
}\r
+\r
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
+ {\r
+ /* We unblocked but the queue is empty. We probably\r
+ timed out. */\r
+ xReturn = errQUEUE_EMPTY;\r
+ }\r
\r
vTaskSuspendAll();\r
prvLockQueue( pxQueue );\r
}\r
}\r
\r
- taskENTER_CRITICAL();\r
+ if( xReturn != errQUEUE_EMPTY )\r
{\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
+ taskENTER_CRITICAL();\r
{\r
- pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
{\r
- pxQueue->pcReadFrom = pxQueue->pcHead;\r
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+ {\r
+ pxQueue->pcReadFrom = pxQueue->pcHead;\r
+ }\r
+ --( pxQueue->uxMessagesWaiting );\r
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
+ \r
+ /* Increment the lock count so prvUnlockQueue knows to check for\r
+ tasks waiting for space to become available on the queue. */\r
+ ++( pxQueue->xRxLock );\r
+ xReturn = pdPASS;\r
+ }\r
+ else\r
+ {\r
+ xReturn = errQUEUE_EMPTY;\r
}\r
- --( pxQueue->uxMessagesWaiting );\r
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
- \r
- /* Increment the lock count so prvUnlockQueue knows to check for\r
- tasks waiting for space to become available on the queue. */\r
- ++( pxQueue->xRxLock );\r
- xReturn = pdPASS;\r
- }\r
- else\r
- {\r
- xReturn = errQUEUE_EMPTY;\r
}\r
+ taskEXIT_CRITICAL();\r
}\r
- taskEXIT_CRITICAL();\r
\r
if( xReturn == errQUEUE_EMPTY )\r
{\r
between the check to see if the queue is empty and blocking on the queue. */\r
portDISABLE_INTERRUPTS();\r
{\r
- if( prvIsQueueEmpty( pxQueue ) )\r
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
{\r
/* There are no messages in the queue, do we want to block or just\r
leave with nothing? */ \r