From: RichardBarry Date: Tue, 21 Aug 2007 16:54:48 +0000 (+0000) Subject: Added xQueueSendToBack, xQueueSendToFront, xQueuePeek and xSemaphoreCreateMutex ... X-Git-Tag: V4.5.0~6 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=fd2afe0c8be739e87606a4981633e6dff8aa8fe6;p=freertos Added xQueueSendToBack, xQueueSendToFront, xQueuePeek and xSemaphoreCreateMutex - along with GenQTest.c to demonstrate their usage. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@103 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/Demo/Common/Full/BlockQ.c b/Demo/Common/Full/BlockQ.c index 6c96a79b0..e7688ae33 100644 --- a/Demo/Common/Full/BlockQ.c +++ b/Demo/Common/Full/BlockQ.c @@ -89,7 +89,7 @@ Changes from V4.0.2 #include "BlockQ.h" #include "print.h" -#define blckqSTACK_SIZE ( ( unsigned portSHORT ) 128 ) +#define blckqSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE ) #define blckqNUM_TASK_SETS ( 3 ) /* Structure used to pass parameters to the blocking queue tasks. */ @@ -215,7 +215,7 @@ portSHORT sErrorEverOccurred = pdFALSE; for( ;; ) { - if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS ) + if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS ) { vPrintDisplayMessage( &pcTaskErrorMsg ); sErrorEverOccurred = pdTRUE; diff --git a/Demo/Common/Full/PollQ.c b/Demo/Common/Full/PollQ.c index dd6ac8bdd..cfd1cba37 100644 --- a/Demo/Common/Full/PollQ.c +++ b/Demo/Common/Full/PollQ.c @@ -78,7 +78,7 @@ Changes from V2.0.0 /* Demo program include files. */ #include "PollQ.h" -#define pollqSTACK_SIZE ( ( unsigned portSHORT ) 128 ) +#define pollqSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE ) /* The task that posts the incrementing number onto the queue. */ static void vPolledQueueProducer( void *pvParameters ); @@ -125,7 +125,7 @@ portSHORT sError = pdFALSE; for( usLoop = 0; usLoop < usNumToProduce; ++usLoop ) { /* Send an incrementing number on the queue without blocking. */ - if( xQueueSend( *pxQueue, ( void * ) &usValue, ( portTickType ) 0 ) != pdPASS ) + if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( portTickType ) 0 ) != pdPASS ) { /* We should never find the queue full - this is an error. */ vPrintDisplayMessage( &pcTaskErrorMsg ); diff --git a/Demo/Common/Full/dynamic.c b/Demo/Common/Full/dynamic.c index 128785d0d..454e7524a 100644 --- a/Demo/Common/Full/dynamic.c +++ b/Demo/Common/Full/dynamic.c @@ -146,7 +146,7 @@ static void prvChangePriorityHelperTask( void *pvParameters ); /* Demo task specific constants. */ -#define priSTACK_SIZE ( ( unsigned portSHORT ) 128 ) +#define priSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE ) #define priSLEEP_TIME ( ( portTickType ) 50 ) #define priLOOPS ( 5 ) #define priMAX_COUNT ( ( unsigned portLONG ) 0xff ) @@ -193,7 +193,7 @@ void vStartDynamicPriorityTasks( void ) xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL ); - xTaskCreate( prvChangePriorityHelperTask, "2nt_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle ); + xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle ); } /*-----------------------------------------------------------*/ diff --git a/Demo/Common/Full/events.c b/Demo/Common/Full/events.c index 630c11076..ab39bacfd 100644 --- a/Demo/Common/Full/events.c +++ b/Demo/Common/Full/events.c @@ -68,7 +68,7 @@ #include "print.h" /* Demo specific constants. */ -#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) 128 ) +#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE ) #define evtNUM_TASKS ( 4 ) #define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 ) #define evtNO_DELAY 0 diff --git a/Demo/Common/Minimal/GenQTest.c b/Demo/Common/Minimal/GenQTest.c new file mode 100644 index 000000000..275b814d3 --- /dev/null +++ b/Demo/Common/Minimal/GenQTest.c @@ -0,0 +1,536 @@ +/* + FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry. + + This file is part of the FreeRTOS.org distribution. + + FreeRTOS.org is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS.org; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS.org, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + + +/* + * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 - + * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and + * mutex behaviour. + * + * See the comments above the prvSendFrontAndBackTest() and + * prvLowPriorityMutexTask() prototypes below for more information. + */ + + +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* Demo program include files. */ +#include "GenQTest.h" + +#define genqQUEUE_LENGTH ( 5 ) +#define genqNO_BLOCK ( 0 ) + +#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY ) +#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 ) + +/*-----------------------------------------------------------*/ + +/* + * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack() + * macros by using both to fill a queue, then reading from the queue to + * check the resultant queue order is as expected. Queue data is also + * peeked. + */ +static void prvSendFrontAndBackTest( void *pvParameters ); + +/* + * The following three tasks are used to demonstrate the mutex behaviour. + * Each task is given a different priority to demonstrate the priority + * inheritance mechanism. + * + * The low priority task obtains a mutex. After this a high priority task + * attempts to obtain the same mutex, causing its priority to be inherited + * by the low priority task. The task with the inherited high priority then + * resumes a medium priority task to ensure it is not blocked by the medium + * priority task while it holds the inherited high priority. Once the mutex + * is returned the task with the inherited priority returns to its original + * low priority, and is therefore immediately preempted by first the high + * priority task and then the medium prioroity task before it can continue. + */ +static void prvLowPriorityMutexTask( void *pvParameters ); +static void prvMediumPriorityMutexTask( void *pvParameters ); +static void prvHighPriorityMutexTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* Flag that will be latched to pdTRUE should any unexpected behaviour be +detected in any of the tasks. */ +static portBASE_TYPE xErrorDetected = pdFALSE; + +/* Counters that are incremented on each cycle of a test. This is used to +detect a stalled task - a test that is no longer running. */ +static volatile unsigned portLONG ulLoopCounter = 0; +static volatile unsigned portLONG ulLoopCounter2 = 0; + +/* The variable that is guarded by the mutex in the mutex demo tasks. */ +static volatile unsigned portLONG ulGuardedVariable = 0; + +/* Handles used in the mutext test to suspend and resume the high and medium +priority mutex test tasks. */ +static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask; + +/*-----------------------------------------------------------*/ + +void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority ) +{ +xQueueHandle xQueue; +xSemaphoreHandle xMutex; + + /* Create the queue that we are going to use for the + prvSendFrontAndBackTest demo. */ + xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) ); + + /* Create the demo task and pass it the queue just created. We are + passing the queue handle by value so it does not matter that it is + declared on the stack here. */ + xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL ); + + /* Create the mutex used by the prvMutexTest task. */ + xMutex = xSemaphoreCreateMutex(); + + /* Create the mutex demo tasks and pass it the mutex just created. We are + passing the mutex handle by value so it does not matter that it is declared + on the stack here. */ + xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL ); + xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask ); + xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask ); +} +/*-----------------------------------------------------------*/ + +static void prvSendFrontAndBackTest( void *pvParameters ) +{ +unsigned portLONG ulData, ulData2; +xQueueHandle xQueue; + + #ifdef USE_STDIO + void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); + + const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n"; + + /* Queue a message for printing to say the task has started. */ + vPrintDisplayMessage( &pcTaskStartMsg ); + #endif + + xQueue = ( xQueueHandle ) pvParameters; + + for( ;; ) + { + /* The queue is empty, so sending an item to the back of the queue + should have the same efect as sending it to the front of the queue. + + First send to the front and check everything is as expected. */ + xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); + + if( uxQueueMessagesWaiting( xQueue ) != 1 ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* The data we sent to the queue should equal the data we just received + from the queue. */ + if( ulLoopCounter != ulData ) + { + xErrorDetected = pdTRUE; + } + + /* Then do the same, sending the data to the back, checking everything + is as expected. */ + if( uxQueueMessagesWaiting( xQueue ) != 0 ) + { + xErrorDetected = pdTRUE; + } + + xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK ); + + if( uxQueueMessagesWaiting( xQueue ) != 1 ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( uxQueueMessagesWaiting( xQueue ) != 0 ) + { + xErrorDetected = pdTRUE; + } + + /* The data we sent to the queue should equal the data we just received + from the queue. */ + if( ulLoopCounter != ulData ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + + + /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ + for( ulData = 2; ulData < 5; ulData++ ) + { + xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + } + + /* Now the order in the queue should be 2, 3, 4, with 2 being the first + thing to be read out. Now add 1 then 0 to the front of the queue. */ + if( uxQueueMessagesWaiting( xQueue ) != 3 ) + { + xErrorDetected = pdTRUE; + } + ulData = 1; + xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + ulData = 0; + xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ); + + /* Now the queue should be full, and when we read the data out we + should receive 0, 1, 2, 3, 4. */ + if( uxQueueMessagesWaiting( xQueue ) != 5 ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + /* Check the data we read out is in the expected order. */ + for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ ) + { + /* Try peeking the data first. */ + if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( ulData != ulData2 ) + { + xErrorDetected = pdTRUE; + } + + + /* Now try receiving the data for real. The value should be the + same. Clobber the value first so we know we really received it. */ + ulData2 = ~ulData2; + if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( ulData != ulData2 ) + { + xErrorDetected = pdTRUE; + } + } + + /* The queue should now be empty again. */ + if( uxQueueMessagesWaiting( xQueue ) != 0 ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + + /* Our queue is empty once more, add 10, 11 to the back. */ + ulData = 10; + if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + ulData = 11; + if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( uxQueueMessagesWaiting( xQueue ) != 2 ) + { + xErrorDetected = pdTRUE; + } + + /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the + front. */ + for( ulData = 9; ulData >= 7; ulData-- ) + { + if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + } + + /* Now check that the queue is full, and that receiving data provides + the expected sequence of 7, 8, 9, 10, 11. */ + if( uxQueueMessagesWaiting( xQueue ) != 5 ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + { + xErrorDetected = pdTRUE; + } + + if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL ) + { + xErrorDetected = pdTRUE; + } + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + + /* Check the data we read out is in the expected order. */ + for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ ) + { + if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + if( ulData != ulData2 ) + { + xErrorDetected = pdTRUE; + } + } + + if( uxQueueMessagesWaiting( xQueue ) != 0 ) + { + xErrorDetected = pdTRUE; + } + + ulLoopCounter++; + } +} +/*-----------------------------------------------------------*/ + +static void prvLowPriorityMutexTask( void *pvParameters ) +{ +xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters; + + #ifdef USE_STDIO + void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); + + const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n"; + + /* Queue a message for printing to say the task has started. */ + vPrintDisplayMessage( &pcTaskStartMsg ); + #endif + + for( ;; ) + { + /* Take the mutex. It should be available now. */ + if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* Set our guarded variable to a known start value. */ + ulGuardedVariable = 0; + + /* Our priority should be as per that assigned when the task was + created. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now unsuspend the high priority task. This will attempt to take the + mutex, and block when it finds it cannot obtain it. */ + vTaskResume( xHighPriorityMutexTask ); + + /* We should now have inherited the prioritoy of the high priority task, + as by now it will have attempted to get the mutex. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* We can attempt to set our priority to the test priority - between the + idle priority and the medium/high test priorities, but our actual + prioroity should remain at the high priority. */ + vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); + if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Now unsuspend the medium priority task. This should not run as our + inherited priority is above that of the medium priority task. */ + vTaskResume( xMediumPriorityMutexTask ); + + /* If the did run then it will have incremented our guarded variable. */ + if( ulGuardedVariable != 0 ) + { + xErrorDetected = pdTRUE; + } + + /* When we give back the semaphore our priority should be disinherited + back to the priority to which we attempted to set ourselves. This means + that when the high priority task next blocks, the medium priority task + should execute and increment the guarded variable. When we next run + both the high and medium priority tasks will have been suspended again. */ + if( xSemaphoreGive( xMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* Check that the guarded variable did indeed increment... */ + if( ulGuardedVariable != 1 ) + { + xErrorDetected = pdTRUE; + } + + /* ... and that our priority has been disinherited to + genqMUTEX_TEST_PRIORITY. */ + if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) + { + xErrorDetected = pdTRUE; + } + + /* Set our priority back to our original priority ready for the next + loop around this test. */ + vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); + + /* Just to show we are still running. */ + ulLoopCounter2++; + + #if configUSE_PREEMPTION == 0 + taskYIELD(); + #endif + } +} +/*-----------------------------------------------------------*/ + +static void prvMediumPriorityMutexTask( void *pvParameters ) +{ + for( ;; ) + { + /* The medium priority task starts by suspending itself. The low + priority task will unsuspend this task when required. */ + vTaskSuspend( NULL ); + + /* When this task unsuspends all it does is increment the guarded + variable, this is so the low priority task knows that it has + executed. */ + ulGuardedVariable++; + } +} +/*-----------------------------------------------------------*/ + +static void prvHighPriorityMutexTask( void *pvParameters ) +{ +xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters; + + for( ;; ) + { + /* The high priority task starts by suspending itself. The low + priority task will unsuspend this task when required. */ + vTaskSuspend( NULL ); + + /* When this task unsuspends all it does is attempt to obtain + the mutex. It should find the mutex is not available so a + block time is specified. */ + if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + + /* When we eventually obtain the mutex we just give it back then + return to suspend ready for the next test. */ + if( xSemaphoreGive( xMutex ) != pdPASS ) + { + xErrorDetected = pdTRUE; + } + } +} +/*-----------------------------------------------------------*/ + +/* This is called to check that all the created tasks are still running. */ +portBASE_TYPE xAreGenericQueueTasksStillRunning( void ) +{ +static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0; + + /* If the demo task is still running then we expect the loopcounters to + have incremented since this function was last called. */ + if( ulLastLoopCounter == ulLoopCounter ) + { + xErrorDetected = pdTRUE; + } + + if( ulLastLoopCounter2 == ulLoopCounter2 ) + { + xErrorDetected = pdTRUE; + } + + ulLastLoopCounter = ulLoopCounter; + ulLastLoopCounter2 = ulLoopCounter2; + + /* Errors detected in the task itself will have latched xErrorDetected + to true. */ + + return !xErrorDetected; +} + + diff --git a/Demo/Common/include/GenQTest.h b/Demo/Common/include/GenQTest.h new file mode 100644 index 000000000..8adbb7b13 --- /dev/null +++ b/Demo/Common/include/GenQTest.h @@ -0,0 +1,45 @@ +/* + FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry. + + This file is part of the FreeRTOS.org distribution. + + FreeRTOS.org is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS.org; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS.org, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + +#ifndef GEN_Q_TEST_H +#define GEN_Q_TEST_H + +void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority ); +portBASE_TYPE xAreGenericQueueTasksStillRunning( void ); + +#endif /* GEN_Q_TEST_H */ + + + diff --git a/Demo/PC/FreeRTOSConfig.h b/Demo/PC/FreeRTOSConfig.h index 0920a60e6..97eb232d3 100644 --- a/Demo/PC/FreeRTOSConfig.h +++ b/Demo/PC/FreeRTOSConfig.h @@ -53,13 +53,14 @@ #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 1 #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) -#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 128 ) /* This can be made smaller if required. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 256 ) /* This can be made smaller if required. */ #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 32 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 1 #define configIDLE_SHOULD_YIELD 1 #define configUSE_CO_ROUTINES 1 +#define configUSE_MUTEXES 1 #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 10 ) #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) diff --git a/Demo/PC/main.c b/Demo/PC/main.c index 055095f1d..6811bbb10 100644 --- a/Demo/PC/main.c +++ b/Demo/PC/main.c @@ -119,6 +119,7 @@ Changes from V3.2.4 #include "mevents.h" #include "crhook.h" #include "blocktim.h" +#include "GenQTest.h" /* Priority definitions for the tasks in the demo application. */ #define mainLED_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) @@ -128,6 +129,7 @@ Changes from V3.2.4 #define mainQUEUE_BLOCK_PRIORITY ( tskIDLE_PRIORITY + 3 ) #define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define mainSEMAPHORE_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainGENERIC_QUEUE_PRIORITY ( tskIDLE_PRIORITY ) #define mainPRINT_STACK_SIZE ( ( unsigned portSHORT ) 512 ) #define mainDEBUG_LOG_BUFFER_SIZE ( ( unsigned portSHORT ) 20480 ) @@ -176,7 +178,7 @@ portSHORT main( void ) vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); vStartBlockingQueueTasks( mainQUEUE_BLOCK_PRIORITY ); vCreateBlockTimeTasks(); - + vStartGenericQueueTasks( mainGENERIC_QUEUE_PRIORITY ); vStartSemaphoreTasks( mainSEMAPHORE_TASK_PRIORITY ); vStartDynamicPriorityTasks(); vStartMultiEventTasks(); @@ -391,6 +393,12 @@ static portSHORT sErrorHasOccurred = pdFALSE; sErrorHasOccurred = pdTRUE; } + if( xAreGenericQueueTasksStillRunning() != pdTRUE ) + { + vDisplayMessage( "Error in generic queue test task!\r\n" ); + sErrorHasOccurred = pdTRUE; + } + if( sErrorHasOccurred == pdFALSE ) { vDisplayMessage( "OK " ); diff --git a/Demo/PC/rtosdemo.tgt b/Demo/PC/rtosdemo.tgt index 7b5f2d66d..53595149d 100644 --- a/Demo/PC/rtosdemo.tgt +++ b/Demo/PC/rtosdemo.tgt @@ -15,7 +15,7 @@ WString de6en 1 0 -0 +1 4 MCommand 0 @@ -75,7 +75,7 @@ WVList 0 19 WPickList -50 +52 20 MItem 3 @@ -97,11 +97,11 @@ WCC WString 25 d????Include directories: -1 +0 26 WString -97 -$(%watcom)\h;..\common\include;..\..\source\include;..\..\source\portable\owatcom\16bitdos\common +99 +$(%watcom)\h;..\common\include;..\..\source\include;..\..\source\portable\owatcom\16bitdos\common;. 0 27 MCState @@ -113,7 +113,7 @@ WCC WString 26 ?????Force ANSI compliance -1 +0 1 30 MCState @@ -125,7 +125,7 @@ WCC WString 33 ?????Disable stack depth checking -1 +0 1 33 MVState @@ -137,11 +137,11 @@ WCC WString 23 ?????Macro definitions: -1 +0 36 WString -52 -OPEN_WATCOM_INDUSTRIAL_PC_PORT USE_STDIO DEBUG_BUILD +40 +OPEN_WATCOM_INDUSTRIAL_PC_PORT USE_STDIO 0 37 MCState @@ -153,7 +153,7 @@ WCC WString 34 ?????Change char default to signed -1 +0 1 40 MRState @@ -163,10 +163,10 @@ WString WCC 42 WString -21 -?????Compiler default -1 +29 +?????No debugging information 0 +1 43 MRState 44 @@ -175,9 +175,9 @@ WString WCC 45 WString -21 -?????Compiler default -1 +28 +?????Line number information +0 0 46 MRState @@ -187,22 +187,22 @@ WString WCC 48 WString -25 -?????Floating-point calls -1 -1 +21 +?????Compiler default +0 +0 49 -MCState +MRState 50 WString 3 WCC 51 WString -31 -???e?SS not assumed equal to DS -1 -1 +21 +?????Compiler default +0 +0 52 MRState 53 @@ -211,114 +211,114 @@ WString WCC 54 WString -9 -??6??8086 -1 +25 +?????Floating-point calls 0 +1 55 -MRState +MCState 56 WString 3 WCC 57 WString -10 -??6??80186 -1 +31 +???e?SS not assumed equal to DS +0 1 58 -MVState +MRState 59 WString 3 WCC 60 WString -25 -d????Include directories: +9 +??6??8086 0 -61 -WString -99 -$(%watcom)\h;..\common\include;..\..\source\include;..\..\source\portable\owatcom\16bitdos\common;. 0 +61 +MRState 62 -MCState -63 WString 3 WCC -64 +63 WString -26 -?????Force ANSI compliance +10 +??6??80186 0 1 +64 +MVState 65 -MCState -66 WString 3 WCC +66 +WString +25 +d????Include directories: +1 67 WString -33 -?????Disable stack depth checking +97 +$(%watcom)\h;..\common\include;..\..\source\include;..\..\source\portable\owatcom\16bitdos\common 0 -1 68 -MVState +MCState 69 WString 3 WCC 70 WString -23 -?????Macro definitions: -0 +26 +?????Force ANSI compliance +1 +1 71 -WString -40 -OPEN_WATCOM_INDUSTRIAL_PC_PORT USE_STDIO -0 +MVState 72 -MCState -73 WString 3 WCC +73 +WString +23 +?????Macro definitions: +1 74 WString -34 -?????Change char default to signed +52 +OPEN_WATCOM_INDUSTRIAL_PC_PORT USE_STDIO DEBUG_BUILD 0 -1 75 -MRState +MCState 76 WString 3 WCC 77 WString -29 -?????No debugging information -0 +34 +?????Change char default to signed +1 1 78 -MRState +MCState 79 WString 3 WCC 80 WString -28 -?????Line number information -0 -0 +33 +?????Disable stack depth checking +1 +1 81 MRState 82 @@ -329,7 +329,7 @@ WCC WString 21 ?????Compiler default -0 +1 0 84 MRState @@ -341,7 +341,7 @@ WCC WString 21 ?????Compiler default -0 +1 0 87 MRState @@ -353,7 +353,7 @@ WCC WString 25 ?????Floating-point calls -0 +1 1 90 MCState @@ -365,7 +365,7 @@ WCC WString 31 ???e?SS not assumed equal to DS -0 +1 1 93 MRState @@ -377,7 +377,7 @@ WCC WString 9 ??6??8086 -0 +1 0 96 MRState @@ -389,7 +389,7 @@ WCC WString 10 ??6??80186 -0 +1 1 99 WVList @@ -760,8 +760,8 @@ WVList 0 180 MItem -15 -fileio\fileio.c +28 +..\COMMON\MINIMAL\GenQTest.c 181 WString 4 @@ -778,8 +778,8 @@ WVList 0 184 MItem -6 -main.c +15 +fileio\fileio.c 185 WString 4 @@ -796,8 +796,8 @@ WVList 0 188 MItem -17 -partest\partest.c +6 +main.c 189 WString 4 @@ -814,8 +814,8 @@ WVList 0 192 MItem -15 -serial\serial.c +17 +partest\partest.c 193 WString 4 @@ -832,26 +832,26 @@ WVList 0 196 MItem -3 -*.h +15 +serial\serial.c 197 WString -3 -NIL +4 +COBJ 198 WVList 0 199 WVList 0 --1 +20 +1 1 -0 0 200 MItem -31 -..\..\SOURCE\INCLUDE\croutine.h +3 +*.h 201 WString 3 @@ -862,14 +862,14 @@ WVList 203 WVList 0 -196 -1 +-1 1 0 +0 204 MItem -27 -..\..\source\include\list.h +31 +..\..\SOURCE\INCLUDE\croutine.h 205 WString 3 @@ -880,14 +880,14 @@ WVList 207 WVList 0 -196 +200 1 1 0 208 MItem -31 -..\..\source\include\portable.h +27 +..\..\source\include\list.h 209 WString 3 @@ -898,14 +898,14 @@ WVList 211 WVList 0 -196 +200 1 1 0 212 MItem 31 -..\..\source\include\projdefs.h +..\..\source\include\portable.h 213 WString 3 @@ -916,14 +916,14 @@ WVList 215 WVList 0 -196 +200 1 1 0 216 MItem -28 -..\..\source\include\queue.h +31 +..\..\source\include\projdefs.h 217 WString 3 @@ -934,14 +934,14 @@ WVList 219 WVList 0 -196 +200 1 1 0 220 MItem -29 -..\..\source\include\semphr.h +28 +..\..\source\include\queue.h 221 WString 3 @@ -952,14 +952,14 @@ WVList 223 WVList 0 -196 +200 1 1 0 224 MItem -27 -..\..\source\include\task.h +29 +..\..\source\include\semphr.h 225 WString 3 @@ -970,14 +970,14 @@ WVList 227 WVList 0 -196 +200 1 1 0 228 MItem -55 -..\..\source\portable\owatcom\16bitdos\common\portasm.h +27 +..\..\source\include\task.h 229 WString 3 @@ -988,14 +988,14 @@ WVList 231 WVList 0 -196 +200 1 1 0 232 MItem -53 -..\..\source\portable\owatcom\16bitdos\pc\portmacro.h +55 +..\..\source\portable\owatcom\16bitdos\common\portasm.h 233 WString 3 @@ -1006,14 +1006,14 @@ WVList 235 WVList 0 -196 +200 1 1 0 236 MItem -26 -..\common\include\blockq.h +53 +..\..\source\portable\owatcom\16bitdos\pc\portmacro.h 237 WString 3 @@ -1024,14 +1024,14 @@ WVList 239 WVList 0 -196 +200 1 1 0 240 MItem -28 -..\COMMON\INCLUDE\blocktim.h +26 +..\common\include\blockq.h 241 WString 3 @@ -1042,14 +1042,14 @@ WVList 243 WVList 0 -196 +200 1 1 0 244 MItem -27 -..\common\include\comtest.h +28 +..\COMMON\INCLUDE\blocktim.h 245 WString 3 @@ -1060,14 +1060,14 @@ WVList 247 WVList 0 -196 +200 1 1 0 248 MItem -26 -..\COMMON\INCLUDE\crhook.h +27 +..\common\include\comtest.h 249 WString 3 @@ -1078,14 +1078,14 @@ WVList 251 WVList 0 -196 +200 1 1 0 252 MItem -25 -..\common\include\death.h +26 +..\COMMON\INCLUDE\crhook.h 253 WString 3 @@ -1096,14 +1096,14 @@ WVList 255 WVList 0 -196 +200 1 1 0 256 MItem -27 -..\COMMON\INCLUDE\dynamic.h +25 +..\common\include\death.h 257 WString 3 @@ -1114,14 +1114,14 @@ WVList 259 WVList 0 -196 +200 1 1 0 260 MItem -26 -..\common\include\fileio.h +27 +..\COMMON\INCLUDE\dynamic.h 261 WString 3 @@ -1132,14 +1132,14 @@ WVList 263 WVList 0 -196 +200 1 1 0 264 MItem -25 -..\common\include\flash.h +26 +..\common\include\fileio.h 265 WString 3 @@ -1150,14 +1150,14 @@ WVList 267 WVList 0 -196 +200 1 1 0 268 MItem -24 -..\common\include\flop.h +25 +..\common\include\flash.h 269 WString 3 @@ -1168,14 +1168,14 @@ WVList 271 WVList 0 -196 +200 1 1 0 272 MItem -27 -..\common\include\partest.h +24 +..\common\include\flop.h 273 WString 3 @@ -1186,14 +1186,14 @@ WVList 275 WVList 0 -196 +200 1 1 0 276 MItem -25 -..\common\include\pollq.h +28 +..\COMMON\INCLUDE\GenQTest.h 277 WString 3 @@ -1204,14 +1204,14 @@ WVList 279 WVList 0 -196 +200 1 1 0 280 MItem -25 -..\common\include\print.h +27 +..\common\include\partest.h 281 WString 3 @@ -1222,14 +1222,14 @@ WVList 283 WVList 0 -196 +200 1 1 0 284 MItem -27 -..\common\include\semtest.h +25 +..\common\include\pollq.h 285 WString 3 @@ -1240,14 +1240,14 @@ WVList 287 WVList 0 -196 +200 1 1 0 288 MItem -26 -..\common\include\serial.h +25 +..\common\include\print.h 289 WString 3 @@ -1258,14 +1258,14 @@ WVList 291 WVList 0 -196 +200 1 1 0 292 MItem -16 -FreeRTOSConfig.h +27 +..\common\include\semtest.h 293 WString 3 @@ -1276,7 +1276,43 @@ WVList 295 WVList 0 -196 +200 +1 +1 +0 +296 +MItem +26 +..\common\include\serial.h +297 +WString +3 +NIL +298 +WVList +0 +299 +WVList +0 +200 +1 +1 +0 +300 +MItem +16 +FreeRTOSConfig.h +301 +WString +3 +NIL +302 +WVList +0 +303 +WVList +0 +200 1 1 0 diff --git a/Demo/PC/rtosdemo.wpj b/Demo/PC/rtosdemo.wpj index 1b02cfb2f..25dbb7d79 100644 --- a/Demo/PC/rtosdemo.wpj +++ b/Demo/PC/rtosdemo.wpj @@ -31,7 +31,7 @@ WRect 0 0 7168 -7168 +8523 0 0 9 @@ -39,5 +39,5 @@ WFileName 12 rtosdemo.tgt 0 -25 +26 7 diff --git a/Demo/PC/serial/serial.c b/Demo/PC/serial/serial.c index 566530b42..b8625d724 100644 --- a/Demo/PC/serial/serial.c +++ b/Demo/PC/serial/serial.c @@ -500,6 +500,7 @@ static portSHORT sComPortISR( const xComPort * const pxPort ) portSHORT sInterruptID; portCHAR cIn, cOut; portBASE_TYPE xTaskWokenByPost = pdFALSE, xAnotherTaskWokenByPost = pdFALSE, xTaskWokenByTx = pdFALSE; +extern void vComTestUnsuspendTask( void ); portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, ( portINPUT_BYTE( pxPort->us8259InterruptMaskReg) | ~pxPort->ucInterruptEnableMast ) ); diff --git a/Source/include/FreeRTOS.h b/Source/include/FreeRTOS.h index 11ca53f62..3c02e6c6f 100644 --- a/Source/include/FreeRTOS.h +++ b/Source/include/FreeRTOS.h @@ -19,13 +19,13 @@ A special exception to the GPL can be applied should you wish to distribute a combined work that includes FreeRTOS.org, without being obliged to provide - the source code for any proprietary components. See the licensing section + the source code for any proprietary components. See the licensing section of http://www.FreeRTOS.org for full details of how and when the exception can be applied. *************************************************************************** - See http://www.FreeRTOS.org for documentation, latest information, license - and contact details. Please ensure to read the configuration and relevant + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant port sections of the online documentation. Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along @@ -37,8 +37,8 @@ #define INC_FREERTOS_H -/* - * Include the generic headers required for the FreeRTOS port being used. +/* + * Include the generic headers required for the FreeRTOS port being used. */ #include @@ -58,7 +58,7 @@ /* - * Check all the required application specific macros have been defined. + * Check all the required application specific macros have been defined. * These macros are application specific and (as downloaded) are defined * within FreeRTOSConfig.h. */ @@ -111,4 +111,19 @@ #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif +#ifndef configUSE_MUTEXES + #define configUSE_MUTEXES 0 +#endif + +#if ( configUSE_MUTEXES == 1 ) + /* xTaskGetCurrentTaskHandle is used by the priority inheritance mechanism + within the mutex implementation so must be available if mutexes are used. */ + #undef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 1 +#else + #ifndef INCLUDE_xTaskGetCurrentTaskHandle + #define INCLUDE_xTaskGetCurrentTaskHandle 0 + #endif #endif + +#endif /* INC_FREERTOS_H */ diff --git a/Source/include/queue.h b/Source/include/queue.h index 6ded97871..c9d448989 100644 --- a/Source/include/queue.h +++ b/Source/include/queue.h @@ -19,13 +19,13 @@ A special exception to the GPL can be applied should you wish to distribute a combined work that includes FreeRTOS.org, without being obliged to provide - the source code for any proprietary components. See the licensing section + the source code for any proprietary components. See the licensing section of http://www.FreeRTOS.org for full details of how and when the exception can be applied. *************************************************************************** - See http://www.FreeRTOS.org for documentation, latest information, license - and contact details. Please ensure to read the configuration and relevant + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant port sections of the online documentation. Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along @@ -38,12 +38,17 @@ typedef void * xQueueHandle; +/* For internal use only. */ +#define queueSEND_TO_BACK ( 0 ) +#define queueSEND_TO_FRONT ( 1 ) + + /** * queue. h *
- xQueueHandle xQueueCreate( 
-                              unsigned portBASE_TYPE uxQueueLength, 
-                              unsigned portBASE_TYPE uxItemSize 
+ xQueueHandle xQueueCreate(
+                              unsigned portBASE_TYPE uxQueueLength,
+                              unsigned portBASE_TYPE uxItemSize
                           );
  * 
* @@ -52,15 +57,15 @@ typedef void * xQueueHandle; * * @param uxQueueLength The maximum number of items that the queue can contain. * - * @param uxItemSize The number of bytes each item in the queue will require. + * @param uxItemSize The number of bytes each item in the queue will require. * Items are queued by copy, not by reference, so this is the number of bytes * that will be copied for each posted item. Each item on the queue must be * the same size. * - * @return If the queue is successfully create then a handle to the newly + * @return If the queue is successfully create then a handle to the newly * created queue is returned. If the queue cannot be created then 0 is * returned. - * + * * Example usage:
  struct AMessage
@@ -99,20 +104,273 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA
 /**
  * queue. h
  * 
- portBASE_TYPE xQueueSend( 
-                             xQueueHandle xQueue, 
-                             const void * pvItemToQueue, 
-                             portTickType xTicksToWait 
+ portBASE_TYPE xQueueSendToToFront(
+                                   xQueueHandle xQueue,
+                                   const void * pvItemToQueue,
+                                   portTickType xTicksToWait
+                               );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the front of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0. The + * time is defined in tick periods so the constant portTICK_RATE_MS + * should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+    // Create a queue capable of containing 10 unsigned long values.
+    xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+    // Create a queue capable of containing 10 pointers to AMessage structures.
+    // These should be passed by pointer as they contain a lot of data.
+    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+    // ...
+
+    if( xQueue1 != 0 )
+    {
+        // Send an unsigned long.  Wait for 10 ticks for space to become
+        // available if necessary.
+        if( xQueueSendToFront( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+        {
+            // Failed to post the message, even after 10 ticks.
+        }
+    }
+
+    if( xQueue2 != 0 )
+    {
+        // Send a pointer to a struct AMessage object.  Don't block if the
+        // queue is already full.
+        pxMessage = & xMessage;
+        xQueueSendToFront( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+    }
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_FRONT ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToBack(
+                                   xQueueHandle xQueue,
+                                   const void * pvItemToQueue,
+                                   portTickType xTicksToWait
+                               );
+ * 
+ * + * This is a macro that calls xQueueGenericSend(). + * + * Post an item to the back of a queue. The item is queued by copy, not by + * reference. This function must not be called from an interrupt service + * routine. See xQueueSendFromISR () for an alternative which may be used + * in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0. The + * time is defined in tick periods so the constant portTICK_RATE_MS + * should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+    // Create a queue capable of containing 10 unsigned long values.
+    xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+    // Create a queue capable of containing 10 pointers to AMessage structures.
+    // These should be passed by pointer as they contain a lot of data.
+    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+    // ...
+
+    if( xQueue1 != 0 )
+    {
+        // Send an unsigned long.  Wait for 10 ticks for space to become
+        // available if necessary.
+        if( xQueueSendToBack( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+        {
+            // Failed to post the message, even after 10 ticks.
+        }
+    }
+
+    if( xQueue2 != 0 )
+    {
+        // Send a pointer to a struct AMessage object.  Don't block if the
+        // queue is already full.
+        pxMessage = & xMessage;
+        xQueueSendToBack( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+    }
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueSend(
+                              xQueueHandle xQueue,
+                              const void * pvItemToQueue,
+                              portTickType xTicksToWait
                          );
  * 
* + * This is a macro that calls xQueueGenericSend(). It is included for + * backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToFront() and xQueueSendToBack() macros. It is + * equivalent to xQueueSendToBack(). + * + * Post an item on a queue. The item is queued by copy, not by reference. + * This function must not be called from an interrupt service routine. + * See xQueueSendFromISR () for an alternative which may be used in an ISR. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for space to become available on the queue, should it already + * be full. The call will return immediately if this is set to 0. The + * time is defined in tick periods so the constant portTICK_RATE_MS + * should be used to convert to real time if this is required. + * + * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * + * Example usage: +
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+    // Create a queue capable of containing 10 unsigned long values.
+    xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+    // Create a queue capable of containing 10 pointers to AMessage structures.
+    // These should be passed by pointer as they contain a lot of data.
+    xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+    // ...
+
+    if( xQueue1 != 0 )
+    {
+        // Send an unsigned long.  Wait for 10 ticks for space to become
+        // available if necessary.
+        if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+        {
+            // Failed to post the message, even after 10 ticks.
+        }
+    }
+
+    if( xQueue2 != 0 )
+    {
+        // Send a pointer to a struct AMessage object.  Don't block if the
+        // queue is already full.
+        pxMessage = & xMessage;
+        xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+    }
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, queueSEND_TO_BACK ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueGenericSend(
+									xQueueHandle xQueue,
+									const void * pvItemToQueue,
+									portTickType xTicksToWait
+									portBASE_TYPE xCopyPosition
+								);
+ * 
+ * + * It is preferred that the macros xQueueSend(), xQueueSendToFront() and + * xQueueSendToBack() are used in place of calling this function directly. + * * Post an item on a queue. The item is queued by copy, not by reference. * This function must not be called from an interrupt service routine. * See xQueueSendFromISR () for an alternative which may be used in an ISR. * * @param xQueue The handle to the queue on which the item is to be posted. - * - * @param pvItemToQueue A pointer to the item that is to be placed on the + * + * @param pvItemToQueue A pointer to the item that is to be placed on the * queue. The size of the items the queue will hold was defined when the * queue was created, so this many bytes will be copied from pvItemToQueue * into the queue storage area. @@ -120,9 +378,13 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA * @param xTicksToWait The maximum amount of time the task should block * waiting for space to become available on the queue, should it already * be full. The call will return immediately if this is set to 0. The - * time is defined in tick periods so the constant portTICK_RATE_MS + * time is defined in tick periods so the constant portTICK_RATE_MS * should be used to convert to real time if this is required. * + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. * * Example usage: @@ -145,46 +407,234 @@ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBA // Create a queue capable of containing 10 pointers to AMessage structures. // These should be passed by pointer as they contain a lot of data. - xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); + xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); + + // ... + + if( xQueue1 != 0 ) + { + // Send an unsigned long. Wait for 10 ticks for space to become + // available if necessary. + if( xQueueGenericSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10, queueSEND_TO_BACK ) != pdPASS ) + { + // Failed to post the message, even after 10 ticks. + } + } + + if( xQueue2 != 0 ) + { + // Send a pointer to a struct AMessage object. Don't block if the + // queue is already full. + pxMessage = & xMessage; + xQueueGenericSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0, queueSEND_TO_BACK ); + } + + // ... Rest of task code. + } +
+ * \defgroup xQueueSend xQueueSend + * \ingroup QueueManagement + */ +signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portTickType xCopyPosition ); + +/** + * queue. h + *
+ portBASE_TYPE xQueuePeek(
+                             xQueueHandle xQueue,
+                             void *pvBuffer,
+                             portTickType xTicksToWait
+                         );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue without removing the item from the queue. + * The item is received by copy so a buffer of adequate size must be + * provided. The number of bytes copied into the buffer was defined when + * the queue was created. + * + * Successfully received items remain on the queue so will be returned again + * by the next call, or a call to xQueueReceive(). + * + * This macro must not be used in an interrupt service routine. + * + * @param pxQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+    // Create a queue capable of containing 10 pointers to AMessage structures.
+    // These should be passed by pointer as they contain a lot of data.
+    xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+    if( xQueue == 0 )
+    {
+        // Failed to create the queue.
+    }
+
+    // ...
+
+    // Send a pointer to a struct AMessage object.  Don't block if the
+    // queue is already full.
+    pxMessage = & xMessage;
+    xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to peek the data from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+    if( xQueue != 0 )
+    {
+        // Peek a message on the created queue.  Block for 10 ticks if a
+        // message is not immediately available.
+        if( xQueuePeek( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+        {
+            // pcRxedMessage now points to the struct AMessage variable posted
+            // by vATask, but the item still remains on the queue.
+        }
+    }
+
+	// ... Rest of task code.
+ }
+ 
+ * \defgroup xQueueReceive xQueueReceive + * \ingroup QueueManagement + */ +#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdTRUE ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueReceive(
+                                 xQueueHandle xQueue,
+                                 void *pvBuffer,
+                                 portTickType xTicksToWait
+                            );
+ * + * This is a macro that calls the xQueueGenericReceive() function. + * + * Receive an item from a queue. The item is received by copy so a buffer of + * adequate size must be provided. The number of bytes copied into the buffer + * was defined when the queue was created. + * + * Successfully received items are removed from the queue. + * + * This function must not be used in an interrupt service routine. See + * xQueueReceiveFromISR for an alternative that can. + * + * @param pxQueue The handle to the queue from which the item is to be + * received. + * + * @param pvBuffer Pointer to the buffer into which the received item will + * be copied. + * + * @param xTicksToWait The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. The time is defined in tick periods so the constant + * portTICK_RATE_MS should be used to convert to real time if this is required. + * + * @return pdTRUE if an item was successfully received from the queue, + * otherwise pdFALSE. + * + * Example usage: +
+ struct AMessage
+ {
+    portCHAR ucMessageID;
+    portCHAR ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+    // Create a queue capable of containing 10 pointers to AMessage structures.
+    // These should be passed by pointer as they contain a lot of data.
+    xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+    if( xQueue == 0 )
+    {
+        // Failed to create the queue.
+    }
 
     // ...
 
-    if( xQueue1 != 0 )
+    // Send a pointer to a struct AMessage object.  Don't block if the
+    // queue is already full.
+    pxMessage = & xMessage;
+    xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+	// ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+    if( xQueue != 0 )
     {
-        // Send an unsigned long.  Wait for 10 ticks for space to become 
-        // available if necessary.
-        if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+        // Receive a message on the created queue.  Block for 10 ticks if a
+        // message is not immediately available.
+        if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
         {
-            // Failed to post the message, even after 10 ticks.
+            // pcRxedMessage now points to the struct AMessage variable posted
+            // by vATask.
         }
     }
 
-    if( xQueue2 != 0 )
-    {
-        // Send a pointer to a struct AMessage object.  Don't block if the
-        // queue is already full.
-        pxMessage = & xMessage;
-        xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
-    }
-
 	// ... Rest of task code.
  }
  
- * \defgroup xQueueSend xQueueSend + * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( xQueue, pvBuffer, xTicksToWait, pdFALSE ) + /** * queue. h *
- portBASE_TYPE xQueueReceive( 
-                                xQueueHandle xQueue, 
-                                void *pvBuffer, 
-                                portTickType xTicksToWait 
-                            );
+ portBASE_TYPE xQueueGenericReceive( + xQueueHandle xQueue, + void *pvBuffer, + portTickType xTicksToWait + portBASE_TYPE xJustPeek + ); + * + * It is preferred that the macro xQueueReceive() be used rather than calling + * this function directly. * - * Receive an item from a queue. The item is received by copy so a buffer of + * Receive an item from a queue. The item is received by copy so a buffer of * adequate size must be provided. The number of bytes copied into the buffer * was defined when the queue was created. * @@ -196,12 +646,17 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue * * @param pvBuffer Pointer to the buffer into which the received item will * be copied. - * + * * @param xTicksToWait The maximum amount of time the task should block * waiting for an item to receive should the queue be empty at the time - * of the call. The time is defined in tick periods so the constant + * of the call. The time is defined in tick periods so the constant * portTICK_RATE_MS should be used to convert to real time if this is required. * + * @param xJustPeek When set to true, the item received from the queue is not + * actually removed from the queue - meaning a subsequent call to + * xQueueReceive() will return the same item. When set to false, the item + * being received from the queue is also removed from the queue. + * * @return pdTRUE if an item was successfully received from the queue, * otherwise pdFALSE. * @@ -214,7 +669,7 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue } xMessage; xQueueHandle xQueue; - + // Task to create a queue and post a value. void vATask( void *pvParameters ) { @@ -247,7 +702,7 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue { // Receive a message on the created queue. Block for 10 ticks if a // message is not immediately available. - if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) ) + if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) ) { // pcRxedMessage now points to the struct AMessage variable posted // by vATask. @@ -260,7 +715,7 @@ signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait ); +signed portBASE_TYPE xQueueGenericReceive( xQueueHandle xQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeek ); /** * queue. h @@ -269,7 +724,7 @@ signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTic * Return the number of messages stored in a queue. * * @param xQueue A handle to the queue being queried. - * + * * @return The number of messages available in the queue. * * \page uxQueueMessagesWaiting uxQueueMessagesWaiting @@ -283,7 +738,7 @@ unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue ); * * Delete a queue - freeing all the memory allocated for storing of items * placed on the queue. - * + * * @param xQueue A handle to the queue to be deleted. * * \page vQueueDelete vQueueDelete @@ -294,13 +749,254 @@ void vQueueDelete( xQueueHandle xQueue ); /** * queue. h *
- portBASE_TYPE xQueueSendFromISR( 
-                                    xQueueHandle pxQueue, 
-                                    const void *pvItemToQueue, 
-                                    portBASE_TYPE xTaskPreviouslyWoken 
+ portBASE_TYPE xQueueSendToFrontFromISR(
+                                         xQueueHandle pxQueue,
+                                         const void *pvItemToQueue,
+                                         portBASE_TYPE xTaskPreviouslyWoken
+                                      );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the front of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param cTaskPreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. See the file serial .c in the + * PC port for a good example of this mechanism. + * + * @return pdTRUE if a task was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+    // We have not woken a task at the start of the ISR.
+    cTaskWokenByPost = pdFALSE;
+
+    // Loop until the buffer is empty.
+    do
+    {
+        // Obtain a byte from the buffer.
+        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );						
+
+        // Post the byte.  The first time round the loop cTaskWokenByPost
+        // will be pdFALSE.  If the queue send causes a task to wake we do
+        // not want the task to run until we have finished the ISR, so
+        // xQueueSendFromISR does not cause a context switch.  Also we
+        // don't want subsequent posts to wake any other tasks, so we store
+        // the return value back into cTaskWokenByPost so xQueueSendFromISR
+        // knows not to wake any task the next iteration of the loop.
+        xTaskWokenByPost = xQueueSendToFrontFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+    } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+    // Now the buffer is empty we can switch context if necessary.
+    if( cTaskWokenByPost )
+    {
+        taskYIELD ();
+    }
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToFromFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_FRONT ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendToBackFromISR(
+                                         xQueueHandle pxQueue,
+                                         const void *pvItemToQueue,
+                                         portBASE_TYPE xTaskPreviouslyWoken
+                                      );
+ 
+ * + * This is a macro that calls xQueueGenericSendFromISR(). + * + * Post an item to the back of a queue. It is safe to use this macro from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param cTaskPreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. See the file serial .c in the + * PC port for a good example of this mechanism. + * + * @return pdTRUE if a task was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+    // We have not woken a task at the start of the ISR.
+    cTaskWokenByPost = pdFALSE;
+
+    // Loop until the buffer is empty.
+    do
+    {
+        // Obtain a byte from the buffer.
+        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );						
+
+        // Post the byte.  The first time round the loop cTaskWokenByPost
+        // will be pdFALSE.  If the queue send causes a task to wake we do
+        // not want the task to run until we have finished the ISR, so
+        // xQueueSendFromISR does not cause a context switch.  Also we
+        // don't want subsequent posts to wake any other tasks, so we store
+        // the return value back into cTaskWokenByPost so xQueueSendFromISR
+        // knows not to wake any task the next iteration of the loop.
+        xTaskWokenByPost = xQueueSendToBackFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+    } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+    // Now the buffer is empty we can switch context if necessary.
+    if( cTaskWokenByPost )
+    {
+        taskYIELD ();
+    }
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendToBackFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_BACK ) + + +/** + * queue. h + *
+ portBASE_TYPE xQueueSendFromISR(
+                                     xQueueHandle pxQueue,
+                                     const void *pvItemToQueue,
+                                     portBASE_TYPE xTaskPreviouslyWoken
                                 );
  
* + * This is a macro that calls xQueueGenericSendFromISR(). It is included + * for backward compatibility with versions of FreeRTOS.org that did not + * include the xQueueSendToBackFromISR() and xQueueSendToFrontFromISR() + * macros. + * + * Post an item to the back of a queue. It is safe to use this function from + * within an interrupt service routine. + * + * Items are queued by copy not reference so it is preferable to only + * queue small items, especially when called from an ISR. In most cases + * it would be preferable to store a pointer to the item being queued. + * + * @param xQueue The handle to the queue on which the item is to be posted. + * + * @param pvItemToQueue A pointer to the item that is to be placed on the + * queue. The size of the items the queue will hold was defined when the + * queue was created, so this many bytes will be copied from pvItemToQueue + * into the queue storage area. + * + * @param cTaskPreviouslyWoken This is included so an ISR can post onto + * the same queue multiple times from a single interrupt. The first call + * should always pass in pdFALSE. Subsequent calls should pass in + * the value returned from the previous call. See the file serial .c in the + * PC port for a good example of this mechanism. + * + * @return pdTRUE if a task was woken by posting onto the queue. This is + * used by the ISR to determine if a context switch may be required following + * the ISR. + * + * Example usage for buffered IO (where the ISR can obtain more than one value + * per call): +
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+    // We have not woken a task at the start of the ISR.
+    cTaskWokenByPost = pdFALSE;
+
+    // Loop until the buffer is empty.
+    do
+    {
+        // Obtain a byte from the buffer.
+        cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );						
+
+        // Post the byte.  The first time round the loop cTaskWokenByPost
+        // will be pdFALSE.  If the queue send causes a task to wake we do
+        // not want the task to run until we have finished the ISR, so
+        // xQueueSendFromISR does not cause a context switch.  Also we
+        // don't want subsequent posts to wake any other tasks, so we store
+        // the return value back into cTaskWokenByPost so xQueueSendFromISR
+        // knows not to wake any task the next iteration of the loop.
+        xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+    } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+    // Now the buffer is empty we can switch context if necessary.
+    if( cTaskWokenByPost )
+    {
+        taskYIELD ();
+    }
+ }
+ 
+ * + * \defgroup xQueueSendFromISR xQueueSendFromISR + * \ingroup QueueManagement + */ +#define xQueueSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken ) xQueueGenericSendFromISR( pxQueue, pvItemToQueue, xTaskPreviouslyWoken, queueSEND_TO_BACK ) + +/** + * queue. h + *
+ portBASE_TYPE xQueueGenericSendFromISR(
+                                           xQueueHandle pxQueue,
+                                           const void *pvItemToQueue,
+                                           portBASE_TYPE xTaskPreviouslyWoken
+										   portBASE_TYPE xCopyPosition
+                                       );
+ 
+ * + * It is preferred that the macros xQueueSendFromISR(), + * xQueueSendToFrontFromISR() and xQueueSendToBackFromISR() be used in place + * of calling this function directly. + * * Post an item on a queue. It is safe to use this function from within an * interrupt service routine. * @@ -309,8 +1005,8 @@ void vQueueDelete( xQueueHandle xQueue ); * it would be preferable to store a pointer to the item being queued. * * @param xQueue The handle to the queue on which the item is to be posted. - * - * @param pvItemToQueue A pointer to the item that is to be placed on the + * + * @param pvItemToQueue A pointer to the item that is to be placed on the * queue. The size of the items the queue will hold was defined when the * queue was created, so this many bytes will be copied from pvItemToQueue * into the queue storage area. @@ -321,7 +1017,11 @@ void vQueueDelete( xQueueHandle xQueue ); * the value returned from the previous call. See the file serial .c in the * PC port for a good example of this mechanism. * - * @return pdTRUE if a task was woken by posting onto the queue. This is + * @param xCopyPosition Can take the value queueSEND_TO_BACK to place the + * item at the back of the queue, or queueSEND_TO_FRONT to place the item + * at the front of the queue (for high priority messages). + * + * @return pdTRUE if a task was woken by posting onto the queue. This is * used by the ISR to determine if a context switch may be required following * the ISR. * @@ -345,11 +1045,11 @@ void vQueueDelete( xQueueHandle xQueue ); // Post the byte. The first time round the loop cTaskWokenByPost // will be pdFALSE. If the queue send causes a task to wake we do // not want the task to run until we have finished the ISR, so - // xQueueSendFromISR does not cause a context switch. Also we + // xQueueSendFromISR does not cause a context switch. Also we // don't want subsequent posts to wake any other tasks, so we store // the return value back into cTaskWokenByPost so xQueueSendFromISR // knows not to wake any task the next iteration of the loop. - xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost ); + xTaskWokenByPost = xQueueGenericSendFromISR( xRxQueue, &cIn, cTaskWokenByPost, queueSEND_TO_BACK ); } while( portINPUT_BYTE( BUFFER_COUNT ) ); @@ -364,16 +1064,16 @@ void vQueueDelete( xQueueHandle xQueue ); * \defgroup xQueueSendFromISR xQueueSendFromISR * \ingroup QueueManagement */ -signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken ); +signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition ); /** * queue. h *
- portBASE_TYPE xQueueReceiveFromISR( 
-                                       xQueueHandle pxQueue, 
-                                       void *pvBuffer, 
-                                       portBASE_TYPE *pxTaskWoken 
-                                   ); 
+ portBASE_TYPE xQueueReceiveFromISR(
+                                       xQueueHandle pxQueue,
+                                       void *pvBuffer,
+                                       portBASE_TYPE *pxTaskWoken
+                                   );
  * 
* * Receive an item from a queue. It is safe to use this function from within an @@ -384,7 +1084,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem * * @param pvBuffer Pointer to the buffer into which the received item will * be copied. - * + * * @param pxTaskWoken A task may be blocked waiting for space to become * available on the queue. If xQueueReceiveFromISR causes such a task to * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will @@ -395,9 +1095,9 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem * * Example usage:
- 
+
  xQueueHandle xQueue;
- 
+
  // Function to create a queue and post some values.
  void vAFunction( void *pvParameters )
  {
@@ -427,7 +1127,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem
     xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
  }
 
- // ISR that outputs all the characters received on the queue. 
+ // ISR that outputs all the characters received on the queue.
  void vISR_Routine( void )
  {
  portBASE_TYPE xTaskWokenByReceive = pdFALSE;
@@ -438,7 +1138,7 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem
         // A character was received.  Output the character now.
         vOutputCharacter( cRxedChar );
 
-        // If removing the character from the queue woke the task that was 
+        // If removing the character from the queue woke the task that was
         // posting onto the queue cTaskWokenByReceive will have been set to
         // pdTRUE.  No matter how many times this loop iterates only one
         // task will be woken.
@@ -453,13 +1153,13 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem
  * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
  * \ingroup QueueManagement
  */
-signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken );
 
 
-/* 
- * The functions defined above are for passing data to and from tasks.  The 
- * functions below are the equivalents for passing data to and from 
- * co-rtoutines.
+/*
+ * The functions defined above are for passing data to and from tasks.  The
+ * functions below are the equivalents for passing data to and from
+ * co-routines.
  *
  * These functions are called from the co-routine macro implementation and
  * should not be called directly from application code.  Instead use the macro
@@ -470,5 +1170,11 @@ signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffe
 signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
 signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
 
-#endif
+/*
+ * For internal use only.  Use xSemaphoreCreateMutex() instead of calling
+ * this function directly.
+ */
+xQueueHandle xQueueCreateMutex( void );
+
+#endif /* QUEUE_H */
 
diff --git a/Source/include/semphr.h b/Source/include/semphr.h
index 266ad1ae9..18bbb444d 100644
--- a/Source/include/semphr.h
+++ b/Source/include/semphr.h
@@ -54,6 +54,13 @@ typedef xQueueHandle xSemaphoreHandle;
  * as we don't want to actually store any data - we just want to know if the
  * queue is empty or full.
  *
+ * This type of semaphore can be used for pure synchronisation between tasks or
+ * between an interrupt and a task.  The semaphore need not be given back once
+ * obtained, so one task/interrupt can continuously 'give' the semaphore while
+ * another continuously 'takes' the semaphore.  For this reason this type of
+ * semaphore does not use a priority inheritance mechanism.  For an alternative
+ * that does use priority inheritance see xSemaphoreCreateMutex().
+ *
  * @param xSemaphore Handle to the created semaphore.  Should be of type xSemaphoreHandle.
  *
  * Example usage:
@@ -205,7 +212,7 @@ typedef xQueueHandle xSemaphoreHandle;
  * \defgroup xSemaphoreGive xSemaphoreGive
  * \ingroup Semaphores
  */
-#define xSemaphoreGive( xSemaphore )				xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME )
+#define xSemaphoreGive( xSemaphore )				xQueueGenericSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
 
 /**
  * semphr. h
@@ -218,6 +225,9 @@ typedef xQueueHandle xSemaphoreHandle;
  * Macro to  release a semaphore.  The semaphore must of been created using 
  * vSemaphoreCreateBinary (), and obtained using xSemaphoreTake ().
  *
+ * Mutex type semaphores (those created using a call to xSemaphoreCreateMutex())
+ * must not be used with this macro.
+ *
  * This macro can be used from an ISR.
  *
  * @param xSemaphore A handle to the semaphore being released.  This is the
@@ -285,8 +295,52 @@ typedef xQueueHandle xSemaphoreHandle;
  * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
  * \ingroup Semaphores
  */
-#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken )			xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken )
+#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken )			xQueueGenericSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken, queueSEND_TO_BACK )
+
+/**
+ * semphr. h
+ * 
xSemaphoreCreateMutex( xSemaphoreHandle xSemaphore )
+ * + * Macro that implements a mutex semaphore by using the existing queue + * mechanism. + * + * This type of semaphore uses a priority inheritance mechanism so a task + * 'taking' a semaphore MUST ALWAYS 'give' the semaphore back once the + * semaphore it is no longer required. + * + * Mutex type semaphores cannot be used from within interrupt service routines. + * + * See xSemaphoreCreateBinary() for an alternative implemnetation that can be + * used for pure synchronisation (where one task or interrupt always 'gives' the + * semaphore and another always 'takes' the semaphore) and from within interrupt + * service routines. + * + * @param xSemaphore Handle to the created mutex semaphore. Should be of type + * xSemaphoreHandle. + * + * Example usage: +
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+    // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+    // This is a macro so pass the variable in directly.
+    vSemaphoreCreateMutex( xSemaphore );
+
+    if( xSemaphore != NULL )
+    {
+        // The semaphore was created successfully.
+        // The semaphore can now be used.  
+    }
+ }
+ 
+ * \defgroup vSemaphoreCreateMutex vSemaphoreCreateMutex + * \ingroup Semaphores + */ +#define xSemaphoreCreateMutex() xQueueCreateMutex() + +#endif /* SEMAPHORE_H */ -#endif diff --git a/Source/include/task.h b/Source/include/task.h index 7a4d1095b..6535fc8b3 100644 --- a/Source/include/task.h +++ b/Source/include/task.h @@ -364,7 +364,7 @@ void vTaskDelay( portTickType xTicksToDelay ); * \defgroup vTaskDelayUntil vTaskDelayUntil * \ingroup TaskCtrl */ -void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement ); +void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ); /** * task. h @@ -894,7 +894,7 @@ inline void vTaskIncrementTick( void ); * portTICK_RATE_MS can be used to convert kernel ticks into a real time * period. */ -void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait ); +void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ); /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -911,7 +911,7 @@ void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait ); * @return pdTRUE if the task being removed has a higher priority than the task * making the call, otherwise pdFALSE. */ -signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList ); +signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ); /* * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN @@ -944,13 +944,13 @@ xTaskHandle xTaskGetCurrentTaskHandle( void ); /* * Capture the current time status for future reference. */ -void vTaskSetTimeOutState( xTimeOutType *pxTimeOut ); +void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ); /* * Compare the time status now with that previously captured to see if the * timeout has expired. */ -portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait ); +portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ); /* * Shortcut used by the queue implementation to prevent unnecessary call to @@ -964,6 +964,18 @@ void vTaskMissedYield( void ); */ portBASE_TYPE xTaskGetSchedulerState( void ); +/* + * Raises the priority of the mutex holder to that of the calling task should + * the mutex holder have a priority less than the calling task. + */ +void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ); + +/* + * Set the priority of a task back to its proper priority in the case that it + * inherited a higher priority while it was holding a semaphore. + */ +void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ); + #endif /* TASK_H */ diff --git a/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h b/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h index 51e80a3e7..1fbcc85b4 100644 --- a/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h +++ b/Source/portable/Paradigm/Tern_EE/large_untested/portasm.h @@ -51,18 +51,18 @@ void portSWITCH_CONTEXT( void ); */ void portFIRST_CONTEXT( void ); -#define portSWITCH_CONTEXT() -// asm { mov ax, seg pxCurrentTCB } -// asm { mov ds, ax } -// asm { les bx, pxCurrentTCB } /* Save the stack pointer into the TCB. */ -// asm { mov es:0x2[ bx ], ss } -// asm { mov es:[ bx ], sp } -// asm { call far ptr vTaskSwitchContext } /* Perform the switch. */ -// asm { mov ax, seg pxCurrentTCB } /* Restore the stack pointer from the TCB. */ -// asm { mov ds, ax } -// asm { les bx, dword ptr pxCurrentTCB } -// asm { mov ss, es:[ bx + 2 ] } -// asm { mov sp, es:[ bx ] } +#define portSWITCH_CONTEXT() \ + asm { mov ax, seg pxCurrentTCB } \ + asm { mov ds, ax } \ + asm { les bx, pxCurrentTCB } /* Save the stack pointer into the TCB. */ \ + asm { mov es:0x2[ bx ], ss } \ + asm { mov es:[ bx ], sp } \ + asm { call far ptr vTaskSwitchContext } /* Perform the switch. */ \ + asm { mov ax, seg pxCurrentTCB } /* Restore the stack pointer from the TCB. */ \ + asm { mov ds, ax } \ + asm { les bx, dword ptr pxCurrentTCB } \ + asm { mov ss, es:[ bx + 2 ] } \ + asm { mov sp, es:[ bx ] } #define portFIRST_CONTEXT() \ asm { mov ax, seg pxCurrentTCB } \ @@ -70,7 +70,7 @@ void portFIRST_CONTEXT( void ); asm { les bx, dword ptr pxCurrentTCB } \ asm { mov ss, es:[ bx + 2 ] } \ asm { mov sp, es:[ bx ] } \ - asm { pop bx } \ + asm { pop bp } \ asm { pop di } \ asm { pop si } \ asm { pop ds } \ diff --git a/Source/queue.c b/Source/queue.c index 58d8ccde8..0431715df 100644 --- a/Source/queue.c +++ b/Source/queue.c @@ -70,9 +70,9 @@ Changes from V4.1.2: Changes from V4.1.3: - + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) - case whereby a task unblocking due to a temporal event can remove/send an - item from/to a queue when a higher priority task is still blocked on the + + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely) + case whereby a task unblocking due to a temporal event can remove/send an + item from/to a queue when a higher priority task is still blocked on the queue. This modification is a result of the SafeRTOS testing. */ @@ -90,6 +90,15 @@ Changes from V4.1.3: #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 ) #define queueERRONEOUS_UNBLOCK ( -1 ) +/* For internal use only. */ +#define queueSEND_TO_BACK ( 0 ) +#define queueSEND_TO_FRONT ( 1 ) + +/* Effectively make a union out of the xQUEUE structure. */ +#define pxMutexHolder pcTail +#define uxQueueType pcHead +#define queueQUEUE_IS_MUTEX NULL + /* * Definition of the queue used by the scheduler. * Items are queued by copy, not reference. @@ -109,8 +118,8 @@ typedef struct QueueDefinition unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */ unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */ - signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ - signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ + signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */ } xQUEUE; /*-----------------------------------------------------------*/ @@ -127,12 +136,13 @@ typedef xQUEUE * xQueueHandle; * functions are documented in the API header file. */ xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ); -signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); +signed portBASE_TYPE xQueueGenericSend( xQueueHandle xQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ); unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue ); void vQueueDelete( xQueueHandle xQueue ); -signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken ); -signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ); -signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ); +signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition ); +signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ); +signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ); +xQueueHandle xQueueCreateMutex( void ); #if configUSE_CO_ROUTINES == 1 signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ); @@ -166,20 +176,15 @@ static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue ); static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue ); /* - * Macro that copies an item into the queue. This is done by copying the item - * byte for byte, not by reference. Updates the queue state to ensure it's - * integrity after the copy. + * Copies an item into the queue, either at the front of the queue or the + * back of the queue. */ -#define prvCopyQueueData( pxQueue, pvItemToQueue ) \ -{ \ - memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \ - ++( pxQueue->uxMessagesWaiting ); \ - pxQueue->pcWriteTo += pxQueue->uxItemSize; \ - if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \ - { \ - pxQueue->pcWriteTo = pxQueue->pcHead; \ - } \ -} +static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ); + +/* + * Copies an item out of a queue. + */ +static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ); /*-----------------------------------------------------------*/ /* @@ -248,7 +253,49 @@ size_t xQueueSizeInBytes; } /*-----------------------------------------------------------*/ -signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) +#if ( configUSE_MUTEXES == 1 ) + + xQueueHandle xQueueCreateMutex( void ) + { + xQUEUE *pxNewQueue; + + /* Allocate the new queue structure. */ + pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) ); + if( pxNewQueue != NULL ) + { + /* Information required for priority inheritance. */ + pxNewQueue->pxMutexHolder = NULL; + pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; + + /* Queues used as a mutex no data is actually copied into or out + of the queue. */ + pxNewQueue->pcWriteTo = NULL; + pxNewQueue->pcReadFrom = NULL; + + /* Each mutex has a length of 1 (like a binary semaphore) and + an item size of 0 as nothing is actually copied into or out + of the mutex. */ + pxNewQueue->uxMessagesWaiting = 0; + pxNewQueue->uxLength = 1; + pxNewQueue->uxItemSize = 0; + pxNewQueue->xRxLock = queueUNLOCKED; + pxNewQueue->xTxLock = queueUNLOCKED; + + /* Ensure the event queues start with the correct state. */ + vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); + vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); + + /* Start with the semaphore in the expected state. */ + xQueueGenericSend( pxNewQueue, NULL, 0, queueSEND_TO_BACK ); + } + + return pxNewQueue; + } + +#endif /* configUSE_MUTEXES */ +/*-----------------------------------------------------------*/ + +signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { signed portBASE_TYPE xReturn = pdPASS; xTimeOutType xTimeOut; @@ -285,15 +332,15 @@ xTimeOutType xTimeOut; queue being modified here. Places where the event list is modified include: - + xQueueSendFromISR(). This checks the lock on the queue to see if - it has access. If the queue is locked then the Tx lock count is + + xQueueGenericSendFromISR(). This checks the lock on the queue to see + if it has access. If the queue is locked then the Tx lock count is incremented to signify that a task waiting for data can be made ready once the queue lock is removed. If the queue is not locked then a task can be moved from the event list, but will not be removed from the delayed list or placed in the ready list until the scheduler is unlocked. - + xQueueReceiveFromISR(). As per xQueueSendFromISR(). + + xQueueReceiveFromISR(). As per xQueueGenericSendFromISR(). */ /* If the queue is already full we may have to block. */ @@ -390,7 +437,7 @@ xTimeOutType xTimeOut; if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { /* There is room in the queue, copy the data into the queue. */ - prvCopyQueueData( pxQueue, pvItemToQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); xReturn = pdPASS; /* Update the TxLock count so prvUnlockQueue knows to check for @@ -425,16 +472,16 @@ xTimeOutType xTimeOut; } /*-----------------------------------------------------------*/ -signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken ) +signed portBASE_TYPE xQueueGenericSendFromISR( xQueueHandle pxQueue, const void * const pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken, portBASE_TYPE xCopyPosition ) { - /* Similar to xQueueSend, except we don't block if there is no room in the - queue. Also we don't directly wake a task that was blocked on a queue - read, instead we return a flag to say whether a context switch is required - or not (i.e. has a task with a higher priority than us been woken by this - post). */ + /* Similar to xQueueGenericSend, except we don't block if there is no room + in the queue. Also we don't directly wake a task that was blocked on a + queue read, instead we return a flag to say whether a context switch is + required or not (i.e. has a task with a higher priority than us been woken + by this post). */ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { - prvCopyQueueData( pxQueue, pvItemToQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); /* If the queue is locked we do not alter the event list. This will be done when the queue is unlocked later. */ @@ -467,13 +514,14 @@ signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItem } /*-----------------------------------------------------------*/ -signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) +signed portBASE_TYPE xQueueGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) { signed portBASE_TYPE xReturn = pdTRUE; xTimeOutType xTimeOut; +signed portCHAR *pcOriginalReadPosition; - /* This function is very similar to xQueueSend(). See comments within - xQueueSend() for a more detailed explanation. + /* This function is very similar to xQueueGenericSend(). See comments + within xQueueGenericSend() for a more detailed explanation. Make sure other tasks do not access the queue. */ vTaskSuspendAll(); @@ -493,6 +541,17 @@ xTimeOutType xTimeOut; leave with nothing? */ if( xTicksToWait > ( portTickType ) 0 ) { + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + portENTER_CRITICAL(); + vTaskPriorityInherit( ( xTaskHandle * const ) pxQueue->pxMutexHolder ); + portEXIT_CRITICAL(); + } + } + #endif + vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); taskENTER_CRITICAL(); { @@ -522,18 +581,39 @@ xTimeOutType xTimeOut; { if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { - pxQueue->pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->pcReadFrom >= pxQueue->pcTail ) + /* Remember our read position in case we are just peeking. */ + pcOriginalReadPosition = pxQueue->pcReadFrom; + + prvCopyDataFromQueue( pxQueue, pvBuffer ); + + if( xJustPeeking == pdFALSE ) { - pxQueue->pcReadFrom = pxQueue->pcHead; + /* We are actually removing data. */ + --( pxQueue->uxMessagesWaiting ); + + /* Increment the lock count so prvUnlockQueue knows to check for + tasks waiting for space to become available on the queue. */ + ++( pxQueue->xRxLock ); + + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* Record the information required to implement + priority inheritance should it become necessary. */ + pxQueue->pxMutexHolder = xTaskGetCurrentTaskHandle(); + } + } + #endif } - --( pxQueue->uxMessagesWaiting ); - memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); - - /* Increment the lock count so prvUnlockQueue knows to check for - tasks waiting for space to become available on the queue. */ - ++( pxQueue->xRxLock ); - xReturn = pdPASS; + else + { + /* We are not removing the data, so reset our read + pointer. */ + pxQueue->pcReadFrom = pcOriginalReadPosition; + } + + xReturn = pdPASS; } else { @@ -563,21 +643,15 @@ xTimeOutType xTimeOut; } /*-----------------------------------------------------------*/ -signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) +signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void * const pvBuffer, signed portBASE_TYPE *pxTaskWoken ) { signed portBASE_TYPE xReturn; /* We cannot block from an ISR, so check there is data available. */ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { - /* Copy the data from the queue. */ - pxQueue->pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->pcReadFrom >= pxQueue->pcTail ) - { - pxQueue->pcReadFrom = pxQueue->pcHead; - } + prvCopyDataFromQueue( pxQueue, pvBuffer ); --( pxQueue->uxMessagesWaiting ); - memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); /* If the queue is locked we will not modify the event list. Instead we update the lock count so the task that unlocks the queue will know @@ -636,6 +710,57 @@ void vQueueDelete( xQueueHandle pxQueue ) } /*-----------------------------------------------------------*/ +static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) +{ + if( pxQueue->uxItemSize == 0 ) + { + #if ( configUSE_MUTEXES == 1 ) + { + if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) + { + /* The mutex is no longer being held. */ + vTaskPriorityDisinherit( ( xTaskHandle * const ) pxQueue->pxMutexHolder ); + } + } + #endif + } + else if( xPosition == queueSEND_TO_BACK ) + { + memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); + pxQueue->pcWriteTo += pxQueue->uxItemSize; + if( pxQueue->pcWriteTo >= pxQueue->pcTail ) + { + pxQueue->pcWriteTo = pxQueue->pcHead; + } + } + else + { + memcpy( ( void * ) pxQueue->pcReadFrom, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); + pxQueue->pcReadFrom -= pxQueue->uxItemSize; + if( pxQueue->pcReadFrom < pxQueue->pcHead ) + { + pxQueue->pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); + } + } + + ++( pxQueue->uxMessagesWaiting ); +} +/*-----------------------------------------------------------*/ + +static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) +{ + if( pxQueue->uxQueueType != queueQUEUE_IS_MUTEX ) + { + pxQueue->pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->pcReadFrom = pxQueue->pcHead; + } + memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + } +} +/*-----------------------------------------------------------*/ + static void prvUnlockQueue( xQueueHandle pxQueue ) { /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */ @@ -722,7 +847,7 @@ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQue signed portBASE_TYPE xReturn; /* If the queue is already full we may have to block. A critical section - is required to prevent an interrupt removing something from the queue + is required to prevent an interrupt removing something from the queue between the check to see if the queue is full and blocking on the queue. */ portDISABLE_INTERRUPTS(); { @@ -754,19 +879,19 @@ signed portBASE_TYPE xReturn; if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { /* There is room in the queue, copy the data into the queue. */ - prvCopyQueueData( pxQueue, pvItemToQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); xReturn = pdPASS; /* Were any co-routines waiting for data to become available? */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) { - /* In this instance the co-routine could be placed directly - into the ready list as we are within a critical section. - Instead the same pending ready list mechansim is used as if + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if the event were caused from within an interrupt. */ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The co-routine waiting has a higher priority so record + /* The co-routine waiting has a higher priority so record that a yield might be appropriate. */ xReturn = errQUEUE_YIELD; } @@ -790,7 +915,7 @@ signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, port signed portBASE_TYPE xReturn; /* If the queue is already empty we may have to block. A critical section - is required to prevent an interrupt adding something to the queue + is required to prevent an interrupt adding something to the queue between the check to see if the queue is empty and blocking on the queue. */ portDISABLE_INTERRUPTS(); { @@ -835,9 +960,9 @@ signed portBASE_TYPE xReturn; /* Were any co-routines waiting for space to become available? */ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) { - /* In this instance the co-routine could be placed directly - into the ready list as we are within a critical section. - Instead the same pending ready list mechansim is used as if + /* In this instance the co-routine could be placed directly + into the ready list as we are within a critical section. + Instead the same pending ready list mechanism is used as if the event were caused from within an interrupt. */ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { @@ -866,9 +991,9 @@ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvIt exit without doing anything. */ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { - prvCopyQueueData( pxQueue, pvItemToQueue ); + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); - /* We only want to wake one co-routine per ISR, so check that a + /* We only want to wake one co-routine per ISR, so check that a co-routine has not already been woken. */ if( !xCoRoutinePreviouslyWoken ) { diff --git a/Source/tasks.c b/Source/tasks.c index e572f5c09..7ed5637a1 100644 --- a/Source/tasks.c +++ b/Source/tasks.c @@ -229,10 +229,6 @@ Changes since V4.3.1: #define configMAX_TASK_NAME_LEN 16 #endif -#ifndef INCLUDE_xTaskGetCurrentTaskHandle - #define INCLUDE_xTaskGetCurrentTaskHandle 0 -#endif - #ifndef configIDLE_SHOULD_YIELD #define configIDLE_SHOULD_YIELD 1 #endif @@ -261,9 +257,16 @@ typedef struct tskTaskControlBlock xListItem xEventListItem; /*< List item used to place the TCB in event lists. */ unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */ portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */ - unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */ signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ - unsigned portSHORT usStackDepth; /*< Total depth of the stack (when empty). This is defined as the number of variables the stack can hold, not the number of bytes. */ + + #if ( configUSE_TRACE_FACILITY == 1 ) + unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */ + #endif + + #if ( configUSE_MUTEXES == 1 ) + unsigned portBASE_TYPE uxBasePriority; + #endif + } tskTCB; /*lint -e956 */ @@ -429,7 +432,7 @@ register tskTCB *pxTCB; \ * Utility to ready a TCB for a given task. Mainly just copies the parameters * into the TCB structure. */ -static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority ); +static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority ); /* * Utility to ready all the lists used by the scheduler. This is called @@ -485,7 +488,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); */ #if ( configUSE_TRACE_FACILITY == 1 ) - static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus ); + static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus ); #endif @@ -496,7 +499,7 @@ static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth ); */ #if ( configUSE_TRACE_FACILITY == 1 ) - unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte ); + unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ); #endif @@ -524,7 +527,9 @@ signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR { signed portBASE_TYPE xReturn; tskTCB * pxNewTCB; -static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */ +#if ( configUSE_TRACE_FACILITY == 1 ) + static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */ +#endif /* Allocate the memory required by the TCB and stack for the new task. checking that the allocation was successful. */ @@ -535,7 +540,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat portSTACK_TYPE *pxTopOfStack; /* Setup the newly allocated TCB with the initial state of the task. */ - prvInitialiseTCBVariables( pxNewTCB, usStackDepth, pcName, uxPriority ); + prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority ); /* Calculate the top of stack address. This depends on whether the stack grows from high memory to low (as per the 80x86) or visa versa. @@ -543,7 +548,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat required by the port. */ #if portSTACK_GROWTH < 0 { - pxTopOfStack = pxNewTCB->pxStack + ( pxNewTCB->usStackDepth - 1 ); + pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); } #else { @@ -593,9 +598,13 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat uxTopUsedPriority = pxNewTCB->uxPriority; } - /* Add a counter into the TCB for tracing only. */ - pxNewTCB->uxTCBNumber = uxTaskNumber; - uxTaskNumber++; + #if ( configUSE_TRACE_FACILITY == 1 ) + { + /* Add a counter into the TCB for tracing only. */ + pxNewTCB->uxTCBNumber = uxTaskNumber; + uxTaskNumber++; + } + #endif prvAddTaskToReadyQueue( pxNewTCB ); @@ -695,7 +704,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat #if ( INCLUDE_vTaskDelayUntil == 1 ) - void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement ) + void vTaskDelayUntil( portTickType * const pxPreviousWakeTime, portTickType xTimeIncrement ) { portTickType xTimeToWake; portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE; @@ -867,13 +876,22 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat /* If null is passed in here then we are changing the priority of the calling function. */ pxTCB = prvGetTCBFromHandle( pxTask ); - uxCurrentPriority = pxTCB->uxPriority; + + #if ( configUSE_MUTEXES == 1 ) + { + uxCurrentPriority = pxTCB->uxBasePriority; + } + #else + { + uxCurrentPriority = pxTCB->uxPriority; + } + #endif if( uxCurrentPriority != uxNewPriority ) { /* The priority change may have readied a task of higher priority than the calling task. */ - if( uxNewPriority > pxCurrentTCB->uxPriority ) + if( uxNewPriority > uxCurrentPriority ) { if( pxTask != NULL ) { @@ -891,7 +909,26 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat xYieldRequired = pdTRUE; } - pxTCB->uxPriority = uxNewPriority; + + + #if ( configUSE_MUTEXES == 1 ) + { + /* Only change the priority being used if the task is not + currently using an inherited priority. */ + if( pxTCB->uxBasePriority == pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + } + + /* The base priority gets set whatever. */ + pxTCB->uxBasePriority = uxNewPriority; + } + #else + { + pxTCB->uxPriority = uxNewPriority; + } + #endif + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxNewPriority ); /* If the task is in the blocked or suspended list we need do @@ -1051,7 +1088,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat { /* We cannot access the delayed or ready lists, so will hold this task pending until the scheduler is resumed, at which point a - yield will be preformed if necessary. */ + yield will be performed if necessary. */ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); } } @@ -1457,7 +1494,7 @@ void vTaskSwitchContext( void ) } /*-----------------------------------------------------------*/ -void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait ) +void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) { portTickType xTimeToWake; @@ -1527,7 +1564,7 @@ portTickType xTimeToWake; } /*-----------------------------------------------------------*/ -signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList ) +signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList ) { tskTCB *pxUnblockedTCB; portBASE_TYPE xReturn; @@ -1574,14 +1611,14 @@ portBASE_TYPE xReturn; } /*-----------------------------------------------------------*/ -void vTaskSetTimeOutState( xTimeOutType *pxTimeOut ) +void vTaskSetTimeOutState( xTimeOutType * const pxTimeOut ) { pxTimeOut->xOverflowCount = xNumOfOverflows; pxTimeOut->xTimeOnEntering = xTickCount; } /*-----------------------------------------------------------*/ -portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait ) +portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType * const pxTimeOut, portTickType * const pxTicksToWait ) { portBASE_TYPE xReturn; @@ -1701,10 +1738,8 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) -static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority ) +static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority ) { - pxTCB->usStackDepth = usStackDepth; - /* Store the function name in the TCB. */ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN ); pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0'; @@ -1716,6 +1751,11 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStack } pxTCB->uxPriority = uxPriority; + #if ( configUSE_MUTEXES == 1 ) + { + pxTCB->uxBasePriority = uxPriority; + } + #endif vListInitialiseItem( &( pxTCB->xGenericListItem ) ); vListInitialiseItem( &( pxTCB->xEventListItem ) ); @@ -1831,7 +1871,7 @@ tskTCB *pxNewTCB; #if ( configUSE_TRACE_FACILITY == 1 ) - static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus ) + static void prvListTaskWithinSingleList( const signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus ) { volatile tskTCB *pxNextTCB, *pxFirstTCB; static portCHAR pcStatusString[ 50 ]; @@ -1853,7 +1893,7 @@ tskTCB *pxNewTCB; /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) - unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte ) + unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR * pucStackByte ) { register unsigned portSHORT usCount = 0; @@ -1933,4 +1973,63 @@ tskTCB *pxNewTCB; #endif +#if ( configUSE_MUTEXES == 1 ) + + void vTaskPriorityInherit( xTaskHandle * const pxMutexHolder ) + { + tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; + + if( pxTCB->uxPriority < pxCurrentTCB->uxPriority ) + { + /* Adjust the mutex holder state to account for its new priority. */ + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxCurrentTCB->uxPriority ); + + /* If the task being modified is in the read state it will need to + be moved in to a new list. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ) ) + { + vListRemove( &( pxTCB->xGenericListItem ) ); + + /* Inherit the priority before being moved into the new list. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + prvAddTaskToReadyQueue( pxTCB ); + } + else + { + /* Just inherit the priority. */ + pxTCB->uxPriority = pxCurrentTCB->uxPriority; + } + } + } + +#endif + +#if ( configUSE_MUTEXES == 1 ) + + void vTaskPriorityDisinherit( xTaskHandle * const pxMutexHolder ) + { + tskTCB * const pxTCB = ( tskTCB * ) pxMutexHolder; + + if( pxMutexHolder != NULL ) + { + if( pxTCB->uxPriority != pxTCB->uxBasePriority ) + { + /* We must be the running task to be able to give the mutex back. + Remove ourselves from the ready list we currently appear in. */ + vListRemove( &( pxTCB->xGenericListItem ) ); + + /* Disinherit the priority before adding ourselves into the new + ready list. */ + pxTCB->uxPriority = pxTCB->uxBasePriority; + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) pxTCB->uxPriority ); + prvAddTaskToReadyQueue( pxTCB ); + } + } + } + +#endif + + + +