]> git.sur5r.net Git - freertos/commitdiff
Re-write the queue send and queue receive functions to improve their effect on interr...
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 23 Mar 2008 16:06:45 +0000 (16:06 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Sun, 23 Mar 2008 16:06:45 +0000 (16:06 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@255 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Source/include/queue.h
Source/queue.c

index 2ba816ae20f616ec3837617ef9476b3319375bd0..8c7a884462ba20a3126208878a78e7547d76fc59 100644 (file)
@@ -1170,7 +1170,7 @@ signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, const void * co
  */\r
 signed portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );\r
 signed portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );\r
-signed portBASE_TYPE xQueueMessagesWaitingFromISR( const xQueueHandle pxQueue, unsigned portBASE_TYPE *puxMessagesWaiting );\r
+unsigned portBASE_TYPE uxQueueMessagesWaitingFromISR( const xQueueHandle pxQueue );\r
 \r
 \r
 /* \r
index 77b0a4fb9f02bd6aa10ad7b4c3a591a145e765f4..46f102860227196babcd9200ac6401e1dbf5ef9a 100644 (file)
@@ -118,6 +118,10 @@ portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle xMutex, portTickType xBlock
 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
+portBASE_TYPE xQueueIsQueueEmptyFromISR( const xQueueHandle pxQueue );\r
+portBASE_TYPE xQueueIsQueueFullFromISR( const xQueueHandle pxQueue );\r
+portBASE_TYPE xQueueMessagesWaitingFromISR( 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
@@ -387,164 +391,105 @@ size_t xQueueSizeInBytes;
 \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
                                        traceBLOCKING_ON_QUEUE_SEND( pxQueue );\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
+                                       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
-                                       traceQUEUE_SEND( pxQueue );\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
@@ -567,9 +512,6 @@ xTimeOutType xTimeOut;
        }\r
        while( xReturn == queueERRONEOUS_UNBLOCK );\r
 \r
-       prvUnlockQueue( pxQueue );\r
-       xTaskResumeAll();\r
-\r
        return xReturn;\r
 }\r
 /*-----------------------------------------------------------*/\r
@@ -578,90 +520,109 @@ xTimeOutType xTimeOut;
 \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 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
+               /* 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 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
+               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
+                                               /* 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( prvIsQueueFull( pxQueue ) )\r
                                        {\r
-                                               traceBLOCKING_ON_QUEUE_SEND( pxQueue );\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
-                                               /* 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 will exit the critical section, then re-enter when\r
+                                                       the task next runs. */\r
+                                                       taskYIELD();\r
+                                               }\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
                                        traceQUEUE_SEND( pxQueue );\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 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
-                                               else\r
-                                               {\r
-                                                       traceQUEUE_SEND_FAILED( pxQueue );\r
-                                               }\r
+                       if( xReturn == errQUEUE_FULL )\r
+                       {\r
+                               if( xTicksToWait > 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
-                       while( xReturn == queueERRONEOUS_UNBLOCK );\r
                }\r
-               taskEXIT_CRITICAL();\r
+               while( xReturn == queueERRONEOUS_UNBLOCK );\r
 \r
                return xReturn;\r
        }\r
@@ -677,45 +638,58 @@ xTimeOutType xTimeOut;
        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
+               /* 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 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
+               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
-                                               traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\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
@@ -729,7 +703,7 @@ xTimeOutType xTimeOut;
 \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
@@ -740,12 +714,11 @@ xTimeOutType xTimeOut;
                                                        }\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
@@ -757,6 +730,20 @@ xTimeOutType xTimeOut;
                                                /* 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
@@ -764,31 +751,34 @@ xTimeOutType xTimeOut;
                                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 > 0 )\r
+                               {\r
+                                       if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
                                        {\r
-                                               if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
-                                               {\r
-                                                       xReturn = queueERRONEOUS_UNBLOCK;\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       traceQUEUE_RECEIVE_FAILED( pxQueue );\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
@@ -846,119 +836,128 @@ signed portBASE_TYPE xReturn = pdTRUE;
 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
-                               traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );\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 ( configUSE_MUTEXES == 1 )\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 * ) 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
-                                               traceQUEUE_RECEIVE( pxQueue );\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
-                                               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 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
@@ -980,10 +979,6 @@ signed portCHAR *pcOriginalReadPosition;
                }\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
@@ -1051,6 +1046,16 @@ unsigned portBASE_TYPE uxReturn;
 }\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
@@ -1180,6 +1185,16 @@ signed portBASE_TYPE xReturn;
 }\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
@@ -1192,6 +1207,16 @@ signed portBASE_TYPE xReturn;
 }\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