/*\r
- FreeRTOS.org V4.1.0 - Copyright (C) 2003-2006 Richard Barry.\r
+ FreeRTOS.org V4.7.0 - Copyright (C) 2003-2007 Richard Barry.\r
\r
This file is part of the FreeRTOS.org distribution.\r
\r
See http://www.FreeRTOS.org for documentation, latest information, license\r
and contact details. Please ensure to read the configuration and relevant\r
port sections of the online documentation.\r
- ***************************************************************************\r
-*/\r
-\r
-/*\r
-Changes from V1.01\r
-\r
- + More use of 8bit data types.\r
- + Function name prefixes changed where the data type returned has changed.\r
-\r
-Changed from V2.0.0\r
-\r
- + Added the queue locking mechanism and make more use of the scheduler\r
- suspension feature to minimise the time interrupts have to be disabled\r
- when accessing a queue.\r
-\r
-Changed from V2.2.0\r
-\r
- + Explicit use of 'signed' qualifier on portCHAR types added.\r
-\r
-Changes from V3.0.0\r
-\r
- + API changes as described on the FreeRTOS.org WEB site.\r
-\r
-Changes from V3.2.3\r
-\r
- + Added the queue functions that can be used from co-routines.\r
-\r
-Changes from V4.0.5\r
-\r
- + Added a loop within xQueueSend() and xQueueReceive() to prevent the\r
- functions exiting when a block time remains and the function has\r
- not completed.\r
\r
+ Also see http://www.SafeRTOS.com a version that has been certified for use\r
+ in safety critical systems, plus commercial licensing, development and\r
+ support options.\r
+ ***************************************************************************\r
*/\r
\r
#include <stdlib.h>\r
#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )\r
#define queueERRONEOUS_UNBLOCK ( -1 )\r
\r
+/* For internal use only. */\r
+#define queueSEND_TO_BACK ( 0 )\r
+#define queueSEND_TO_FRONT ( 1 )\r
+\r
+/* Effectively make a union out of the xQUEUE structure. */\r
+#define pxMutexHolder pcTail\r
+#define uxQueueType pcHead\r
+#define queueQUEUE_IS_MUTEX NULL\r
+\r
+/* Semaphores do not actually store or copy data, so have an items size of\r
+zero. */\r
+#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( 0 )\r
+#define queueDONT_BLOCK ( ( portTickType ) 0 )\r
+\r
/*\r
* Definition of the queue used by the scheduler.\r
* Items are queued by copy, not reference.\r
xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */\r
xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */\r
\r
- unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
+ volatile unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */\r
unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */\r
unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */\r
\r
- signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
- signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
+ signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
+ signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */\r
} xQUEUE;\r
/*-----------------------------------------------------------*/\r
\r
* functions are documented in the API header file.\r
*/\r
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );\r
-signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );\r
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );\r
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue );\r
void vQueueDelete( xQueueHandle xQueue );\r
-signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );\r
-signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition );\r
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );\r
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );\r
+xQueueHandle xQueueCreateMutex( void );\r
+xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount );\r
+signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );\r
+signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );\r
\r
#if configUSE_CO_ROUTINES == 1\r
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );\r
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );\r
\r
/*\r
- * Macro that copies an item into the queue. This is done by copying the item\r
- * byte for byte, not by reference. Updates the queue state to ensure it's\r
- * integrity after the copy.\r
+ * Copies an item into the queue, either at the front of the queue or the\r
+ * back of the queue.\r
*/\r
-#define prvCopyQueueData( pxQueue, pvItemToQueue ) \\r
-{ \\r
- memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \\r
- ++( pxQueue->uxMessagesWaiting ); \\r
- pxQueue->pcWriteTo += pxQueue->uxItemSize; \\r
- if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \\r
- { \\r
- pxQueue->pcWriteTo = pxQueue->pcHead; \\r
- } \\r
-}\r
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition );\r
+\r
+/*\r
+ * Copies an item out of a queue.\r
+ */\r
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer );\r
/*-----------------------------------------------------------*/\r
\r
/*\r
}\r
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
+#if ( configUSE_MUTEXES == 1 )\r
+\r
+ xQueueHandle xQueueCreateMutex( void )\r
+ {\r
+ xQUEUE *pxNewQueue;\r
+ \r
+ /* Allocate the new queue structure. */\r
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );\r
+ if( pxNewQueue != NULL )\r
+ {\r
+ /* Information required for priority inheritance. */\r
+ pxNewQueue->pxMutexHolder = NULL;\r
+ pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;\r
+ \r
+ /* Queues used as a mutex no data is actually copied into or out\r
+ of the queue. */\r
+ pxNewQueue->pcWriteTo = NULL;\r
+ pxNewQueue->pcReadFrom = NULL;\r
+ \r
+ /* Each mutex has a length of 1 (like a binary semaphore) and\r
+ an item size of 0 as nothing is actually copied into or out\r
+ of the mutex. */\r
+ pxNewQueue->uxMessagesWaiting = 0;\r
+ pxNewQueue->uxLength = 1;\r
+ pxNewQueue->uxItemSize = 0;\r
+ pxNewQueue->xRxLock = queueUNLOCKED;\r
+ pxNewQueue->xTxLock = queueUNLOCKED;\r
+ \r
+ /* Ensure the event queues start with the correct state. */\r
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
+\r
+ /* Start with the semaphore in the expected state. */\r
+ xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );\r
+ }\r
+ \r
+ return pxNewQueue;\r
+ }\r
+\r
+#endif /* configUSE_MUTEXES */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if configUSE_COUNTING_SEMAPHORES == 1\r
+\r
+ xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount )\r
+ {\r
+ xQueueHandle pxHandle;\r
+ \r
+ pxHandle = xQueueCreate( ( unsigned portBASE_TYPE ) uxCountValue, queueSEMAPHORE_QUEUE_ITEM_LENGTH );\r
+\r
+ if( pxHandle != NULL )\r
+ {\r
+ pxHandle->uxMessagesWaiting = uxInitialCount;\r
+ }\r
+\r
+ return pxHandle;\r
+ }\r
+\r
+#endif /* configUSE_COUNTING_SEMAPHORES */\r
+/*-----------------------------------------------------------*/\r
+\r
+signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\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
queue being modified here. Places where the event list is modified\r
include:\r
\r
- + xQueueSendFromISR(). This checks the lock on the queue to see if\r
- it has access. If the queue is locked then the Tx lock count is\r
+ + xQueueGenericSendFromISR(). This checks the lock on the queue to see\r
+ if it has access. If the queue is locked then the Tx lock count is\r
incremented to signify that a task waiting for data can be made ready\r
once the queue lock is removed. If the queue is not locked then\r
a task can be moved from the event list, but will not be removed\r
from the delayed list or placed in the ready list until the scheduler\r
is unlocked.\r
\r
- + xQueueReceiveFromISR(). As per xQueueSendFromISR().\r
+ + xQueueReceiveFromISR(). As per xQueueGenericSendFromISR().\r
*/\r
\r
/* If the queue is already full we may have to block. */\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
- {\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
+ /* 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
- xReturn = errQUEUE_FULL;\r
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+ {\r
+ /* There is room in the queue, copy the data into the queue. */ \r
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\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
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )\r
+#if configUSE_ALTERNATIVE_API == 1\r
+\r
+ signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition )\r
+ {\r
+ signed portBASE_TYPE xReturn;\r
+ xTimeOutType xTimeOut;\r
+\r
+ /* The source code that implements the alternative (Alt) API is much \r
+ simpler because it executes everything from within a critical section. \r
+ This is the approach taken by many other RTOSes, but FreeRTOS.org has the \r
+ preferred fully featured API too. The fully featured API has more \r
+ complex code that takes longer to execute, but makes much less use of \r
+ critical sections. Therefore the alternative API sacrifices interrupt \r
+ responsiveness to gain execution speed, whereas the fully featured API\r
+ sacrifices execution speed to ensure better interrupt responsiveness. */\r
+\r
+ taskENTER_CRITICAL();\r
+ {\r
+ /* Capture the current time status for future reference. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
+\r
+ /* If the queue is already full we may have to block. */\r
+ do\r
+ {\r
+ if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )\r
+ {\r
+ /* The queue is full - do we want to block or just leave without\r
+ posting? */\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
+ {\r
+ /* We are going to place ourselves on the xTasksWaitingToSend \r
+ event list, and will get woken should the delay expire, or \r
+ space become available on the queue. */\r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
+ \r
+ /* Force a context switch now as we are blocked. We can do\r
+ this from within a critical section as the task we are\r
+ switching to has its own context. When we return here (i.e.\r
+ we unblock) we will leave the critical section as normal. */\r
+ taskYIELD();\r
+ }\r
+ }\r
+ \r
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+ {\r
+ /* There is room in the queue, copy the data into the queue. */ \r
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
+ xReturn = pdPASS;\r
+\r
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
+ {\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
+ {\r
+ /* The task waiting has a higher priority. */\r
+ taskYIELD();\r
+ }\r
+ } \r
+ }\r
+ else\r
+ {\r
+ xReturn = errQUEUE_FULL;\r
+\r
+ if( xTicksToWait > 0 )\r
+ { \r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+ {\r
+ /* Another task must have accessed the queue between \r
+ this task unblocking and actually executing. */\r
+ xReturn = queueERRONEOUS_UNBLOCK;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ while( xReturn == queueERRONEOUS_UNBLOCK );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+\r
+ return xReturn;\r
+ }\r
+\r
+#endif /* configUSE_ALTERNATIVE_API */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if configUSE_ALTERNATIVE_API == 1\r
+\r
+ signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
+ {\r
+ signed portBASE_TYPE xReturn = pdTRUE;\r
+ xTimeOutType xTimeOut;\r
+ signed portCHAR *pcOriginalReadPosition;\r
+\r
+ /* The source code that implements the alternative (Alt) API is much \r
+ simpler because it executes everything from within a critical section. \r
+ This is the approach taken by many other RTOSes, but FreeRTOS.org has the \r
+ preferred fully featured API too. The fully featured API has more \r
+ complex code that takes longer to execute, but makes much less use of \r
+ critical sections. Therefore the alternative API sacrifices interrupt \r
+ responsiveness to gain execution speed, whereas the fully featured API\r
+ sacrifices execution speed to ensure better interrupt responsiveness. */\r
+\r
+ taskENTER_CRITICAL();\r
+ {\r
+ /* Capture the current time status for future reference. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
+\r
+ do\r
+ {\r
+ /* If there are no messages in the queue we may have to block. */\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
+ if( xTicksToWait > ( portTickType ) 0 )\r
+ {\r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ }\r
+ }\r
+ #endif\r
+ \r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
+ taskYIELD();\r
+ }\r
+ }\r
+ \r
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
+ {\r
+ /* Remember our read position in case we are just peeking. */\r
+ pcOriginalReadPosition = pxQueue->pcReadFrom;\r
+\r
+ prvCopyDataFromQueue( pxQueue, pvBuffer );\r
+\r
+ if( xJustPeeking == pdFALSE )\r
+ {\r
+ /* We are actually removing data. */\r
+ --( pxQueue->uxMessagesWaiting );\r
+ \r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ /* Record the information required to implement\r
+ priority inheritance should it become necessary. */\r
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
+ }\r
+ }\r
+ #endif\r
+\r
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
+ {\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
+ {\r
+ /* The task waiting has a higher priority. */\r
+ taskYIELD();\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* We are not removing the data, so reset our read\r
+ pointer. */\r
+ pxQueue->pcReadFrom = pcOriginalReadPosition;\r
+ }\r
+ \r
+ xReturn = pdPASS; \r
+ }\r
+ else\r
+ {\r
+ xReturn = errQUEUE_EMPTY;\r
+\r
+ if( xTicksToWait > 0 )\r
+ {\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+ {\r
+ xReturn = queueERRONEOUS_UNBLOCK;\r
+ }\r
+ }\r
+ }\r
+\r
+ } while( xReturn == queueERRONEOUS_UNBLOCK );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+\r
+ return xReturn;\r
+ }\r
+\r
+#endif /* configUSE_ALTERNATIVE_API */\r
+/*-----------------------------------------------------------*/\r
+\r
+signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition )\r
{\r
- /* Similar to xQueueSend, except we don't block if there is no room in the\r
- queue. Also we don't directly wake a task that was blocked on a queue\r
- read, instead we return a flag to say whether a context switch is required\r
- or not (i.e. has a task with a higher priority than us been woken by this\r
- post). */\r
+ /* Similar to xQueueGenericSend, except we don't block if there is no room\r
+ in the queue. Also we don't directly wake a task that was blocked on a\r
+ queue read, instead we return a flag to say whether a context switch is\r
+ required or not (i.e. has a task with a higher priority than us been woken\r
+ by this post). */\r
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
{\r
- prvCopyQueueData( pxQueue, pvItemToQueue );\r
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
\r
/* If the queue is locked we do not alter the event list. This will\r
be done when the queue is unlocked later. */\r
}\r
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
{\r
-signed portBASE_TYPE xReturn;\r
+signed portBASE_TYPE xReturn = pdTRUE;\r
xTimeOutType xTimeOut;\r
+signed portCHAR *pcOriginalReadPosition;\r
\r
- /* This function is very similar to xQueueSend(). See comments within\r
- xQueueSend() for a more detailed explanation.\r
+ /* This function is very similar to xQueueGenericSend(). See comments\r
+ within xQueueGenericSend() for a more detailed explanation.\r
\r
Make sure other tasks do not access the queue. */\r
vTaskSuspendAll();\r
leave with nothing? */ \r
if( xTicksToWait > ( portTickType ) 0 )\r
{\r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ portENTER_CRITICAL();\r
+ vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ portEXIT_CRITICAL();\r
+ }\r
+ }\r
+ #endif\r
+ \r
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
taskENTER_CRITICAL();\r
{\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
+ /* Remember our read position in case we are just peeking. */\r
+ pcOriginalReadPosition = pxQueue->pcReadFrom;\r
+\r
+ prvCopyDataFromQueue( pxQueue, pvBuffer );\r
+\r
+ if( xJustPeeking == pdFALSE )\r
+ {\r
+ /* We are actually removing data. */\r
+ --( pxQueue->uxMessagesWaiting );\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
+ \r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ /* Record the information required to implement\r
+ priority inheritance should it become necessary. */\r
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
+ }\r
+ }\r
+ #endif\r
+ }\r
+ else\r
+ {\r
+ /* We are not removing the data, so reset our read\r
+ pointer. */\r
+ pxQueue->pcReadFrom = pcOriginalReadPosition;\r
+\r
+ /* The data is being left in the queue, so increment the\r
+ lock count so prvUnlockQueue knows to check for other\r
+ tasks waiting for the data to be available. */\r
+ ++( pxQueue->xTxLock ); \r
+ }\r
+ \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
}\r
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken )\r
{\r
signed portBASE_TYPE xReturn;\r
\r
/* We cannot block from an ISR, so check there is data available. */\r
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
{\r
- /* Copy the data from the queue. */\r
- pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
- if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
- {\r
- pxQueue->pcReadFrom = pxQueue->pcHead;\r
- }\r
+ prvCopyDataFromQueue( pxQueue, pvBuffer );\r
--( pxQueue->uxMessagesWaiting );\r
- memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
\r
/* If the queue is locked we will not modify the event list. Instead\r
we update the lock count so the task that unlocks the queue will know\r
}\r
/*-----------------------------------------------------------*/\r
\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )\r
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue )\r
{\r
unsigned portBASE_TYPE uxReturn;\r
\r
}\r
/*-----------------------------------------------------------*/\r
\r
+static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition )\r
+{\r
+ if( pxQueue->uxItemSize == 0 )\r
+ {\r
+ #if ( configUSE_MUTEXES == 1 )\r
+ {\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ /* The mutex is no longer being held. */\r
+ vTaskPriorityDisinherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ }\r
+ }\r
+ #endif\r
+ }\r
+ else if( xPosition == queueSEND_TO_BACK )\r
+ {\r
+ memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
+ pxQueue->pcWriteTo += pxQueue->uxItemSize;\r
+ if( pxQueue->pcWriteTo >= pxQueue->pcTail )\r
+ {\r
+ pxQueue->pcWriteTo = pxQueue->pcHead;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize );\r
+ pxQueue->pcReadFrom -= pxQueue->uxItemSize;\r
+ if( pxQueue->pcReadFrom < pxQueue->pcHead )\r
+ {\r
+ pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );\r
+ } \r
+ }\r
+\r
+ ++( pxQueue->uxMessagesWaiting );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer )\r
+{\r
+ if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX )\r
+ {\r
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+ {\r
+ pxQueue->pcReadFrom = pxQueue->pcHead;\r
+ }\r
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
+ } \r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
static void prvUnlockQueue( xQueueHandle pxQueue )\r
{\r
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
signed portBASE_TYPE xReturn;\r
\r
/* If the queue is already full we may have to block. A critical section\r
- is required to prevent an interrupt removing something from the queue \r
+ is required to prevent an interrupt removing something from the queue\r
between the check to see if the queue is full and blocking on the queue. */\r
portDISABLE_INTERRUPTS();\r
{\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
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
xReturn = pdPASS;\r
\r
/* Were any co-routines waiting for data to become available? */\r
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
{\r
- /* In this instance the co-routine could be placed directly \r
- into the ready list as we are within a critical section. \r
- Instead the same pending ready list mechansim is used as if\r
+ /* In this instance the co-routine could be placed directly\r
+ into the ready list as we are within a critical section.\r
+ Instead the same pending ready list mechanism is used as if\r
the event were caused from within an interrupt. */\r
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
{\r
- /* The co-routine waiting has a higher priority so record \r
+ /* The co-routine waiting has a higher priority so record\r
that a yield might be appropriate. */\r
xReturn = errQUEUE_YIELD;\r
}\r
signed portBASE_TYPE xReturn;\r
\r
/* If the queue is already empty we may have to block. A critical section\r
- is required to prevent an interrupt adding something to the queue \r
+ is required to prevent an interrupt adding something to the queue\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
/* Were any co-routines waiting for space to become available? */\r
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
{\r
- /* In this instance the co-routine could be placed directly \r
- into the ready list as we are within a critical section. \r
- Instead the same pending ready list mechansim is used as if\r
+ /* In this instance the co-routine could be placed directly\r
+ into the ready list as we are within a critical section.\r
+ Instead the same pending ready list mechanism is used as if\r
the event were caused from within an interrupt. */\r
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
{\r
exit without doing anything. */\r
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
{\r
- prvCopyQueueData( pxQueue, pvItemToQueue );\r
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK );\r
\r
- /* We only want to wake one co-routine per ISR, so check that a \r
+ /* We only want to wake one co-routine per ISR, so check that a\r
co-routine has not already been woken. */\r
if( !xCoRoutinePreviouslyWoken ) \r
{\r