]> git.sur5r.net Git - freertos/blobdiff - Source/queue.c
Add an option for 8 byte alignment.
[freertos] / Source / queue.c
index 74aac9094b063adc769c3db77e148d9e69319c55..009e68360f9e1edd7bb269270868a6a6eae14c6c 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.1.1 - Copyright (C) 2003-2006 Richard Barry.\r
+       FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
@@ -60,6 +60,17 @@ Changes from V4.0.5
          functions exiting when a block time remains and the function has\r
          not completed.\r
 \r
+Changes from V4.1.2:\r
+\r
+       + BUG FIX:  Removed the call to prvIsQueueEmpty from within xQueueCRReceive\r
+         as it exited with interrupts enabled.  Thanks Paul Katz.\r
+\r
+Changes from V4.1.3:\r
+\r
+       + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) \r
+       case whereby a task unblocking due to a temporal event can remove/send an \r
+       item from/to a queue when a higher priority task is     still blocked on the \r
+       queue.  This modification is a result of the SafeRTOS testing.\r
 */\r
 \r
 #include <stdlib.h>\r
@@ -236,7 +247,7 @@ size_t xQueueSizeInBytes;
 \r
 signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )\r
 {\r
-signed portBASE_TYPE xReturn;\r
+signed portBASE_TYPE xReturn = pdPASS;\r
 xTimeOutType xTimeOut;\r
 \r
        /* Make sure other tasks do not access the queue. */\r
@@ -333,6 +344,20 @@ xTimeOutType xTimeOut;
                                        {\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
@@ -343,29 +368,39 @@ xTimeOutType xTimeOut;
                        }\r
                }\r
                        \r
-               /* When we are here it is possible that we unblocked as space became\r
-               available on the queue.  It is also possible that an ISR posted to the\r
-               queue since we left the critical section, so it may be that again there\r
-               is no space.  This would only happen if a task and ISR post onto the\r
-               same queue. */\r
-               taskENTER_CRITICAL();\r
+               /* If xReturn is errQUEUE_FULL then we unblocked when the queue\r
+               was still full.  Don't check it again now as it is possible that\r
+               an interrupt has removed an item from the queue since we left the\r
+               critical section and we don't want to write to the queue in case\r
+               there is a task of higher priority blocked waiting for space to\r
+               be available on the queue.  If this is the case the higher priority\r
+               task will execute when the scheduler is unsupended. */\r
+               if( xReturn != errQUEUE_FULL )\r
                {\r
-                       if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )\r
+                       /* 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
-                               /* 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
+                               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
+                       taskEXIT_CRITICAL();\r
                }\r
-               taskEXIT_CRITICAL();\r
 \r
                if( xReturn == errQUEUE_FULL )\r
                {\r
@@ -431,7 +466,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem
 \r
 signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )\r
 {\r
-signed portBASE_TYPE xReturn;\r
+signed portBASE_TYPE xReturn = pdTRUE;\r
 xTimeOutType xTimeOut;\r
 \r
        /* This function is very similar to xQueueSend().  See comments within\r
@@ -463,6 +498,13 @@ xTimeOutType xTimeOut;
                                        {\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
@@ -471,29 +513,32 @@ xTimeOutType xTimeOut;
                        }\r
                }\r
        \r
-               taskENTER_CRITICAL();\r
+               if( xReturn != errQUEUE_EMPTY )\r
                {\r
-                       if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
+                       taskENTER_CRITICAL();\r
                        {\r
-                               pxQueue->pcReadFrom += pxQueue->uxItemSize;\r
-                               if( pxQueue->pcReadFrom >= pxQueue->pcTail )\r
+                               if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )\r
                                {\r
-                                       pxQueue->pcReadFrom = pxQueue->pcHead;\r
+                                       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
-                       {\r
-                               xReturn = errQUEUE_EMPTY;\r
                        }\r
+                       taskEXIT_CRITICAL();\r
                }\r
-               taskEXIT_CRITICAL();\r
 \r
                if( xReturn == errQUEUE_EMPTY )\r
                {\r
@@ -746,7 +791,7 @@ signed portBASE_TYPE xReturn;
        between the check to see if the queue is empty and blocking on the queue. */\r
        portDISABLE_INTERRUPTS();\r
        {\r
-               if( prvIsQueueEmpty( pxQueue ) )\r
+               if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )\r
                {\r
                        /* There are no messages in the queue, do we want to block or just\r
                        leave with nothing? */                  \r