/*\r
- FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.\r
+ FreeRTOS.org V4.7.1 - Copyright (C) 2003-2008 Richard Barry.\r
\r
This file is part of the FreeRTOS.org distribution.\r
\r
can be applied.\r
\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
- Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along\r
- with commercial development and support options.\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
+ Please ensure to read the configuration and relevant port sections of the \r
+ online documentation.\r
\r
-Changes from V3.2.3\r
+ +++ http://www.FreeRTOS.org +++\r
+ Documentation, latest information, license and contact details. \r
\r
- + Added the queue functions that can be used from co-routines.\r
+ +++ http://www.SafeRTOS.com +++\r
+ A version that is certified for use in safety critical systems.\r
\r
-Changes from V4.0.5\r
+ +++ http://www.OpenRTOS.com +++\r
+ Commercial support, development, porting, licensing and training services.\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
-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
\r
#include <stdlib.h>\r
/* Effectively make a union out of the xQUEUE structure. */\r
#define pxMutexHolder pcTail\r
#define uxQueueType pcHead\r
+#define uxRecursiveCallCount pcReadFrom\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
+#define queueMUTEX_GIVE_BLOCK_TIME ( ( portTickType ) 0 )\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
*/\r
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );\r
signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition );\r
-unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );\r
+unsigned portBASE_TYPE uxQueueMessagesWaiting( const xQueueHandle pxQueue );\r
void vQueueDelete( xQueueHandle xQueue );\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, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking );\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );\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
+portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlockTime );\r
+portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle xMutex );\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
#endif /* configUSE_MUTEXES */\r
/*-----------------------------------------------------------*/\r
\r
+#if configUSE_RECURSIVE_MUTEXES == 1\r
+\r
+ portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex )\r
+ {\r
+ portBASE_TYPE xReturn;\r
+\r
+ /* If this is the task that holds the mutex then pxMutexHolder will not \r
+ change outside of this task. If this task does not hold the mutex then\r
+ pxMutexHolder can never coincidentally equal the tasks handle, and as\r
+ this is the only condition we are interested in it does not matter if\r
+ pxMutexHolder is accessed simultaneously by another task. Therefore no\r
+ mutual exclusion is required to test the pxMutexHolder variable. */\r
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
+ {\r
+ /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to\r
+ the task handle, therefore no underflow check is required. Also, \r
+ uxRecursiveCallCount is only modified by the mutex holder, and as\r
+ there can only be one, no mutual exclusion is required to modify the\r
+ uxRecursiveCallCount member. */\r
+ ( pxMutex->uxRecursiveCallCount )--;\r
+\r
+ /* Have we unwound the call count? */\r
+ if( pxMutex->uxRecursiveCallCount == 0 )\r
+ {\r
+ /* Return the mutex. This will automatically unblock any other\r
+ task that might be waiting to access the mutex. */\r
+ xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );\r
+ }\r
+\r
+ xReturn = pdPASS;\r
+ }\r
+ else\r
+ {\r
+ /* We cannot give the mutex because we are not the holder. */\r
+ xReturn = pdFAIL;\r
+ }\r
+\r
+ return xReturn;\r
+ }\r
+\r
+#endif /* configUSE_RECURSIVE_MUTEXES */\r
+/*-----------------------------------------------------------*/\r
+\r
+#if configUSE_RECURSIVE_MUTEXES == 1\r
+\r
+ portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime )\r
+ {\r
+ portBASE_TYPE xReturn;\r
+\r
+ /* Comments regarding mutual exclusion as per those within \r
+ xQueueGiveMutexRecursive(). */\r
+\r
+ if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() )\r
+ {\r
+ ( pxMutex->uxRecursiveCallCount )++;\r
+ xReturn = pdPASS;\r
+ }\r
+ else\r
+ {\r
+ xReturn = xQueueGenericReceive( pxMutex, NULL, xBlockTime, pdFALSE );\r
+\r
+ /* pdPASS will only be returned if we successfully obtained the mutex,\r
+ we may have blocked to reach here. */\r
+ if( xReturn == pdPASS )\r
+ {\r
+ ( pxMutex->uxRecursiveCallCount )++;\r
+ }\r
+ }\r
+\r
+ return xReturn;\r
+ }\r
+\r
+#endif /* configUSE_RECURSIVE_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 = pdPASS;\r
}\r
/*-----------------------------------------------------------*/\r
\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 xQueueGenericSend, except we don't block if there is no room\r
}\r
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
+signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, const void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking )\r
{\r
signed portBASE_TYPE xReturn = pdTRUE;\r
xTimeOutType xTimeOut;\r
{\r
/* We are not removing the data, so reset our read\r
pointer. */\r
- pxQueue->pcReadFrom = pcOriginalReadPosition; \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
/*-----------------------------------------------------------*/\r
\r
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const 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
}\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
/* The mutex is no longer being held. */\r
vTaskPriorityDisinherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ pxQueue->pxMutexHolder = NULL;\r
}\r
}\r
#endif\r