/*\r
- FreeRTOS.org V4.7.0 - Copyright (C) 2003-2007 Richard Barry.\r
+ FreeRTOS.org V4.8.0 - Copyright (C) 2003-2008 Richard Barry.\r
\r
This file is part of the FreeRTOS.org distribution.\r
\r
of http://www.FreeRTOS.org for full details of how and when the exception\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
+ ***************************************************************************\r
+ * *\r
+ * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, *\r
+ * and even write all or part of your application on your behalf. *\r
+ * See http://www.OpenRTOS.com for details of the services we provide to *\r
+ * expedite your project. *\r
+ * *\r
+ ***************************************************************************\r
+ ***************************************************************************\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
+ Please ensure to read the configuration and relevant port sections of the\r
+ online documentation.\r
+\r
+ http://www.FreeRTOS.org - Documentation, latest information, license and \r
+ contact details.\r
+\r
+ http://www.SafeRTOS.com - A version that is certified for use in safety \r
+ critical systems.\r
+\r
+ http://www.OpenRTOS.com - Commercial support, development, porting, \r
+ licensing and training services.\r
*/\r
\r
#include <stdlib.h>\r
*----------------------------------------------------------*/\r
\r
/* Constants used with the cRxLock and cTxLock structure members. */\r
-#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )\r
+#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )\r
+#define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 )\r
+\r
#define queueERRONEOUS_UNBLOCK ( -1 )\r
\r
/* For internal use only. */\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
-\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
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
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );\r
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );\r
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );\r
+\r
\r
#if configUSE_CO_ROUTINES == 1\r
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );\r
* Macro to mark a queue as locked. Locking a queue prevents an ISR from\r
* accessing the queue event lists.\r
*/\r
-#define prvLockQueue( pxQueue ) \\r
-{ \\r
- taskENTER_CRITICAL(); \\r
- ++( pxQueue->xRxLock ); \\r
- ++( pxQueue->xTxLock ); \\r
- taskEXIT_CRITICAL(); \\r
+#define prvLockQueue( pxQueue ) \\r
+{ \\r
+ taskENTER_CRITICAL(); \\r
+ { \\r
+ if( pxQueue->xRxLock == queueUNLOCKED ) \\r
+ { \\r
+ pxQueue->xRxLock = queueLOCKED_UNMODIFIED; \\r
+ } \\r
+ if( pxQueue->xTxLock == queueUNLOCKED ) \\r
+ { \\r
+ pxQueue->xTxLock = queueLOCKED_UNMODIFIED; \\r
+ } \\r
+ } \\r
+ taskEXIT_CRITICAL(); \\r
}\r
/*-----------------------------------------------------------*/\r
\r
vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );\r
vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );\r
\r
+ traceQUEUE_CREATE( pxNewQueue );\r
+\r
return pxNewQueue;\r
}\r
else\r
{\r
+ traceQUEUE_CREATE_FAILED();\r
vPortFree( pxNewQueue );\r
}\r
}\r
\r
/* Start with the semaphore in the expected state. */\r
xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK );\r
+\r
+ traceCREATE_MUTEX( pxNewQueue );\r
+ }\r
+ else\r
+ {\r
+ traceCREATE_MUTEX_FAILED();\r
}\r
\r
return pxNewQueue;\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
+ traceGIVE_MUTEX_RECURSIVE( pxMutex );\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
+ traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );\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
+ traceTAKE_MUTEX_RECURSIVE( pxMutex );\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
if( pxHandle != NULL )\r
{\r
pxHandle->uxMessagesWaiting = uxInitialCount;\r
+\r
+ traceCREATE_COUNTING_SEMAPHORE();\r
+ }\r
+ else\r
+ {\r
+ traceCREATE_COUNTING_SEMAPHORE_FAILED();\r
}\r
\r
return pxHandle;\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
+signed portBASE_TYPE xReturn = pdTRUE;\r
xTimeOutType xTimeOut;\r
\r
- /* Make sure other tasks do not access the queue. */\r
- vTaskSuspendAll();\r
-\r
- /* Capture the current time status for future reference. */\r
- vTaskSetTimeOutState( &xTimeOut );\r
-\r
- /* It is important that this is the only thread/ISR that modifies the\r
- ready or delayed lists until xTaskResumeAll() is called. Places where\r
- the ready/delayed lists are modified include:\r
-\r
- + vTaskDelay() - Nothing can call vTaskDelay as the scheduler is\r
- suspended, vTaskDelay() cannot be called from an ISR.\r
- + vTaskPrioritySet() - Has a critical section around the access.\r
- + vTaskSwitchContext() - This will not get executed while the scheduler\r
- is suspended.\r
- + prvCheckDelayedTasks() - This will not get executed while the\r
- scheduler is suspended.\r
- + xTaskCreate() - Has a critical section around the access.\r
- + vTaskResume() - Has a critical section around the access.\r
- + xTaskResumeAll() - Has a critical section around the access.\r
- + xTaskRemoveFromEventList - Checks to see if the scheduler is\r
- suspended. If so then the TCB being removed from the event is\r
- removed from the event and added to the xPendingReadyList.\r
- */\r
-\r
- /* Make sure interrupts do not access the queue event list. */\r
- prvLockQueue( pxQueue );\r
-\r
- /* It is important that interrupts to not access the event list of the\r
- queue being modified here. Places where the event list is modified\r
- include:\r
-\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 xQueueGenericSendFromISR().\r
- */\r
- \r
- /* If the queue is already full we may have to block. */\r
do\r
{\r
- if( prvIsQueueFull( pxQueue ) )\r
+ /* If xTicksToWait is zero then we are not going to block even\r
+ if there is no room in the queue to post. */\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
{\r
- /* The queue is full - do we want to block or just leave without\r
- posting? */\r
- if( xTicksToWait > ( portTickType ) 0 )\r
+ vTaskSuspendAll();\r
+ prvLockQueue( pxQueue );\r
+\r
+ if( xReturn == pdTRUE )\r
{\r
- /* We are going to place ourselves on the xTasksWaitingToSend event\r
- list, and will get woken should the delay expire, or space become\r
- available on the queue.\r
- \r
- As detailed above we do not require mutual exclusion on the event\r
- list as nothing else can modify it or the ready lists while we\r
- have the scheduler suspended and queue locked.\r
- \r
- It is possible that an ISR has removed data from the queue since we\r
- checked if any was available. If this is the case then the data\r
- will have been copied from the queue, and the queue variables\r
- updated, but the event list will not yet have been checked to see if\r
- anything is waiting as the queue is locked. */\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. we\r
- unblock) we will leave the critical section as normal.\r
- \r
- It is possible that an ISR has caused an event on an unrelated and\r
- unlocked queue. If this was the case then the event list for that\r
- queue will have been updated but the ready lists left unchanged -\r
- instead the readied task will have been added to the pending ready\r
- list. */\r
- taskENTER_CRITICAL();\r
+ /* This is the first time through - we need to capture the\r
+ time while the scheduler is locked to ensure we attempt to\r
+ block at least once. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
+ }\r
+\r
+ if( prvIsQueueFull( pxQueue ) )\r
+ {\r
+ /* Need to call xTaskCheckForTimeout again as time could\r
+ have passed since it was last called if this is not the\r
+ first time around this loop. */\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
{\r
- /* We can safely unlock the queue and scheduler here as\r
- interrupts are disabled. We must not yield with anything\r
- locked, but we can yield from within a critical section.\r
- \r
- Tasks that have been placed on the pending ready list cannot\r
- be tasks that are waiting for events on this queue. See\r
- in comment xTaskRemoveFromEventList(). */\r
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
+ \r
+ /* Unlocking the queue means queue events can effect the\r
+ event list. It is possible that interrupts occurring now\r
+ remove this task from the event list again - but as the\r
+ scheduler is suspended the task will go onto the pending\r
+ ready last instead of the actual ready list. */\r
prvUnlockQueue( pxQueue );\r
- \r
- /* Resuming the scheduler may cause a yield. If so then there\r
- is no point yielding again here. */\r
+ \r
+ /* Resuming the scheduler will move tasks from the pending\r
+ ready list into the ready list - so it is feasible that this\r
+ task is already in a ready list before it yields - in which\r
+ case the yield will not cause a context switch unless there\r
+ is also a higher priority task in the pending ready list. */\r
if( !xTaskResumeAll() )\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
- vTaskSuspendAll();\r
- prvLockQueue( pxQueue ); \r
}\r
- taskEXIT_CRITICAL();\r
+ else\r
+ {\r
+ prvUnlockQueue( pxQueue );\r
+ ( void ) xTaskResumeAll();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* The queue was not full so we can just unlock the\r
+ scheduler and queue again before carrying on. */\r
+ prvUnlockQueue( pxQueue );\r
+ ( void ) xTaskResumeAll();\r
}\r
}\r
- \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
+ /* Higher priority tasks and interrupts can execute during\r
+ this time and could possible refill the queue - even if we\r
+ unblocked because space became available. */\r
+ \r
+ taskENTER_CRITICAL();\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
+ /* Is there room on the queue now? To be running we must be\r
+ the highest priority task wanting to access the queue. */\r
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\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
- /* 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
+ traceQUEUE_SEND( pxQueue );\r
+ prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
+ xReturn = pdPASS;\r
+ \r
+ /* If there was a task waiting for data to arrive on the\r
+ queue then unblock it now. */\r
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
{\r
- xReturn = errQUEUE_FULL;\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
+ {\r
+ /* The unblocked task has a priority higher than\r
+ our own so yield immediately. */\r
+ taskYIELD();\r
+ }\r
}\r
}\r
- taskEXIT_CRITICAL();\r
+ else\r
+ {\r
+ /* Setting xReturn to errQUEUE_FULL will force its timeout\r
+ to be re-evaluated. This is necessary in case interrupts\r
+ and higher priority tasks accessed the queue between this\r
+ task being unblocked and subsequently attempting to write\r
+ to the queue. */\r
+ xReturn = errQUEUE_FULL;\r
+ }\r
}\r
+ taskEXIT_CRITICAL();\r
\r
if( xReturn == errQUEUE_FULL )\r
{\r
- if( xTicksToWait > 0 )\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
{\r
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
{\r
xReturn = queueERRONEOUS_UNBLOCK;\r
}\r
+ else\r
+ {\r
+ traceQUEUE_SEND_FAILED( pxQueue );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ traceQUEUE_SEND_FAILED( pxQueue );\r
}\r
}\r
}\r
while( xReturn == queueERRONEOUS_UNBLOCK );\r
\r
- prvUnlockQueue( pxQueue );\r
- xTaskResumeAll();\r
-\r
return xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
\r
signed portBASE_TYPE xQueueAltGenericSend( 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
- /* The source code that implements the light weight (fast) 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
- fully featured API as an alternative. 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 light weight API sacrifices interrupt \r
- responsiveness to gain execution speed, whereas the fully featured API\r
- sacrifices execution speed to ensure better interrupt responsiveness. */\r
+ /* The source code that implements the alternative (Alt) API is\r
+ simpler because it makes more use of critical sections. This is \r
+ 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 less use of\r
+ critical sections. */\r
\r
- taskENTER_CRITICAL();\r
+ do\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
+ /* If xTicksToWait is zero then we are not going to block even\r
+ if there is no room in the queue to post. */\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
{\r
- if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )\r
+ portENTER_CRITICAL();\r
{\r
- /* The queue is full - do we want to block or just leave without\r
- posting? */\r
- if( xTicksToWait > ( portTickType ) 0 )\r
+ if( xReturn == pdPASS )\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
+ /* This is the first time through - capture the time\r
+ inside the critical section to ensure we attempt to\r
+ block at least once. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
}\r
- }\r
\r
+ if( prvIsQueueFull( pxQueue ) )\r
+ {\r
+ /* Need to call xTaskCheckForTimeout again as time could\r
+ have passed since it was last called if this is not the\r
+ first time around this loop. */\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+ {\r
+ traceBLOCKING_ON_QUEUE_SEND( pxQueue );\r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );\r
+\r
+ /* This will exit the critical section, then re-enter when\r
+ the task next runs. */\r
+ taskYIELD();\r
+ }\r
+ }\r
+ }\r
+ portEXIT_CRITICAL();\r
+ }\r
+ \r
+ /* Higher priority tasks and interrupts can execute during\r
+ this time and could possible refill the queue - even if we\r
+ unblocked because space became available. */\r
+ \r
+ taskENTER_CRITICAL();\r
+ {\r
+ /* Is there room on the queue now? To be running we must be\r
+ the highest priority task wanting to access the queue. */\r
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
{\r
- /* There is room in the queue, copy the data into the queue. */ \r
+ traceQUEUE_SEND( pxQueue );\r
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
xReturn = pdPASS;\r
-\r
- if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
+ \r
+ /* If there was a task waiting for data to arrive on the\r
+ queue then unblock it now. */\r
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )\r
{\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) == pdTRUE )\r
{\r
- /* The task waiting has a higher priority. */\r
+ /* The unblocked task has a priority higher than\r
+ our own so yield immediately. */\r
taskYIELD();\r
}\r
- } \r
+ }\r
}\r
else\r
{\r
+ /* Setting xReturn to errQUEUE_FULL will force its timeout\r
+ to be re-evaluated. This is necessary in case interrupts\r
+ and higher priority tasks accessed the queue between this\r
+ task being unblocked and subsequently attempting to write\r
+ to the queue. */\r
xReturn = errQUEUE_FULL;\r
+ }\r
+ }\r
+ taskEXIT_CRITICAL();\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
+ if( xReturn == errQUEUE_FULL )\r
+ {\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
+ {\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+ {\r
+ xReturn = queueERRONEOUS_UNBLOCK;\r
}\r
else\r
{\r
- \r
+ traceQUEUE_SEND_FAILED( pxQueue );\r
}\r
}\r
+ else\r
+ {\r
+ traceQUEUE_SEND_FAILED( pxQueue );\r
+ }\r
}\r
- while( xReturn == queueERRONEOUS_UNBLOCK );\r
}\r
- taskEXIT_CRITICAL();\r
+ while( xReturn == queueERRONEOUS_UNBLOCK );\r
\r
return xReturn;\r
}\r
xTimeOutType xTimeOut;\r
signed portCHAR *pcOriginalReadPosition;\r
\r
- /* The source code that implements the light weight (fast) 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
- fully featured API as an alternative. 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 light weight API sacrifices interrupt \r
- responsiveness to gain execution speed, whereas the fully featured API\r
- sacrifices execution speed to ensure better interrupt responsiveness. */\r
+ /* The source code that implements the alternative (Alt) API is\r
+ simpler because it makes more use of critical sections. This is \r
+ 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 less use of\r
+ critical sections. */\r
\r
- taskENTER_CRITICAL();\r
+ do\r
{\r
- /* Capture the current time status for future reference. */\r
- vTaskSetTimeOutState( &xTimeOut );\r
-\r
- do\r
+ /* If there are no messages in the queue we may have to block. */\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
{\r
- /* If there are no messages in the queue we may have to block. */\r
- if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
+ portENTER_CRITICAL();\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
+ if( xReturn == pdPASS )\r
{\r
- #if ( configUSE_MUTEXES == 1 )\r
+ /* This is the first time through - capture the time\r
+ inside the critical section to ensure we attempt to\r
+ block at least once. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
+ }\r
+ \r
+ if( prvIsQueueEmpty( pxQueue ) )\r
+ {\r
+ /* Need to call xTaskCheckForTimeout again as time could\r
+ have passed since it was last called if this is not the\r
+ first time around this loop. */\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
{\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
+\r
+ #if ( configUSE_MUTEXES == 1 )\r
{\r
- vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ portENTER_CRITICAL();\r
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
+ portEXIT_CRITICAL();\r
+ }\r
}\r
+ #endif\r
+\r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
+ taskYIELD();\r
}\r
- #endif\r
- \r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
- taskYIELD();\r
}\r
}\r
- \r
+ portEXIT_CRITICAL();\r
+ }\r
+ \r
+ taskENTER_CRITICAL();\r
+ {\r
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
{\r
/* Remember our read position in case we are just peeking. */\r
\r
if( xJustPeeking == pdFALSE )\r
{\r
+ traceQUEUE_RECEIVE( pxQueue );\r
+\r
/* We are actually removing data. */\r
--( pxQueue->uxMessagesWaiting );\r
- \r
+\r
#if ( configUSE_MUTEXES == 1 )\r
{\r
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
}\r
}\r
#endif\r
-\r
- if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
+ \r
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\r
{\r
- if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
{\r
- /* The task waiting has a higher priority. */\r
taskYIELD();\r
}\r
}\r
}\r
else\r
{\r
+ traceQUEUE_PEEK( pxQueue );\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 see if there are\r
+ any other tasks waiting for the data. */\r
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
+ {\r
+ /* Tasks that are removed from the event list will get added to\r
+ the pending ready list as the scheduler is still suspended. */\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
+ {\r
+ /* The task waiting has a higher priority that this task. */\r
+ taskYIELD();\r
+ }\r
+ } \r
+\r
}\r
\r
xReturn = pdPASS; \r
else\r
{\r
xReturn = errQUEUE_EMPTY;\r
+ }\r
+ }\r
+ taskEXIT_CRITICAL();\r
\r
- if( xTicksToWait > 0 )\r
+ if( xReturn == errQUEUE_EMPTY )\r
+ {\r
+ if( xTicksToWait > ( portTickType ) 0 )\r
+ {\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
{\r
- if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
- {\r
- xReturn = queueERRONEOUS_UNBLOCK;\r
- }\r
+ xReturn = queueERRONEOUS_UNBLOCK;\r
+ }\r
+ else\r
+ {\r
+ traceQUEUE_RECEIVE_FAILED( pxQueue );\r
}\r
}\r
-\r
- } while( xReturn == queueERRONEOUS_UNBLOCK );\r
- }\r
- taskEXIT_CRITICAL();\r
+ else\r
+ {\r
+ traceQUEUE_RECEIVE_FAILED( pxQueue );\r
+ }\r
+ }\r
+ } while( xReturn == queueERRONEOUS_UNBLOCK );\r
\r
return xReturn;\r
}\r
\r
+\r
#endif /* configUSE_ALTERNATIVE_API */\r
/*-----------------------------------------------------------*/\r
\r
by this post). */\r
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
{\r
+ traceQUEUE_SEND_FROM_ISR( pxQueue );\r
+\r
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );\r
\r
/* If the queue is locked we do not alter the event list. This will\r
++( pxQueue->xTxLock );\r
}\r
}\r
+ else\r
+ {\r
+ traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );\r
+ }\r
\r
return xTaskPreviouslyWoken;\r
}\r
xTimeOutType xTimeOut;\r
signed portCHAR *pcOriginalReadPosition;\r
\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
-\r
- /* Capture the current time status for future reference. */\r
- vTaskSetTimeOutState( &xTimeOut );\r
-\r
- /* Make sure interrupts do not access the queue. */\r
- prvLockQueue( pxQueue );\r
-\r
do\r
{\r
/* If there are no messages in the queue we may have to block. */\r
- if( prvIsQueueEmpty( pxQueue ) )\r
+ if( xTicksToWait > ( portTickType ) 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
+ vTaskSuspendAll();\r
+ prvLockQueue( pxQueue );\r
+\r
+ if( xReturn == pdTRUE )\r
{\r
- #if ( configUSE_MUTEXES == 1 )\r
+ /* This is the first time through - we need to capture the\r
+ time while the scheduler is locked to ensure we attempt to\r
+ block at least once. */\r
+ vTaskSetTimeOutState( &xTimeOut );\r
+ }\r
+\r
+ if( prvIsQueueEmpty( pxQueue ) )\r
+ {\r
+ /* Need to call xTaskCheckForTimeout again as time could\r
+ have passed since it was last called if this is not the\r
+ first time around this loop. */\r
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
{\r
- if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\r
+\r
+ #if ( configUSE_MUTEXES == 1 )\r
{\r
- portENTER_CRITICAL();\r
- vTaskPriorityInherit( ( void * const ) pxQueue->pxMutexHolder );\r
- portEXIT_CRITICAL();\r
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
+ {\r
+ portENTER_CRITICAL();\r
+ vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );\r
+ portEXIT_CRITICAL();\r
+ }\r
}\r
- }\r
- #endif\r
- \r
- vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
- taskENTER_CRITICAL();\r
- {\r
+ #endif\r
+\r
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
prvUnlockQueue( pxQueue );\r
if( !xTaskResumeAll() )\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
- taskEXIT_CRITICAL();\r
+ else\r
+ {\r
+ prvUnlockQueue( pxQueue );\r
+ ( void ) xTaskResumeAll();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ prvUnlockQueue( pxQueue );\r
+ ( void ) xTaskResumeAll();\r
}\r
}\r
\r
- if( xReturn != errQUEUE_EMPTY )\r
+ taskENTER_CRITICAL();\r
{\r
- taskENTER_CRITICAL();\r
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
{\r
- if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\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
- /* Remember our read position in case we are just peeking. */\r
- pcOriginalReadPosition = pxQueue->pcReadFrom;\r
+ traceQUEUE_RECEIVE( pxQueue );\r
\r
- prvCopyDataFromQueue( pxQueue, pvBuffer );\r
+ /* We are actually removing data. */\r
+ --( pxQueue->uxMessagesWaiting );\r
\r
- if( xJustPeeking == pdFALSE )\r
+ #if ( configUSE_MUTEXES == 1 )\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
+ if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\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
+ /* Record the information required to implement\r
+ priority inheritance should it become necessary. */\r
+ pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle();\r
}\r
- #endif\r
}\r
- else\r
+ #endif\r
+ \r
+ if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )\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
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) == pdTRUE )\r
+ {\r
+ taskYIELD();\r
+ }\r
}\r
- \r
- xReturn = pdPASS; \r
}\r
else\r
{\r
- xReturn = errQUEUE_EMPTY;\r
+ traceQUEUE_PEEK( pxQueue );\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 see if there are\r
+ any other tasks waiting for the data. */\r
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
+ {\r
+ /* Tasks that are removed from the event list will get added to\r
+ the pending ready list as the scheduler is still suspended. */\r
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )\r
+ {\r
+ /* The task waiting has a higher priority that this task. */\r
+ taskYIELD();\r
+ }\r
+ } \r
+\r
}\r
+ \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
xReturn = queueERRONEOUS_UNBLOCK;\r
}\r
+ else\r
+ {\r
+ traceQUEUE_RECEIVE_FAILED( pxQueue );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ traceQUEUE_RECEIVE_FAILED( pxQueue );\r
}\r
}\r
} while( xReturn == queueERRONEOUS_UNBLOCK );\r
\r
- /* We no longer require exclusive access to the queue. */\r
- prvUnlockQueue( pxQueue );\r
- xTaskResumeAll();\r
-\r
return xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
/* We cannot block from an ISR, so check there is data available. */\r
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
{\r
+ traceQUEUE_RECEIVE_FROM_ISR( pxQueue );\r
+\r
prvCopyDataFromQueue( pxQueue, pvBuffer );\r
--( pxQueue->uxMessagesWaiting );\r
\r
else\r
{\r
xReturn = pdFAIL;\r
+ traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );\r
}\r
\r
return xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
\r
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue )\r
+{\r
+unsigned portBASE_TYPE uxReturn;\r
+\r
+ uxReturn = pxQueue->uxMessagesWaiting;\r
+\r
+ return uxReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
void vQueueDelete( xQueueHandle pxQueue )\r
{\r
+ traceQUEUE_DELETE( pxQueue );\r
+\r
vPortFree( pxQueue->pcHead );\r
vPortFree( pxQueue );\r
}\r
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )\r
{\r
/* The mutex is no longer being held. */\r
- vTaskPriorityDisinherit( ( void * const ) pxQueue->pxMutexHolder );\r
+ vTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );\r
+ pxQueue->pxMutexHolder = NULL;\r
}\r
}\r
#endif\r
updated. */\r
taskENTER_CRITICAL();\r
{\r
- --( pxQueue->xTxLock );\r
-\r
/* See if data was added to the queue while it was locked. */\r
- if( pxQueue->xTxLock > queueUNLOCKED )\r
+ while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )\r
{\r
- pxQueue->xTxLock = queueUNLOCKED;\r
-\r
/* Data was posted while the queue was locked. Are any tasks\r
blocked waiting for data to become available? */\r
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )\r
context switch is required. */\r
vTaskMissedYield();\r
}\r
- } \r
+\r
+ --( pxQueue->xTxLock );\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
}\r
+\r
+ pxQueue->xTxLock = queueUNLOCKED;\r
}\r
taskEXIT_CRITICAL();\r
\r
/* Do the same for the Rx lock. */\r
taskENTER_CRITICAL();\r
{\r
- --( pxQueue->xRxLock );\r
-\r
- if( pxQueue->xRxLock > queueUNLOCKED )\r
+ while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )\r
{\r
- pxQueue->xRxLock = queueUNLOCKED;\r
-\r
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )\r
{\r
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
{\r
vTaskMissedYield();\r
}\r
- } \r
+\r
+ --( pxQueue->xRxLock );\r
+ }\r
+ else\r
+ {\r
+ break;\r
+ }\r
}\r
+\r
+ pxQueue->xRxLock = queueUNLOCKED;\r
}\r
taskEXIT_CRITICAL();\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
+signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue )\r
+{\r
+signed portBASE_TYPE xReturn;\r
+\r
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )\r
{\r
signed portBASE_TYPE xReturn;\r
}\r
/*-----------------------------------------------------------*/\r
\r
+signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue )\r
+{\r
+signed portBASE_TYPE xReturn;\r
+\r
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
#if configUSE_CO_ROUTINES == 1\r
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
{\r