From d70e1b53d3477ee806a74068a0848236d50f5940 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Thu, 7 Feb 2013 15:10:25 +0000 Subject: [PATCH] Next revision of queue set implementation. Make conditional compilation syntax and commenting consistent. Add common demo tasks to demonstrate queue sets. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1817 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Demo/Common/Minimal/QueueSet.c | 276 +++++++++ FreeRTOS/Demo/Common/Minimal/integer.c | 31 +- FreeRTOS/Demo/Common/include/QueueSet.h | 77 +++ FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h | 26 +- FreeRTOS/Demo/WIN32-MSVC/WIN32.suo | Bin 55296 -> 62464 bytes FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj | 1 + .../Demo/WIN32-MSVC/WIN32.vcxproj.filters | 3 + FreeRTOS/Demo/WIN32-MSVC/main.c | 27 +- FreeRTOS/Source/include/FreeRTOS.h | 1 - FreeRTOS/Source/include/queue.h | 153 ++++- FreeRTOS/Source/queue.c | 553 ++++++++++++------ FreeRTOS/Source/tasks.c | 189 +++--- 12 files changed, 974 insertions(+), 363 deletions(-) create mode 100644 FreeRTOS/Demo/Common/Minimal/QueueSet.c create mode 100644 FreeRTOS/Demo/Common/include/QueueSet.h diff --git a/FreeRTOS/Demo/Common/Minimal/QueueSet.c b/FreeRTOS/Demo/Common/Minimal/QueueSet.c new file mode 100644 index 000000000..ef06c9be0 --- /dev/null +++ b/FreeRTOS/Demo/Common/Minimal/QueueSet.c @@ -0,0 +1,276 @@ +/* + FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. + + FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT + http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation AND MODIFIED BY the FreeRTOS exception. + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained + by writing to Richard Barry, contact details for whom are available on the + FreeRTOS WEB site. + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + + http://www.FreeRTOS.org - Documentation, training, latest versions, license + and contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool. + + Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell + the code with commercial support, indemnification, and middleware, under + the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also + provide a safety engineered and independently SIL3 certified version under + the SafeRTOS brand: http://www.SafeRTOS.com. +*/ + +/* + * Demonstrates the creation an use of queue sets. + * + * A receive task creates a number of queues and adds them to a queue set before + * blocking on a queue set receive. A transmit task repeatedly unblocks the + * receive task by sending messages to the queues in a pseudo random order. + * The receive task removes the messages from the queues and flags an error if + * the received message does not match that expected. + */ + +/* Kernel includes. */ +#include +#include "task.h" +#include "queue.h" + +/* Demo includes. */ +#include "QueueSet.h" + +/* The number of queues that are created and added to the queue set. */ +#define queuesetNUM_QUEUES_IN_SET 3 + +/* The length of each created queue. */ +#define queuesetQUEUE_LENGTH 3 + +/* Block times used in this demo. A block time or 0 means "don't block". */ +#define queuesetSHORT_DELAY 200 +#define queuesetDONT_BLOCK 0 + +/* + * The task that periodically sends to the queue set. + */ +static void prvQueueSetSendingTask( void *pvParameters ); + +/* + * The task that reads from the queue set. + */ +static void prvQueueSetReceivingTask( void *pvParameters ); + +/* The queues that are added to the set. */ +static xQueueHandle xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; + +/* The handle of the queue set to which the queues are added. */ +static xQueueSetHandle xQueueSet; + +/* If the prvQueueSetReceivingTask() task has not detected any errors then +it increments ulCycleCounter on each iteration. +xAreQueueSetTasksStillRunning() returns pdPASS if the value of +ulCycleCounter has changed between consecutive calls, and pdFALSE if +ulCycleCounter has stopped incrementing (indicating an error condition). */ +volatile unsigned long ulCycleCounter = 0UL; + +/* Set to pdFAIL if an error is detected by any queue set task. +ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */ +volatile portBASE_TYPE xQueueSetTasksStatus = pdPASS; + + +/*-----------------------------------------------------------*/ + +void vStartQueueSetTasks( unsigned portBASE_TYPE uxPriority ) +{ +xTaskHandle xQueueSetSendingTask; + + /* Create the two queues. The handle of the sending task is passed into + the receiving task using the task parameter. The receiving task uses the + handle to resume the sending task after it has created the queues. */ + xTaskCreate( prvQueueSetSendingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xQueueSetSendingTask ); + xTaskCreate( prvQueueSetReceivingTask, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, uxPriority, NULL ); + + /* It is important that the sending task does not attempt to write to a + queue before the queue has been created. It is therefore placed into the + suspended state before the scheduler has started. It is resumed by the + receiving task after the receiving task has created the queues and added the + queues to the queue set. */ + vTaskSuspend( xQueueSetSendingTask ); +} +/*-----------------------------------------------------------*/ + +portBASE_TYPE xAreQueueSetTasksStillRunning( void ) +{ +static unsigned long ulLastCycleCounter; +portBASE_TYPE xReturn; + + if( ulLastCycleCounter == ulCycleCounter ) + { + /* The cycle counter is no longer being incremented. Either one of the + tasks is stalled or an error has been detected. */ + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvQueueSetSendingTask( void *pvParameters ) +{ +unsigned long ulTxValue = 0; +portBASE_TYPE xQueueToWriteTo; + + /* Remove compiler warning about the unused parameter. */ + ( void ) pvParameters; + + srand( ( unsigned int ) &ulTxValue ); + + for( ;; ) + { + /* Generate the index for the queue to which a value is to be sent. */ + xQueueToWriteTo = rand() % queuesetNUM_QUEUES_IN_SET; + if( xQueueSendToBack( xQueues[ xQueueToWriteTo ], &ulTxValue, portMAX_DELAY ) != pdPASS ) + { + /* The send should always pass as an infinite block time was + used. */ + xQueueSetTasksStatus = pdFAIL; + } + + ulTxValue++; + } +} +/*-----------------------------------------------------------*/ + +static void prvQueueSetReceivingTask( void *pvParameters ) +{ +unsigned long ulReceived, ulLastReceived = ~0UL; +xQueueHandle xActivatedQueue; +portBASE_TYPE x; +xTaskHandle xQueueSetSendingTask; + + /* The handle to the sending task is passed in using the task parameter. */ + xQueueSetSendingTask = ( xTaskHandle ) pvParameters; + + /* Ensure the queues are created and the queue set configured before the + sending task is unsuspended. + + First Create the queue set such that it will be able to hold a message for + every space in every queue in the set. */ + xQueueSet = xQueueSetCreate( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ); + + for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) + { + /* Create the queue and add it to the set. */ + xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( unsigned long ) ); + configASSERT( xQueues[ x ] ); + if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdPASS ) + { + xQueueSetTasksStatus = pdFAIL; + } + + /* The queue has now been added to the queue set and cannot be added to + another. */ + if( xQueueAddToQueueSet( xQueues[ x ], xQueueSet ) != pdFAIL ) + { + xQueueSetTasksStatus = pdFAIL; + } + } + + /* The task that sends to the queues is not running yet, so attempting to + read from the queue set should fail, resulting in xActivatedQueue being set + to NULL. */ + xActivatedQueue = xQueueReadMultiple( xQueueSet, queuesetSHORT_DELAY ); + configASSERT( xActivatedQueue == NULL ); + + /* Resume the task that writes to the queues. */ + vTaskResume( xQueueSetSendingTask ); + + for( ;; ) + { + /* Wait for a message to arrive on one of the queues in the set. */ + xActivatedQueue = xQueueReadMultiple( xQueueSet, portMAX_DELAY ); + configASSERT( xActivatedQueue ); + + if( xActivatedQueue == NULL ) + { + /* This should not happen as an infinite delay was used. */ + xQueueSetTasksStatus = pdFAIL; + } + else + { + /* Reading from the queue should pass with a zero block time as + this task will only run when something has been posted to a task + in the queue set. */ + if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS ) + { + xQueueSetTasksStatus = pdFAIL; + } + + /* It is always expected that the received value will be one + greater than the previously received value. */ + configASSERT( ulReceived == ( ulLastReceived + 1 ) ); + if( ulReceived != ( ulLastReceived + 1 ) ) + { + xQueueSetTasksStatus = pdFAIL; + } + else + { + ulLastReceived = ulReceived; + } + } + + if( xQueueSetTasksStatus == pdPASS ) + { + ulCycleCounter++; + } + } +} + diff --git a/FreeRTOS/Demo/Common/Minimal/integer.c b/FreeRTOS/Demo/Common/Minimal/integer.c index 5d689c6ae..b441500a9 100644 --- a/FreeRTOS/Demo/Common/Minimal/integer.c +++ b/FreeRTOS/Demo/Common/Minimal/integer.c @@ -67,35 +67,12 @@ */ /* - * This version of integer. c is for use on systems that have limited stack - * space and no display facilities. The complete version can be found in - * the Demo/Common/Full directory. - * - * As with the full version, the tasks created in this file are a good test - * of the scheduler context switch mechanism. The processor has to access - * 32bit variables in two or four chunks (depending on the processor). The low - * priority of these tasks means there is a high probability that a context - * switch will occur mid calculation. See flop. c documentation for - * more information. - * + * Creates one or more tasks that repeatedly perform a set of integer + * calculations. The result of each run-time calculation is compared to the + * known expected result - with a mismatch being indicative of an error in the + * context switch mechanism. */ -/* -Changes from V1.2.1 - - + The constants used in the calculations are larger to ensure the - optimiser does not truncate them to 16 bits. - -Changes from V1.2.3 - - + uxTaskCheck is now just used as a boolean. Instead of incrementing - the variable each cycle of the task, the variable is simply set to - true. sAreIntegerMathsTaskStillRunning() sets it back to false and - expects it to have been set back to true by the time it is called - again. - + A division has been included in the calculation. -*/ - #include /* Scheduler include files. */ diff --git a/FreeRTOS/Demo/Common/include/QueueSet.h b/FreeRTOS/Demo/Common/include/QueueSet.h new file mode 100644 index 000000000..107b7a8bc --- /dev/null +++ b/FreeRTOS/Demo/Common/include/QueueSet.h @@ -0,0 +1,77 @@ +/* + FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. + + FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT + http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS tutorial books are available in pdf and paperback. * + * Complete, revised, and edited pdf reference manuals are also * + * available. * + * * + * Purchasing FreeRTOS documentation will not only help you, by * + * ensuring you get running as quickly as possible and with an * + * in-depth knowledge of how to use FreeRTOS, it will also help * + * the FreeRTOS project to continue with its mission of providing * + * professional grade, cross platform, de facto standard solutions * + * for microcontrollers - completely free of charge! * + * * + * >>> See http://www.FreeRTOS.org/Documentation for details. <<< * + * * + * Thank you for using FreeRTOS, and thank you for your support! * + * * + *************************************************************************** + + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation AND MODIFIED BY the FreeRTOS exception. + >>>NOTE<<< The modification to the GPL is included to allow you to + distribute a combined work that includes FreeRTOS without being obliged to + provide the source code for proprietary components outside of the FreeRTOS + kernel. FreeRTOS 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 and the FreeRTOS license exception along with FreeRTOS; if not it + can be viewed here: http://www.freertos.org/a00114.html and also obtained + by writing to Richard Barry, contact details for whom are available on the + FreeRTOS WEB site. + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + + http://www.FreeRTOS.org - Documentation, training, latest versions, license + and contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool. + + Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell + the code with commercial support, indemnification, and middleware, under + the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also + provide a safety engineered and independently SIL3 certified version under + the SafeRTOS brand: http://www.SafeRTOS.com. +*/ + +#ifndef QUEUE_WAIT_MULTIPLE_H +#define QUEUE_WAIT_MULTIPLE_H + +void vStartQueueSetTasks( unsigned portBASE_TYPE uxPriority ); +portBASE_TYPE xAreQueueSetTasksStillRunning( void ); + +#endif + + diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index deb4a3c36..0c548e3d5 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -100,6 +100,7 @@ #define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_ALTERNATIVE_API 1 +#define configUSE_QUEUE_SETS 1 #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 2 @@ -117,19 +118,19 @@ /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskCleanUpResources 0 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 -#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 #define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 -#define INCLUDE_xTaskGetIdleTaskHandle 1 -#define INCLUDE_pcTaskGetTaskName 1 -#define INCLUDE_eTaskStateGet 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_pcTaskGetTaskName 1 +#define INCLUDE_eTaskGetState 1 extern void vAssertCalled( void ); #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled() @@ -139,6 +140,5 @@ version of the Win32 simulator projects. It will be ignored in the GCC version. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 -#define configUSE_QUEUE_SETS 1 #endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo b/FreeRTOS/Demo/WIN32-MSVC/WIN32.suo index 1c3bbaa14f27896876461b37aa65a98c30b20959..e48277fabc56a98f4bb5a1bdece4dce299c8bef3 100644 GIT binary patch delta 4297 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 BtB(Kx delta 2998 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 diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj index 9944c4b78..87c8fb15d 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj @@ -137,6 +137,7 @@ + diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters index e32e36837..bc0d07c7d 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters @@ -94,6 +94,9 @@ Demo App Source\Common Demo Tasks + + Demo App Source\Common Demo Tasks + diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 85b09edfb..fa0eadbda 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -117,18 +117,20 @@ #include "countsem.h" #include "death.h" #include "dynamic.h" +#include "QueueSet.h" /* Priorities at which the tasks are created. */ -#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) -#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 1 ) -#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) -#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 ) -#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) -#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) -#define mainuIP_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) -#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY ) -#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY ) -#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) +#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainuIP_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainQUEUE_SET_TASK_PRIORITY ( tskIDLE_PRIORITY ) #define mainTIMER_TEST_PERIOD ( 50 ) @@ -165,6 +167,7 @@ int main( void ) vStartTimerDemoTask( mainTIMER_TEST_PERIOD ); vStartCountingSemaphoreTasks(); vStartDynamicPriorityTasks(); + vStartQueueSetTasks( mainQUEUE_SET_TASK_PRIORITY ); /* The suicide tasks must be created last as they need to know how many tasks were running prior to their creation. This then allows them to @@ -250,6 +253,10 @@ const portTickType xCycleFrequency = 1000 / portTICK_RATE_MS; { pcStatusMessage = "Error: Dynamic\r\n"; } + else if( xAreQueueSetTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Queue set\r\n"; + } /* This is the only task that uses stdout so its ok to call printf() directly. */ diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 93a8e1499..a84be03c0 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -560,7 +560,6 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * ); /* For backward compatability. */ #define eTaskStateGet eTaskGetState -#define INCLUDE_eTaskStateGet INCLUDE_eTaskGetState #endif /* INC_FREERTOS_H */ diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index 40562cfc0..b9452662c 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -1,7 +1,7 @@ /* FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd. - FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT + FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. *************************************************************************** @@ -42,7 +42,7 @@ FreeRTOS WEB site. 1 tab == 4 spaces! - + *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * @@ -52,17 +52,17 @@ * * *************************************************************************** - - http://www.FreeRTOS.org - Documentation, training, latest versions, license - and contact details. - + + http://www.FreeRTOS.org - Documentation, training, latest versions, license + and contact details. + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool. - Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell - the code with commercial support, indemnification, and middleware, under + Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell + the code with commercial support, indemnification, and middleware, under the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also - provide a safety engineered and independently SIL3 certified version under + provide a safety engineered and independently SIL3 certified version under the SafeRTOS brand: http://www.SafeRTOS.com. */ @@ -82,12 +82,18 @@ extern "C" { #include "mpu_wrappers.h" /** - * Type by which queues are referenced. For example, a call to xQueueCreate - * returns (via a pointer parameter) an xQueueHandle variable that can then - * be used as a parameter to xQueueSend(), xQueueReceive(), etc. + * Type by which queues are referenced. For example, a call to xQueueCreate() + * returns an xQueueHandle variable that can then be used as a parameter to + * xQueueSend(), xQueueReceive(), etc. */ typedef void * xQueueHandle; +/** + * Type by which queue sets are referenced. For example, a call to + * xQueueSetCreate() returns an xQueueSet variable that can then be used as a + * parameter to xQueueReadMultiple(), xQueueAddToQueueSet(), etc. + */ +typedef void * xQueueSetHandle; /* For internal use only. */ #define queueSEND_TO_BACK ( 0 ) @@ -1236,8 +1242,8 @@ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQue signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ); /* - * For internal use only. Use xSemaphoreCreateMutex(), - * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling + * For internal use only. Use xSemaphoreCreateMutex(), + * xSemaphoreCreateCounting() or xSemaphoreGetMutexHolder() instead of calling * these functions directly. */ xQueueHandle xQueueCreateMutex( unsigned char ucQueueType ); @@ -1284,11 +1290,128 @@ portBASE_TYPE xQueueGiveMutexRecursive( xQueueHandle pxMutex ); #endif /* - * Generic version of the queue creation function, which is in turn called by + * Generic version of the queue creation function, which is in turn called by * any queue, semaphore or mutex creation function or macro. */ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ); +/* + * Queue sets provide a mechanism to allow a task to block (pend) on a read + * operation from multiple queues or semaphores simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * A queue set must be explicitly created using a call to xQueueSetCreate() + * before it can be used. Once created, standard FreeRTOS queues and semaphores + * can be added to the set using calls to xQueueAddToQueueSet(). + * xQueueReadMultiple() is then used to determine which, if any, of the queues + * or semaphores contained in the set is in a state where a queue read or + * semaphore take operation would be successful. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org for reasons why + * queue sets are very rarely needed in practice as there are simpler + * alternatives. Queue sets are provided to allow FreeRTOS to be integrated + * with legacy third party driver code. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * Note 3: An additional 4 bytes of RAM is required for each space in a every + * queue added to a queue set. Therefore counting semaphores with large maximum + * counts should not be added to queue sets. + * + * @param uxEventQueueLength Queue sets themselves queue events that occur on + * the queues and semaphores contained in the set. uxEventQueueLength specifies + * the maximum number of events that can be queued at once. To be absolutely + * certain that events are not lost uxEventQueueLength should be set to the + * total sum of the length of the queues added to the set, where binary + * semaphores and mutexes have a length of 1, and counting semaphores have a + * length set by their maximum count value. Examples: + * + If a queue set is to hold a queue of length 5, another queue of length 12, + * and a binary semaphore, then uxEventQueueLength should be set to + * (5 + 12 + 1), or 18. + * + If a queue set is to hold three binary semaphores then uxEventQueueLength + * should be set to (1 + 1 + 1 ), or 3. + * + If a queue set is to hold a counting semaphore that has a maximum count of + * 5, and a counting semaphore that has a maximum count of 3, then + * uxEventQueueLength should be set to (5 + 3), or 8. + * + * @return If the queue set is created successfully then a handle to the created + * queue set is returned. Otherwise NULL is returned. + */ +xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ); + +/* + * Adds a queue or semaphore to a queue set that was previously created by a + * call to xQueueSetCreate(). + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueue The handle of the queue or semaphore being added to the + * queue set. Variables of type xSemaphoreHandle can be safely added to a + * queue set but may require casting to an xQueueHandle type to avoid compiler + * warnings. + * + * @param xQueueSet The handle of the queue set to which the queue or semaphore + * is being added. + * + * @return If the queue or semaphore was successfully added to the queue set + * then pdPASS is returned. If the queue could not be successfully added to the + * queue set because it is already a member of a different queue set then pdFAIL + * is returned. + */ +portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ); + +/* + * Removes a queue or semaphore from a queue set. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * @param xQueue The handle of the queue or semaphore being removed from the + * queue set. Variables of type xSemaphoreHandle can be safely used but may + * require casting to an xQueueHandle type to avoid compiler warnings. + * + * @param xQueueSet The handle of the queue set in which the queue or semaphore + * is included. + * + * @return If the queue or semaphore was successfully removed from the queue set + * then pdPASS is returned. If the queue was not in the queue set then pdFAIL + * is returned. + */ +portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ); + +/* + * xQueueReadMultiple() allows a task to block (pend) on a read operation on + * all the queues and semaphores in a queue set simultaneously. + * + * See FreeRTOS/Source/Demo/Common/Minimal/QueueSet.c for an example using this + * function. + * + * Note 1: See the documentation on http://wwwFreeRTOS.org for reasons why + * queue sets are very rarely needed in practice as there are simpler + * alternatives. Queue sets are provided to allow FreeRTOS to be integrated + * with legacy third party driver code. + * + * Note 2: Blocking on a queue set that contains a mutex will not cause the + * mutex holder to inherit the priority of the blocked task. + * + * @param xQueueSet The queue set on which the task will (potentially) block. + * + * @param xBlockTimeTicks The maximum time, in ticks, that the calling task will + * remain in the Blocked state (with other tasks executing) to wait for a member + * of the queue set to be ready for a successful queue read or semaphore take + * operation. + * + * @return xQueueReadMultiple() will return the handle of a queue contained + * in the queue set that contains data, or the handle of a semaphore contained + * in the queue set that is available, or NULL if no such queue or semaphore + * exists before before the specified block time expires. + */ +xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ); + /* Not public API functions. */ void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ); portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ); diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index c4e371229..db21c3c07 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -83,10 +83,6 @@ task.h is included from an application file. */ #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE -/*----------------------------------------------------------- - * PUBLIC LIST API documented in list.h - *----------------------------------------------------------*/ - /* Constants used with the cRxLock and xTxLock structure members. */ #define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 ) #define queueLOCKED_UNMODIFIED ( ( signed portBASE_TYPE ) 0 ) @@ -115,6 +111,7 @@ zero. */ #define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( 2U ) #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( 3U ) #define queueQUEUE_TYPE_RECURSIVE_MUTEX ( 4U ) +#define queueQUEUE_TYPE_SET ( 5U ) /* * Definition of the queue used by the scheduler. @@ -122,11 +119,11 @@ zero. */ */ typedef struct QueueDefinition { - signed char *pcHead; /*< Points to the beginning of the queue storage area. */ - signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ + signed char *pcHead; /*< Points to the beginning of the queue storage area. */ + signed char *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */ - signed char *pcWriteTo; /*< Points to the free next place in the storage area. */ - signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */ + signed char *pcWriteTo; /*< Points to the free next place in the storage area. */ + signed char *pcReadFrom; /*< Points to the last place that a queued item was read from. */ xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */ xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */ @@ -143,6 +140,10 @@ typedef struct QueueDefinition unsigned char ucQueueType; #endif + #if ( configUSE_QUEUE_SETS == 1 ) + struct QueueDefinition *pxQueueSetContainer; + #endif + } xQUEUE; /*-----------------------------------------------------------*/ @@ -152,11 +153,14 @@ typedef struct QueueDefinition * pointer to void. */ typedef xQUEUE * xQueueHandle; +typedef xQUEUE * xQueueSetHandle; /* - * Prototypes for public functions are included here so we don't have to - * include the API header file (as it defines xQueueHandle differently). These - * functions are documented in the API header file. + * In order to implement strict data hiding, the queue.h header file defines + * xQueueHandle and xQueueSetHandle as pointers to void. In this file + * xQueueHandle and xQueueSetHandle are defined as pointers to xQUEUE objects. + * Therefore the queue.h header file cannot be included in this source file, + * and the function prototypes are provided directly. */ xQueueHandle xQueueGenericCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize, unsigned char ucQueueType ) PRIVILEGED_FUNCTION; signed portBASE_TYPE xQueueGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) PRIVILEGED_FUNCTION; @@ -180,12 +184,16 @@ void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber ) P unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ) PRIVILEGED_FUNCTION; portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) PRIVILEGED_FUNCTION; xTaskHandle xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; +xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ) PRIVILEGED_FUNCTION; +xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ) PRIVILEGED_FUNCTION; +portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ) PRIVILEGED_FUNCTION; /* * Co-routine queue functions differ from task queue functions. Co-routines are * an optional component. */ -#if configUSE_CO_ROUTINES == 1 +#if ( configUSE_CO_ROUTINES == 1 ) signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) PRIVILEGED_FUNCTION; signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken ) PRIVILEGED_FUNCTION; signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) PRIVILEGED_FUNCTION; @@ -196,7 +204,7 @@ xTaskHandle xQueueGetMutexHolder( xQueueHandle xSemaphore ) PRIVILEGED_FUNCTION; * The queue registry is just a means for kernel aware debuggers to locate * queue structures. It has no other purpose so is an optional component. */ -#if configQUEUE_REGISTRY_SIZE > 0 +#if ( configQUEUE_REGISTRY_SIZE > 0 ) /* The type stored within the queue registry array. This allows a name to be assigned to each queue making kernel aware debugging a little @@ -252,6 +260,15 @@ static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, port * Copies an item out of a queue. */ static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) PRIVILEGED_FUNCTION; + +#if ( configUSE_QUEUE_SETS == 1 ) + /* + * Checks to see if a queue is a member of a queue set, and if so, notifies + * the queue set that the queue contains data. + */ + static portBASE_TYPE prvCheckForMembershipOfQueueSet( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ); +#endif + /*-----------------------------------------------------------*/ /* @@ -273,11 +290,6 @@ static void prvCopyDataFromQueue( xQUEUE * const pxQueue, const void *pvBuffer ) taskEXIT_CRITICAL() /*-----------------------------------------------------------*/ - -/*----------------------------------------------------------- - * PUBLIC QUEUE MANAGEMENT API documented in queue.h - *----------------------------------------------------------*/ - portBASE_TYPE xQueueGenericReset( xQueueHandle pxQueue, portBASE_TYPE xNewQueue ) { configASSERT( pxQueue ); @@ -349,12 +361,19 @@ xQueueHandle xReturn = NULL; pxNewQueue->uxLength = uxQueueLength; pxNewQueue->uxItemSize = uxItemSize; xQueueGenericReset( pxNewQueue, pdTRUE ); + #if ( configUSE_TRACE_FACILITY == 1 ) { pxNewQueue->ucQueueType = ucQueueType; } #endif /* configUSE_TRACE_FACILITY */ + #if( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif /* configUSE_QUEUE_SETS */ + traceQUEUE_CREATE( pxNewQueue ); xReturn = pxNewQueue; } @@ -410,6 +429,12 @@ xQueueHandle xReturn = NULL; } #endif + #if ( configUSE_QUEUE_SETS == 1 ) + { + pxNewQueue->pxQueueSetContainer = NULL; + } + #endif + /* Ensure the event queues start with the correct state. */ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) ); vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) ); @@ -431,7 +456,7 @@ xQueueHandle xReturn = NULL; #endif /* configUSE_MUTEXES */ /*-----------------------------------------------------------*/ -#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xQueueGetMutexHolder == 1 ) ) +#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) ) void* xQueueGetMutexHolder( xQueueHandle xSemaphore ) { @@ -510,7 +535,7 @@ xQueueHandle xReturn = NULL; #endif /* configUSE_RECURSIVE_MUTEXES */ /*-----------------------------------------------------------*/ -#if configUSE_RECURSIVE_MUTEXES == 1 +#if ( configUSE_RECURSIVE_MUTEXES == 1 ) portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex, portTickType xBlockTime ) { @@ -550,7 +575,7 @@ xQueueHandle xReturn = NULL; #endif /* configUSE_RECURSIVE_MUTEXES */ /*-----------------------------------------------------------*/ -#if configUSE_COUNTING_SEMAPHORES == 1 +#if ( configUSE_COUNTING_SEMAPHORES == 1 ) xQueueHandle xQueueCreateCountingSemaphore( unsigned portBASE_TYPE uxCountValue, unsigned portBASE_TYPE uxInitialCount ) { @@ -611,6 +636,20 @@ xTimeOutType xTimeOut; portYIELD_WITHIN_API(); } } + else + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( prvCheckForMembershipOfQueueSet( pxQueue, xCopyPosition ) == pdTRUE ) + { + /* The queue is a member of a queue set, and posting to + the queue set caused a higher priority task to unblock. + A context switch is required. */ + portYIELD_WITHIN_API(); + } + } + #endif /* configUSE_QUEUE_SETS */ + } taskEXIT_CRITICAL(); @@ -695,7 +734,7 @@ xTimeOutType xTimeOut; } /*-----------------------------------------------------------*/ -#if configUSE_ALTERNATIVE_API == 1 +#if ( configUSE_ALTERNATIVE_API == 1 ) signed portBASE_TYPE xQueueAltGenericSend( xQueueHandle pxQueue, const void * const pvItemToQueue, portTickType xTicksToWait, portBASE_TYPE xCopyPosition ) { @@ -772,7 +811,7 @@ xTimeOutType xTimeOut; #endif /* configUSE_ALTERNATIVE_API */ /*-----------------------------------------------------------*/ -#if configUSE_ALTERNATIVE_API == 1 +#if ( configUSE_ALTERNATIVE_API == 1 ) signed portBASE_TYPE xQueueAltGenericReceive( xQueueHandle pxQueue, void * const pvBuffer, portTickType xTicksToWait, portBASE_TYPE xJustPeeking ) { @@ -940,6 +979,17 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; } } } + else + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + xQueueGenericSendFromISR( pxQueue->pxQueueSetContainer, &pxQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK ); + } + } + #endif /* configUSE_QUEUE_SETS */ + } } else { @@ -1018,7 +1068,7 @@ signed char *pcOriginalReadPosition; { traceQUEUE_PEEK( pxQueue ); - /* We are not removing the data, so reset our read + /* The data is not being removed, so reset the read pointer. */ pxQueue->pcReadFrom = pcOriginalReadPosition; @@ -1034,6 +1084,17 @@ signed char *pcOriginalReadPosition; portYIELD_WITHIN_API(); } } + else + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + xQueueGenericSend( pxQueue->pxQueueSetContainer, &pxQueue, 0, queueSEND_TO_BACK ); + } + } + #endif /* configUSE_QUEUE_SETS */ + } } taskEXIT_CRITICAL(); @@ -1212,7 +1273,7 @@ void vQueueDelete( xQueueHandle pxQueue ) return pxQueue->ucQueueNumber; } -#endif +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) @@ -1222,7 +1283,7 @@ void vQueueDelete( xQueueHandle pxQueue ) pxQueue->ucQueueNumber = ucQueueNumber; } -#endif +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) @@ -1232,7 +1293,7 @@ void vQueueDelete( xQueueHandle pxQueue ) return pxQueue->ucQueueType; } -#endif +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, portBASE_TYPE xPosition ) @@ -1312,6 +1373,22 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) context switch is required. */ vTaskMissedYield(); } + else + { + #if ( configUSE_QUEUE_SETS == 1 ) + { + if( pxQueue->pxQueueSetContainer != NULL ) + { + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + xQueueGenericSendFromISR( pxQueue->pxQueueSetContainer, &pxQueue, &xHigherPriorityTaskWoken, queueSEND_TO_BACK ); + if( xHigherPriorityTaskWoken != pdFALSE ) + { + vTaskMissedYield(); + } + } + } + #endif /* configUSE_QUEUE_SETS */ + } --( pxQueue->xTxLock ); } @@ -1397,219 +1474,225 @@ signed portBASE_TYPE xReturn; } /*-----------------------------------------------------------*/ -#if configUSE_CO_ROUTINES == 1 -signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) -{ -signed portBASE_TYPE xReturn; +#if ( configUSE_CO_ROUTINES == 1 ) - /* 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 - between the check to see if the queue is full and blocking on the queue. */ - portDISABLE_INTERRUPTS(); + signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait ) { - if( prvIsQueueFull( pxQueue ) != pdFALSE ) + 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 + between the check to see if the queue is full and blocking on the queue. */ + portDISABLE_INTERRUPTS(); { - /* The queue is full - do we want to block or just leave without - posting? */ - if( xTicksToWait > ( portTickType ) 0 ) - { - /* As this is called from a coroutine we cannot block directly, but - return indicating that we need to block. */ - vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); - portENABLE_INTERRUPTS(); - return errQUEUE_BLOCKED; - } - else + if( prvIsQueueFull( pxQueue ) != pdFALSE ) { - portENABLE_INTERRUPTS(); - return errQUEUE_FULL; + /* The queue is full - do we want to block or just leave without + posting? */ + if( xTicksToWait > ( portTickType ) 0 ) + { + /* As this is called from a coroutine we cannot block directly, but + return indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } } } - } - portENABLE_INTERRUPTS(); + portENABLE_INTERRUPTS(); - portNOP(); + portNOP(); - portDISABLE_INTERRUPTS(); - { - if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + portDISABLE_INTERRUPTS(); { - /* There is room in the queue, copy the data into the queue. */ - prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); - xReturn = pdPASS; - - /* Were any co-routines waiting for data to become available? */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { - /* 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 ) + /* There is room in the queue, copy the data into the queue. */ + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + xReturn = pdPASS; + + /* Were any co-routines waiting for data to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - /* The co-routine waiting has a higher priority so record - that a yield might be appropriate. */ - xReturn = errQUEUE_YIELD; + /* 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 + that a yield might be appropriate. */ + xReturn = errQUEUE_YIELD; + } } } + else + { + xReturn = errQUEUE_FULL; + } } - else - { - xReturn = errQUEUE_FULL; - } + portENABLE_INTERRUPTS(); + + return xReturn; } - portENABLE_INTERRUPTS(); - return xReturn; -} -#endif +#endif /* configUSE_CO_ROUTINES */ /*-----------------------------------------------------------*/ -#if configUSE_CO_ROUTINES == 1 -signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) -{ -signed portBASE_TYPE xReturn; +#if ( configUSE_CO_ROUTINES == 1 ) - /* 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 - between the check to see if the queue is empty and blocking on the queue. */ - portDISABLE_INTERRUPTS(); + signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait ) { - if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) + 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 + between the check to see if the queue is empty and blocking on the queue. */ + portDISABLE_INTERRUPTS(); { - /* There are no messages in the queue, do we want to block or just - leave with nothing? */ - if( xTicksToWait > ( portTickType ) 0 ) + if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 ) { - /* As this is a co-routine we cannot block directly, but return - indicating that we need to block. */ - vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); - portENABLE_INTERRUPTS(); - return errQUEUE_BLOCKED; - } - else - { - portENABLE_INTERRUPTS(); - return errQUEUE_FULL; + /* There are no messages in the queue, do we want to block or just + leave with nothing? */ + if( xTicksToWait > ( portTickType ) 0 ) + { + /* As this is a co-routine we cannot block directly, but return + indicating that we need to block. */ + vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) ); + portENABLE_INTERRUPTS(); + return errQUEUE_BLOCKED; + } + else + { + portENABLE_INTERRUPTS(); + return errQUEUE_FULL; + } } } - } - portENABLE_INTERRUPTS(); + portENABLE_INTERRUPTS(); - portNOP(); + portNOP(); - portDISABLE_INTERRUPTS(); - { - if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + portDISABLE_INTERRUPTS(); { - /* Data is available from the queue. */ - pxQueue->pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->pcReadFrom >= pxQueue->pcTail ) + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { - pxQueue->pcReadFrom = pxQueue->pcHead; - } - --( pxQueue->uxMessagesWaiting ); - memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + /* Data is available from the queue. */ + pxQueue->pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->pcReadFrom >= pxQueue->pcTail ) + { + pxQueue->pcReadFrom = pxQueue->pcHead; + } + --( pxQueue->uxMessagesWaiting ); + memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); - xReturn = pdPASS; + xReturn = pdPASS; - /* Were any co-routines waiting for space to become available? */ - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) - { - /* 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 ) + /* Were any co-routines waiting for space to become available? */ + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - xReturn = errQUEUE_YIELD; + /* 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 ) + { + xReturn = errQUEUE_YIELD; + } } } + else + { + xReturn = pdFAIL; + } } - else - { - xReturn = pdFAIL; - } + portENABLE_INTERRUPTS(); + + return xReturn; } - portENABLE_INTERRUPTS(); - return xReturn; -} -#endif +#endif /* configUSE_CO_ROUTINES */ /*-----------------------------------------------------------*/ +#if ( configUSE_CO_ROUTINES == 1 ) - -#if configUSE_CO_ROUTINES == 1 -signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) -{ - /* Cannot block within an ISR so if there is no space on the queue then - exit without doing anything. */ - if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) + signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken ) { - prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); - - /* We only want to wake one co-routine per ISR, so check that a - co-routine has not already been woken. */ - if( xCoRoutinePreviouslyWoken == pdFALSE ) + /* Cannot block within an ISR so if there is no space on the queue then + exit without doing anything. */ + if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) + prvCopyDataToQueue( pxQueue, pvItemToQueue, queueSEND_TO_BACK ); + + /* We only want to wake one co-routine per ISR, so check that a + co-routine has not already been woken. */ + if( xCoRoutinePreviouslyWoken == pdFALSE ) { - if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { - return pdTRUE; + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) + { + return pdTRUE; + } } } } + + return xCoRoutinePreviouslyWoken; } - return xCoRoutinePreviouslyWoken; -} -#endif +#endif /* configUSE_CO_ROUTINES */ /*-----------------------------------------------------------*/ -#if configUSE_CO_ROUTINES == 1 -signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken ) -{ -signed portBASE_TYPE xReturn; +#if ( configUSE_CO_ROUTINES == 1 ) - /* We cannot block from an ISR, so check there is data available. If - not then just leave without doing anything. */ - if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) + signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken ) { - /* Copy the data from the queue. */ - pxQueue->pcReadFrom += pxQueue->uxItemSize; - if( pxQueue->pcReadFrom >= pxQueue->pcTail ) - { - pxQueue->pcReadFrom = pxQueue->pcHead; - } - --( pxQueue->uxMessagesWaiting ); - memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + signed portBASE_TYPE xReturn; - if( ( *pxCoRoutineWoken ) == pdFALSE ) + /* We cannot block from an ISR, so check there is data available. If + not then just leave without doing anything. */ + if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) { - if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) + /* Copy the data from the queue. */ + pxQueue->pcReadFrom += pxQueue->uxItemSize; + if( pxQueue->pcReadFrom >= pxQueue->pcTail ) { - if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + pxQueue->pcReadFrom = pxQueue->pcHead; + } + --( pxQueue->uxMessagesWaiting ); + memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize ); + + if( ( *pxCoRoutineWoken ) == pdFALSE ) + { + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { - *pxCoRoutineWoken = pdTRUE; + if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) + { + *pxCoRoutineWoken = pdTRUE; + } } } + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; } - xReturn = pdPASS; - } - else - { - xReturn = pdFAIL; + return xReturn; } - return xReturn; -} -#endif +#endif /* configUSE_CO_ROUTINES */ /*-----------------------------------------------------------*/ -#if configQUEUE_REGISTRY_SIZE > 0 +#if ( configQUEUE_REGISTRY_SIZE > 0 ) void vQueueAddToRegistry( xQueueHandle xQueue, signed char *pcQueueName ) { @@ -1629,10 +1712,10 @@ signed portBASE_TYPE xReturn; } } -#endif +#endif /* configQUEUE_REGISTRY_SIZE */ /*-----------------------------------------------------------*/ -#if configQUEUE_REGISTRY_SIZE > 0 +#if ( configQUEUE_REGISTRY_SIZE > 0 ) static void vQueueUnregisterQueue( xQueueHandle xQueue ) { @@ -1652,10 +1735,10 @@ signed portBASE_TYPE xReturn; } -#endif +#endif /* configQUEUE_REGISTRY_SIZE */ /*-----------------------------------------------------------*/ -#if configUSE_TIMERS == 1 +#if ( configUSE_TIMERS == 1 ) void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) { @@ -1682,5 +1765,113 @@ signed portBASE_TYPE xReturn; prvUnlockQueue( pxQueue ); } -#endif +#endif /* configUSE_TIMERS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueSetHandle xQueueSetCreate( unsigned portBASE_TYPE uxEventQueueLength ) + { + xQUEUE *pxQueue; + + pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( xQUEUE * ), queueQUEUE_TYPE_SET ); + + return ( xQueueSetHandle ) pxQueue; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + portBASE_TYPE xQueueAddToQueueSet( xQueueHandle xQueue, xQueueSetHandle xQueueSet ) + { + portBASE_TYPE xReturn; + + if( xQueue->pxQueueSetContainer != NULL ) + { + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + xQueue->pxQueueSetContainer = xQueueSet; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + portBASE_TYPE xQueueRemoveFromQueueSet( xQueueSetHandle xQueueSet, xQueueHandle xQueue ) + { + portBASE_TYPE xReturn; + + if( xQueue->pxQueueSetContainer != xQueueSet ) + { + xReturn = pdFAIL; + } + else + { + taskENTER_CRITICAL(); + { + xQueue->pxQueueSetContainer = NULL; + } + taskEXIT_CRITICAL(); + xReturn = pdPASS; + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + xQueueHandle xQueueReadMultiple( xQueueSetHandle xQueueSet, portTickType xBlockTimeTicks ) + { + xQueueHandle xReturn = NULL; + + xQueueGenericReceive( ( xQueueHandle ) xQueueSet, &xReturn, xBlockTimeTicks, pdFALSE ); + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ +/*-----------------------------------------------------------*/ + +#if ( configUSE_QUEUE_SETS == 1 ) + + static portBASE_TYPE prvCheckForMembershipOfQueueSet( xQUEUE *pxQueue, portBASE_TYPE xCopyPosition ) + { + xQUEUE *pxQueueSetContainer = pxQueue->pxQueueSetContainer; + portBASE_TYPE xReturn = pdFALSE; + + if( pxQueueSetContainer != NULL ) + { + if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength ) + { + prvCopyDataToQueue( pxQueueSetContainer, &pxQueue, xCopyPosition ); + if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE ) + { + if( xTaskRemoveFromEventList( &( pxQueue->pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE ) + { + /* The task waiting has a higher priority */ + xReturn = pdTRUE; + } + } + } + } + + return xReturn; + } + +#endif /* configUSE_QUEUE_SETS */ diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index ab95fbd68..6284a56ff 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -214,7 +214,7 @@ PRIVILEGED_DATA static volatile portTickType xNextTaskUnblockTime = ( portTic /*-----------------------------------------------------------*/ -#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 +#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is performed in a generic way that is not optimised to any particular @@ -478,12 +478,6 @@ static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TY /*lint +e956 */ - - -/*----------------------------------------------------------- - * TASK CREATION API documented in task.h - *----------------------------------------------------------*/ - signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const xMemoryRegion * const xRegions ) { signed portBASE_TYPE xReturn; @@ -526,7 +520,7 @@ tskTCB * pxNewTCB; /* Check the alignment of the calculated top of stack is correct. */ configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); } - #else + #else /* portSTACK_GROWTH */ { pxTopOfStack = pxNewTCB->pxStack; @@ -538,7 +532,7 @@ tskTCB * pxNewTCB; other extreme of the stack space. */ pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); } - #endif + #endif /* portSTACK_GROWTH */ /* Setup the newly allocated TCB with the initial state of the task. */ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); @@ -551,11 +545,11 @@ tskTCB * pxNewTCB; { pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); } - #else + #else /* portUSING_MPU_WRAPPERS */ { pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); } - #endif + #endif /* portUSING_MPU_WRAPPERS */ /* Check the alignment of the initialised stack. */ portALIGNMENT_ASSERT_pxCurrentTCB( ( ( ( unsigned long ) pxNewTCB->pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); @@ -613,7 +607,7 @@ tskTCB * pxNewTCB; /* Add a counter into the TCB for tracing only. */ pxNewTCB->uxTCBNumber = uxTaskNumber; } - #endif + #endif /* configUSE_TRACE_FACILITY */ uxTaskNumber++; traceTASK_CREATE( pxNewTCB ); @@ -705,16 +699,8 @@ tskTCB * pxNewTCB; } } -#endif - - - - - - -/*----------------------------------------------------------- - * TASK CONTROL API documented in task.h - *----------------------------------------------------------*/ +#endif /* INCLUDE_vTaskDelete */ +/*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskDelayUntil == 1 ) @@ -785,7 +771,7 @@ tskTCB * pxNewTCB; } } -#endif +#endif /* INCLUDE_vTaskDelayUntil */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskDelay == 1 ) @@ -837,7 +823,7 @@ tskTCB * pxNewTCB; } } -#endif +#endif /* INCLUDE_vTaskDelay */ /*-----------------------------------------------------------*/ #if ( INCLUDE_eTaskGetState == 1 ) @@ -899,7 +885,7 @@ tskTCB * pxNewTCB; return eReturn; } -#endif +#endif /* INCLUDE_eTaskGetState */ /*-----------------------------------------------------------*/ #if ( INCLUDE_uxTaskPriorityGet == 1 ) @@ -921,7 +907,7 @@ tskTCB * pxNewTCB; return uxReturn; } -#endif +#endif /* INCLUDE_uxTaskPriorityGet */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskPrioritySet == 1 ) @@ -1039,7 +1025,7 @@ tskTCB * pxNewTCB; ( void ) uxPriorityUsedOnEntry; } -#endif +#endif /* INCLUDE_vTaskPrioritySet */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskSuspend == 1 ) @@ -1106,7 +1092,7 @@ tskTCB * pxNewTCB; } } -#endif +#endif /* INCLUDE_vTaskSuspend */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskSuspend == 1 ) @@ -1140,7 +1126,7 @@ tskTCB * pxNewTCB; return xReturn; } -#endif +#endif /* INCLUDE_vTaskSuspend */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskSuspend == 1 ) @@ -1184,7 +1170,7 @@ tskTCB * pxNewTCB; } } -#endif +#endif /* INCLUDE_vTaskSuspend */ /*-----------------------------------------------------------*/ @@ -1226,15 +1212,8 @@ tskTCB * pxNewTCB; return xYieldRequired; } -#endif - - - - -/*----------------------------------------------------------- - * PUBLIC SCHEDULER CONTROL documented in task.h - *----------------------------------------------------------*/ - +#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ +/*-----------------------------------------------------------*/ void vTaskStartScheduler( void ) { @@ -1252,7 +1231,7 @@ portBASE_TYPE xReturn; /* Create the idle task without storing its handle. */ xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); } - #endif + #endif /* INCLUDE_xTaskGetIdleTaskHandle */ #if ( configUSE_TIMERS == 1 ) { @@ -1261,7 +1240,7 @@ portBASE_TYPE xReturn; xReturn = xTimerCreateTimerTask(); } } - #endif + #endif /* configUSE_TIMERS */ if( xReturn == pdPASS ) { @@ -1296,7 +1275,9 @@ portBASE_TYPE xReturn; } } - /* This line will only be reached if the kernel could not be started. */ + /* This line will only be reached if the kernel could not be started, or + vTaskEndScheduler() was called (vTaskEndScheduler() is not implemented for + most ports). */ configASSERT( xReturn ); } /*-----------------------------------------------------------*/ @@ -1345,7 +1326,7 @@ void vTaskSuspendAll( void ) return xReturn; } -#endif /* configUSE_TICKLESS_IDLE != 0 */ +#endif /* configUSE_TICKLESS_IDLE */ /*----------------------------------------------------------*/ signed portBASE_TYPE xTaskResumeAll( void ) @@ -1423,17 +1404,7 @@ signed portBASE_TYPE xAlreadyYielded = pdFALSE; return xAlreadyYielded; } - - - - - - -/*----------------------------------------------------------- - * PUBLIC TASK UTILITIES documented in task.h - *----------------------------------------------------------*/ - - +/*-----------------------------------------------------------*/ portTickType xTaskGetTickCount( void ) { @@ -1483,7 +1454,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) return &( pxTCB->pcTaskName[ 0 ] ); } -#endif +#endif /* INCLUDE_pcTaskGetTaskName */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) @@ -1546,7 +1517,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) xTaskResumeAll(); } -#endif +#endif /* configUSE_TRACE_FACILITY */ /*----------------------------------------------------------*/ #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -1621,7 +1592,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) xTaskResumeAll(); } -#endif +#endif /* configGENERATE_RUN_TIME_STATS */ /*----------------------------------------------------------*/ #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) @@ -1634,7 +1605,7 @@ unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void ) return xIdleTaskHandle; } -#endif +#endif /* INCLUDE_xTaskGetIdleTaskHandle */ /*----------------------------------------------------------*/ /* This conditional compilation should use inequality to 0, not equality to 1. @@ -1649,12 +1620,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than xTickCount += xTicksToJump; } -#endif - -/*----------------------------------------------------------- - * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES - * documented in task.h - *----------------------------------------------------------*/ +#endif /* configUSE_TICKLESS_IDLE */ +/*----------------------------------------------------------*/ void vTaskIncrementTick( void ) { @@ -1726,7 +1693,7 @@ tskTCB * pxTCB; vApplicationTickHook(); } } - #endif + #endif /* configUSE_TICK_HOOK */ } /*-----------------------------------------------------------*/ @@ -1753,7 +1720,7 @@ tskTCB * pxTCB; taskEXIT_CRITICAL(); } -#endif +#endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ #if ( configUSE_APPLICATION_TASK_TAG == 1 ) @@ -1782,7 +1749,7 @@ tskTCB * pxTCB; return xReturn; } -#endif +#endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ #if ( configUSE_APPLICATION_TASK_TAG == 1 ) @@ -1814,7 +1781,7 @@ tskTCB * pxTCB; return xReturn; } -#endif +#endif /* configUSE_APPLICATION_TASK_TAG */ /*-----------------------------------------------------------*/ void vTaskSwitchContext( void ) @@ -1845,7 +1812,7 @@ void vTaskSwitchContext( void ) pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); ulTaskSwitchedInTime = ulTotalRunTime; } - #endif + #endif /* configGENERATE_RUN_TIME_STATS */ taskFIRST_CHECK_FOR_STACK_OVERFLOW(); taskSECOND_CHECK_FOR_STACK_OVERFLOW(); @@ -1898,14 +1865,14 @@ portTickType xTimeToWake; prvAddCurrentTaskToDelayedList( xTimeToWake ); } } - #else + #else /* INCLUDE_vTaskSuspend */ { /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ xTimeToWake = xTickCount + xTicksToWait; prvAddCurrentTaskToDelayedList( xTimeToWake ); } - #endif + #endif /* INCLUDE_vTaskSuspend */ } /*-----------------------------------------------------------*/ @@ -2062,6 +2029,7 @@ void vTaskMissedYield( void ) /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) + unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask ) { unsigned portBASE_TYPE uxReturn; @@ -2079,10 +2047,12 @@ void vTaskMissedYield( void ) return uxReturn; } -#endif + +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ #if ( configUSE_TRACE_FACILITY == 1 ) + void vTaskSetTaskNumber( xTaskHandle xTask, unsigned portBASE_TYPE uxHandle ) { tskTCB *pxTCB; @@ -2093,8 +2063,8 @@ void vTaskMissedYield( void ) pxTCB->uxTaskNumber = uxHandle; } } -#endif +#endif /* configUSE_TRACE_FACILITY */ /* * ----------------------------------------------------------- @@ -2125,7 +2095,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) will automatically get the processor anyway. */ taskYIELD(); } - #endif + #endif /* configUSE_PREEMPTION */ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) { @@ -2143,7 +2113,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) taskYIELD(); } } - #endif + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ #if ( configUSE_IDLE_HOOK == 1 ) { @@ -2156,7 +2126,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) CALL A FUNCTION THAT MIGHT BLOCK. */ vApplicationIdleHook(); } - #endif + #endif /* configUSE_IDLE_HOOK */ /* This conditional compilation should use inequality to 0, not equality to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when @@ -2190,21 +2160,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) xTaskResumeAll(); } } - #endif + #endif /* configUSE_TICKLESS_IDLE */ } } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */ - - - - - - - -/*----------------------------------------------------------- - * File private functions documented at the top of the file. - *----------------------------------------------------------*/ - - +/*-----------------------------------------------------------*/ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) { @@ -2214,7 +2173,7 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const /* Don't bring strncpy into the build unnecessarily. */ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN ); } - #endif + #endif /* configMAX_TASK_NAME_LEN */ pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0'; /* This is used as an array index so must ensure it's not too large. First @@ -2229,7 +2188,7 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const { pxTCB->uxBasePriority = uxPriority; } - #endif + #endif /* configUSE_MUTEXES */ vListInitialiseItem( &( pxTCB->xGenericListItem ) ); vListInitialiseItem( &( pxTCB->xEventListItem ) ); @@ -2246,30 +2205,30 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const { pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0U; } - #endif + #endif /* portCRITICAL_NESTING_IN_TCB */ #if ( configUSE_APPLICATION_TASK_TAG == 1 ) { pxTCB->pxTaskTag = NULL; } - #endif + #endif /* configUSE_APPLICATION_TASK_TAG */ #if ( configGENERATE_RUN_TIME_STATS == 1 ) { pxTCB->ulRunTimeCounter = 0UL; } - #endif + #endif /* configGENERATE_RUN_TIME_STATS */ #if ( portUSING_MPU_WRAPPERS == 1 ) { vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); } - #else + #else /* portUSING_MPU_WRAPPERS */ { ( void ) xRegions; ( void ) usStackDepth; } - #endif + #endif /* portUSING_MPU_WRAPPERS */ } /*-----------------------------------------------------------*/ @@ -2289,8 +2248,9 @@ static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 ); } - /*-----------------------------------------------------------*/ -#endif + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ static void prvInitialiseTaskLists( void ) { @@ -2309,13 +2269,13 @@ unsigned portBASE_TYPE uxPriority; { vListInitialise( ( xList * ) &xTasksWaitingTermination ); } - #endif + #endif /* INCLUDE_vTaskDelete */ #if ( INCLUDE_vTaskSuspend == 1 ) { vListInitialise( ( xList * ) &xSuspendedTaskList ); } - #endif + #endif /* INCLUDE_vTaskSuspend */ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList using list2. */ @@ -2355,7 +2315,7 @@ static void prvCheckTasksWaitingTermination( void ) } } } - #endif + #endif /* vTaskDelete */ } /*-----------------------------------------------------------*/ @@ -2446,7 +2406,7 @@ tskTCB *pxNewTCB; } while( pxNextTCB != pxFirstTCB ); } -#endif +#endif /* configUSE_TRACE_FACILITY */ /*-----------------------------------------------------------*/ #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -2517,7 +2477,7 @@ tskTCB *pxNewTCB; } while( pxNextTCB != pxFirstTCB ); } -#endif +#endif /* configGENERATE_RUN_TIME_STATS */ /*-----------------------------------------------------------*/ #if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) @@ -2537,7 +2497,7 @@ tskTCB *pxNewTCB; return usCount; } -#endif +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) @@ -2565,7 +2525,7 @@ tskTCB *pxNewTCB; return uxReturn; } -#endif +#endif /* INCLUDE_uxTaskGetStackHighWaterMark */ /*-----------------------------------------------------------*/ #if ( INCLUDE_vTaskDelete == 1 ) @@ -2583,9 +2543,7 @@ tskTCB *pxNewTCB; vPortFree( pxTCB ); } -#endif - - +#endif /* INCLUDE_vTaskDelete */ /*-----------------------------------------------------------*/ #if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) @@ -2602,8 +2560,7 @@ tskTCB *pxNewTCB; return xReturn; } -#endif - +#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) @@ -2631,7 +2588,7 @@ tskTCB *pxNewTCB; return xReturn; } -#endif +#endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( configUSE_MUTEXES == 1 ) @@ -2673,7 +2630,7 @@ tskTCB *pxNewTCB; } } -#endif +#endif /* configUSE_MUTEXES */ /*-----------------------------------------------------------*/ #if ( configUSE_MUTEXES == 1 ) @@ -2703,7 +2660,7 @@ tskTCB *pxNewTCB; } } -#endif +#endif /* configUSE_MUTEXES */ /*-----------------------------------------------------------*/ #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -2718,7 +2675,7 @@ tskTCB *pxNewTCB; } } -#endif +#endif /* portCRITICAL_NESTING_IN_TCB */ /*-----------------------------------------------------------*/ #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -2737,9 +2694,9 @@ tskTCB *pxNewTCB; } } } - } + } -#endif +#endif /* portCRITICAL_NESTING_IN_TCB */ /*-----------------------------------------------------------*/ -- 2.39.2