]> git.sur5r.net Git - freertos/blobdiff - Source/queue.c
Changes from V4.1.2
[freertos] / Source / queue.c
index 73f062a3da1eb733d956c1fe612060ccbb04840d..488c8069a9bd1f02333f6329e4d50b489e21689f 100644 (file)
@@ -1,24 +1,24 @@
 /*\r
-       FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry.\r
+       FreeRTOS.org V4.1.2 - Copyright (C) 2003-2006 Richard Barry.\r
 \r
-       This file is part of the FreeRTOS distribution.\r
+       This file is part of the FreeRTOS.org distribution.\r
 \r
-       FreeRTOS is free software; you can redistribute it and/or modify\r
+       FreeRTOS.org is free software; you can redistribute it and/or modify\r
        it under the terms of the GNU General Public License as published by\r
        the Free Software Foundation; either version 2 of the License, or\r
        (at your option) any later version.\r
 \r
-       FreeRTOS is distributed in the hope that it will be useful,\r
+       FreeRTOS.org is distributed in the hope that it will be useful,\r
        but WITHOUT ANY WARRANTY; without even the implied warranty of\r
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
        GNU General Public License for more details.\r
 \r
        You should have received a copy of the GNU General Public License\r
-       along with FreeRTOS; if not, write to the Free Software\r
+       along with FreeRTOS.org; if not, write to the Free Software\r
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
 \r
        A special exception to the GPL can be applied should you wish to distribute\r
-       a combined work that includes FreeRTOS, without being obliged to provide\r
+       a combined work that includes FreeRTOS.org, without being obliged to provide\r
        the source code for any proprietary components.  See the licensing section\r
        of http://www.FreeRTOS.org for full details of how and when the exception\r
        can be applied.\r
@@ -54,6 +54,12 @@ Changes from V3.2.3
 \r
        + Added the queue functions that can be used from co-routines.\r
 \r
+Changes from V4.0.5\r
+\r
+       + Added a loop within xQueueSend() and xQueueReceive() to prevent the\r
+         functions exiting when a block time remains and the function has\r
+         not completed.\r
+\r
 */\r
 \r
 #include <stdlib.h>\r
@@ -68,6 +74,7 @@ Changes from V3.2.3
 \r
 /* Constants used with the cRxLock and cTxLock structure members. */\r
 #define queueUNLOCKED  ( ( signed portBASE_TYPE ) -1 )\r
+#define queueERRONEOUS_UNBLOCK                                 ( -1 )\r
 \r
 /*\r
  * Definition of the queue used by the scheduler.\r
@@ -128,7 +135,7 @@ signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer,
  * to indicate that a task may require unblocking.  When the queue in unlocked\r
  * these lock counts are inspected, and the appropriate action taken.\r
  */\r
-static signed portBASE_TYPE prvUnlockQueue( xQueueHandle pxQueue );\r
+static void prvUnlockQueue( xQueueHandle pxQueue );\r
 \r
 /*\r
  * Uses a critical section to determine if there is any data in a queue.\r
@@ -230,10 +237,14 @@ size_t xQueueSizeInBytes;
 signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
 {\r
 signed portBASE_TYPE xReturn;\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
@@ -272,108 +283,105 @@ signed portBASE_TYPE xReturn;
        */\r
                \r
        /* If the queue is already full we may have to block. */\r
-       if( prvIsQueueFull( pxQueue ) )\r
+       do\r
        {\r
-               /* The queue is full - do we want to block or just leave without\r
-               posting? */\r
-               if( xTicksToWait > ( portTickType ) 0 )\r
+               if( prvIsQueueFull( pxQueue ) )\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
+                       /* The queue is full - do we want to block or just leave without\r
+                       posting? */\r
+                       if( xTicksToWait > ( portTickType ) 0 )\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
+                               /* 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
-                               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
-                               prvUnlockQueue( pxQueue );\r
-\r
-                               /* Resuming the scheduler may cause a yield.  If so then there\r
-                               is no point yielding again here. */\r
-                               if( !xTaskResumeAll() )\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
                                {\r
-                                       taskYIELD();\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
+                                       prvUnlockQueue( pxQueue );\r
+       \r
+                                       /* Resuming the scheduler may cause a yield.  If so then there\r
+                                       is no point yielding again here. */\r
+                                       if( !xTaskResumeAll() )\r
+                                       {\r
+                                               taskYIELD();\r
+                                       }\r
+       \r
+                                       /* Before leaving the critical section we have to ensure\r
+                                       exclusive access again. */\r
+                                       vTaskSuspendAll();\r
+                                       prvLockQueue( pxQueue );                                \r
                                }\r
-\r
-                               /* Before leaving the critical section we have to ensure\r
-                               exclusive access again. */\r
-                               vTaskSuspendAll();\r
-                               prvLockQueue( pxQueue );                                \r
+                               taskEXIT_CRITICAL();\r
                        }\r
-                       taskEXIT_CRITICAL();\r
                }\r
-       }\r
-               \r
-       /* When we are here it is possible that we unblocked as space became\r
-       available on the queue.  It is also possible that an ISR posted to the\r
-       queue since we left the critical section, so it may be that again there\r
-       is no space.  This would only happen if a task and ISR post onto the\r
-       same queue. */\r
-       taskENTER_CRITICAL();\r
-       {\r
-               if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
-               {\r
-                       /* There is room in the queue, copy the data into the queue. */                 \r
-                       prvCopyQueueData( pxQueue, pvItemToQueue );             \r
-                       xReturn = pdPASS;\r
-\r
-                       /* Update the TxLock count so prvUnlockQueue knows to check for\r
-                       tasks waiting for data to become available in the queue. */\r
-                       ++( pxQueue->xTxLock );\r
-               }\r
-               else\r
+                       \r
+               /* When we are here it is possible that we unblocked as space became\r
+               available on the queue.  It is also possible that an ISR posted to the\r
+               queue since we left the critical section, so it may be that again there\r
+               is no space.  This would only happen if a task and ISR post onto the\r
+               same queue. */\r
+               taskENTER_CRITICAL();\r
                {\r
-                       xReturn = errQUEUE_FULL;\r
+                       if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+                       {\r
+                               /* There is room in the queue, copy the data into the queue. */                 \r
+                               prvCopyQueueData( pxQueue, pvItemToQueue );             \r
+                               xReturn = pdPASS;\r
+       \r
+                               /* Update the TxLock count so prvUnlockQueue knows to check for\r
+                               tasks waiting for data to become available in the queue. */\r
+                               ++( pxQueue->xTxLock );\r
+                       }\r
+                       else\r
+                       {\r
+                               xReturn = errQUEUE_FULL;\r
+                       }\r
                }\r
-       }\r
-       taskEXIT_CRITICAL();\r
+               taskEXIT_CRITICAL();\r
 \r
-       /* We no longer require exclusive access to the queue.  prvUnlockQueue\r
-       will remove any tasks suspended on a receive if either this function\r
-       or an ISR has posted onto the queue. */\r
-       if( prvUnlockQueue( pxQueue ) )\r
-       {\r
-               /* Resume the scheduler - making ready any tasks that were woken\r
-               by an event while the scheduler was locked.  Resuming the\r
-               scheduler may cause a yield, in which case there is no point\r
-               yielding again here. */\r
-               if( !xTaskResumeAll() )\r
+               if( xReturn == errQUEUE_FULL )\r
                {\r
-                       taskYIELD();\r
+                       if( xTicksToWait > 0 )\r
+                       {\r
+                               if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+                               {\r
+                                       xReturn = queueERRONEOUS_UNBLOCK;\r
+                               }\r
+                       }\r
                }\r
        }\r
-       else\r
-       {\r
-               /* Resume the scheduler - making ready any tasks that were woken\r
-               by an event while the scheduler was locked. */\r
-               xTaskResumeAll();\r
-       }\r
+       while( xReturn == queueERRONEOUS_UNBLOCK );\r
+\r
+       prvUnlockQueue( pxQueue );\r
+       xTaskResumeAll();\r
 \r
        return xReturn;\r
 }\r
@@ -424,6 +432,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem
 signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
 {\r
 signed portBASE_TYPE xReturn;\r
+xTimeOutType xTimeOut;\r
 \r
        /* This function is very similar to xQueueSend().  See comments within\r
        xQueueSend() for a more detailed explanation.\r
@@ -431,68 +440,76 @@ signed portBASE_TYPE xReturn;
        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
-       /* If there are no messages in the queue we may have to block. */\r
-       if( prvIsQueueEmpty( pxQueue ) )\r
+       do\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 there are no messages in the queue we may have to block. */\r
+               if( prvIsQueueEmpty( pxQueue ) )\r
                {\r
-                       vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
-                       taskENTER_CRITICAL();\r
+                       /* There are no messages in the queue, do we want to block or just\r
+                       leave with nothing? */                  \r
+                       if( xTicksToWait > ( portTickType ) 0 )\r
                        {\r
-                               prvUnlockQueue( pxQueue );\r
-                               if( !xTaskResumeAll() )\r
+                               vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
+                               taskENTER_CRITICAL();\r
                                {\r
-                                       taskYIELD();\r
+                                       prvUnlockQueue( pxQueue );\r
+                                       if( !xTaskResumeAll() )\r
+                                       {\r
+                                               taskYIELD();\r
+                                       }\r
+       \r
+                                       vTaskSuspendAll();\r
+                                       prvLockQueue( pxQueue );\r
                                }\r
-\r
-                               vTaskSuspendAll();\r
-                               prvLockQueue( pxQueue );\r
+                               taskEXIT_CRITICAL();\r
                        }\r
-                       taskEXIT_CRITICAL();\r
                }\r
-       }\r
-\r
-       taskENTER_CRITICAL();\r
-       {\r
-               if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
+       \r
+               taskENTER_CRITICAL();\r
                {\r
-                       pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
-                       if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+                       if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
                        {\r
-                               pxQueue->pcReadFrom = pxQueue->pcHead;\r
+                               pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
+                               if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+                               {\r
+                                       pxQueue->pcReadFrom = pxQueue->pcHead;\r
+                               }\r
+                               --( pxQueue->uxMessagesWaiting );\r
+                               memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
+       \r
+                               /* Increment the lock count so prvUnlockQueue knows to check for\r
+                               tasks waiting for space to become available on the queue. */\r
+                               ++( pxQueue->xRxLock );\r
+                               xReturn = pdPASS;\r
+                       }\r
+                       else\r
+                       {\r
+                               xReturn = errQUEUE_EMPTY;\r
                        }\r
-                       --( pxQueue->uxMessagesWaiting );\r
-                       memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );\r
-\r
-                       /* Increment the lock count so prvUnlockQueue knows to check for\r
-                       tasks waiting for space to become available on the queue. */\r
-                       ++( pxQueue->xRxLock );\r
-                       xReturn = pdPASS;\r
                }\r
-               else\r
+               taskEXIT_CRITICAL();\r
+\r
+               if( xReturn == errQUEUE_EMPTY )\r
                {\r
-                       xReturn = pdFAIL;\r
+                       if( xTicksToWait > 0 )\r
+                       {\r
+                               if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )\r
+                               {\r
+                                       xReturn = queueERRONEOUS_UNBLOCK;\r
+                               }\r
+                       }\r
                }\r
-       }\r
-       taskEXIT_CRITICAL();\r
+       } while( xReturn == queueERRONEOUS_UNBLOCK );\r
 \r
        /* We no longer require exclusive access to the queue. */\r
-       if( prvUnlockQueue( pxQueue ) )\r
-       {\r
-               if( !xTaskResumeAll() )\r
-               {\r
-                       taskYIELD();\r
-               }\r
-       }\r
-       else\r
-       {\r
-               xTaskResumeAll();\r
-       }\r
+       prvUnlockQueue( pxQueue );\r
+       xTaskResumeAll();\r
 \r
        return xReturn;\r
 }\r
@@ -571,10 +588,8 @@ void vQueueDelete( xQueueHandle pxQueue )
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-static signed portBASE_TYPE prvUnlockQueue( xQueueHandle pxQueue )\r
+static void prvUnlockQueue( xQueueHandle pxQueue )\r
 {\r
-signed portBASE_TYPE xYieldRequired = pdFALSE;\r
-\r
        /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */\r
 \r
        /* The lock counts contains the number of extra data items placed or\r
@@ -600,7 +615,7 @@ signed portBASE_TYPE xYieldRequired = pdFALSE;
                                {\r
                                        /* The task waiting has a higher priority so record that a\r
                                        context switch is required. */\r
-                                       xYieldRequired = pdTRUE;\r
+                                       vTaskMissedYield();\r
                                }\r
                        }                       \r
                }\r
@@ -620,14 +635,12 @@ signed portBASE_TYPE xYieldRequired = pdFALSE;
                        {\r
                                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )\r
                                {\r
-                                       xYieldRequired = pdTRUE;\r
+                                       vTaskMissedYield();\r
                                }\r
                        }                       \r
                }\r
        }\r
        taskEXIT_CRITICAL();\r
-\r
-       return xYieldRequired;\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r