From 268cf9679156ae220e783762a3a5d2c850e201a9 Mon Sep 17 00:00:00 2001 From: rtel Date: Sun, 20 Dec 2015 13:44:21 +0000 Subject: [PATCH] Changes to the FreeRTOS code: + Introduced xTaskCreateStatic() to allow tasks to be created without any dynamic memory allocation. + When a task notification is used to unblock a task from an ISR, but the xHigherPriorityTaskWoken parameter is not used, then pend a context switch to occur during the next tick interrupt. Demo application changes: + Updated TaskNotify.c to test the case where a task is unblocked by an ISR, but does not use its xHigherPriorityTaskWoken parameter. + Updated the Win32 MSVC project to test statically allocated tasks being created and deleted. + Introduced StaticAllocation.c standard demo task. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2397 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Demo/Common/Minimal/StaticAllocation.c | 310 ++++++++++++++++++ FreeRTOS/Demo/Common/Minimal/TaskNotify.c | 26 +- FreeRTOS/Demo/Common/Minimal/death.c | 10 +- FreeRTOS/Demo/Common/Minimal/recmutex.c | 4 +- .../Demo/Common/include/StaticAllocation.h | 79 +++++ FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h | 4 +- FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj | 1 + .../Demo/WIN32-MSVC/WIN32.vcxproj.filters | 65 ++-- FreeRTOS/Demo/WIN32-MSVC/main.c | 36 ++ FreeRTOS/Demo/WIN32-MSVC/main_full.c | 8 +- FreeRTOS/Source/include/FreeRTOS.h | 6 +- FreeRTOS/Source/include/task.h | 176 +++++++++- FreeRTOS/Source/queue.c | 4 +- FreeRTOS/Source/tasks.c | 197 +++++++---- FreeRTOS/Source/timers.c | 26 +- 15 files changed, 838 insertions(+), 114 deletions(-) create mode 100644 FreeRTOS/Demo/Common/Minimal/StaticAllocation.c create mode 100644 FreeRTOS/Demo/Common/include/StaticAllocation.h diff --git a/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c new file mode 100644 index 000000000..a957aee90 --- /dev/null +++ b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c @@ -0,0 +1,310 @@ +/* + FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * Demonstrates how to create FreeRTOS objects using pre-allocated memory, + * rather than the normal dynamically allocated memory. Currently only tasks + * are being allocated statically. + * + * Two buffers are required by a task - one that is used by the task as its + * stack, and one that holds the task's control block (TCB). + * prvStaticallyAllocatedTaskCreator() creates and deletes tasks with all + * possible combinations of statically allocated and dynamically allocated + * stacks and TCBs. + */ + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Demo program include files. */ +#include "StaticAllocation.h" + +#define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) + +/* + * A task that is created multiple times, using both statically and dynamically + * allocated stack and TCB. + */ +static void prvStaticallyAllocatedTask( void *pvParameters ); + +/* + * The task that creates and deletes the prvStaticallyAllocatedTask() task, + * using various priorities, and sometimes with statically and sometimes + * dynamically allocated stack and TCB. + */ +static void prvStaticallyAllocatedTaskCreator( void *pvParameters ); + +/* + * Utility function to create pseudo random numbers. + */ +static UBaseType_t prvRand( void ); + +/* + * The task that creates and deletes other tasks has to delay occasionally to + * ensure lower priority tasks are not starved of processing time. A pseudo + * random delay time is used just to add a little bit of randomisation into the + * execution pattern. prvGetNextDelayTime() generates the pseudo random delay. + */ +static TickType_t prvGetNextDelayTime( void ); + +/*-----------------------------------------------------------*/ + +/* DummyTCB_t is a publicly accessible structure that has the same size and +alignment requirements as the real TCB structure. It is provided as a mechanism +for applications to know the size of the TCB (which is dependent on the +architecture and configuration file settings) without breaking the strict data +hiding policy by exposing the real TCB. This DummyTCB_t variable is passed into +the xTaskCreateStatic() function, and will hold the task's TCB. */ +static DummyTCB_t xTCBBuffer; + +/* This is the stack that will be used by the task. The alignment requirements +for the stack depend on the architecture, and the method of forcing an alignment +is dependent on the compiler, but any bad alignment is corrected inside the +FreeRTOS code. */ +static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ]; + +/* Used by the pseudo random number generating function. */ +static uint32_t ulNextRand = 0; + +/* Used so a check task can ensure this test is still executing, and not +stalled. */ +static volatile UBaseType_t uxCycleCounter = 0; + +/*-----------------------------------------------------------*/ + +void vStartStaticallyAllocatedTasks( void ) +{ + /* Create a single task, which then repeatedly creates and deletes the + task implemented by prvStaticallyAllocatedTask() at various different + priorities, and both with and without statically allocated TCB and stack. */ + xTaskCreate( prvStaticallyAllocatedTaskCreator, "StatCreate", configMINIMAL_STACK_SIZE, NULL, staticTASK_PRIORITY, NULL ); + + /* Pseudo seed the random number generator. */ + ulNextRand = ( uint32_t ) prvRand; +} +/*-----------------------------------------------------------*/ + +static void prvStaticallyAllocatedTaskCreator( void *pvParameters ) +{ +TaskHandle_t xCreatedTask; +BaseType_t xReturned; + + /* Avoid compiler warnings. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Create the task. xTaskCreateStatic() has two more parameters than + the usual xTaskCreate() function. The first new parameter is a pointer to + the pre-allocated stack. The second new parameter is a pointer to the + DummyTCB_t structure that will hold the task's TCB. If either pointer is + passed as NULL then the respective object will be allocated dynamically as + if xTaskCreate() had been called. */ + xReturned = xTaskCreateStatic( + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + tskIDLE_PRIORITY, /* The priority of the task. */ + &xCreatedTask, /* Handle of the task being created. */ + &( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ + &xTCBBuffer ); /* The variable that will hold that task's TCB. */ + + /* Check the task was created correctly, then delete the task. */ + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* In case configASSERT() is not defined. */ + vTaskDelete( xCreatedTask ); + + /* Ensure lower priority tasks get CPU time. */ + vTaskDelay( prvGetNextDelayTime() ); + + /* Create and delete the task a few times again - testing both static and + dynamic allocation for the stack and TCB. */ + xReturned = xTaskCreateStatic( + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + staticTASK_PRIORITY + 1, /* The priority of the task. */ + &xCreatedTask, /* Handle of the task being created. */ + NULL, /* This time, dynamically allocate the stack. */ + &xTCBBuffer ); /* The variable that will hold that task's TCB. */ + + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* In case configASSERT() is not defined. */ + vTaskDelete( xCreatedTask ); + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; + + /* Ensure lower priority tasks get CPU time. */ + vTaskDelay( prvGetNextDelayTime() ); + + xReturned = xTaskCreateStatic( + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + staticTASK_PRIORITY - 1, /* The priority of the task. */ + &xCreatedTask, /* Handle of the task being created. */ + &( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ + NULL ); /* This time dynamically allocate the TCB. */ + + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* In case configASSERT() is not defined. */ + vTaskDelete( xCreatedTask ); + + /* Ensure lower priority tasks get CPU time. */ + vTaskDelay( prvGetNextDelayTime() ); + + xReturned = xTaskCreateStatic( + prvStaticallyAllocatedTask, /* Function that implements the task. */ + "Static", /* Human readable name for the task. */ + configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ + NULL, /* Parameter to pass into the task. */ + staticTASK_PRIORITY, /* The priority of the task. */ + &xCreatedTask, /* Handle of the task being created. */ + NULL, /* This time dynamically allocate the stack and TCB. */ + NULL ); /* This time dynamically allocate the stack and TCB. */ + + configASSERT( xReturned == pdPASS ); + ( void ) xReturned; /* In case configASSERT() is not defined. */ + vTaskDelete( xCreatedTask ); + + /* Ensure lower priority tasks get CPU time. */ + vTaskDelay( prvGetNextDelayTime() ); + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; + } +} +/*-----------------------------------------------------------*/ + +static void prvStaticallyAllocatedTask( void *pvParameters ) +{ + ( void ) pvParameters; + + /* The created task doesn't do anything - just waits to get deleted. */ + vTaskSuspend( NULL ); +} +/*-----------------------------------------------------------*/ + +static UBaseType_t prvRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static TickType_t prvGetNextDelayTime( void ) +{ +TickType_t xNextDelay; +const TickType_t xMaxDelay = pdMS_TO_TICKS( ( TickType_t ) 150 ); +const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 ); +const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 ); + + /* Generate the next delay time. This is kept within a narrow band so as + not to disturb the timing of other tests - but does add in some pseudo + randomisation into the tests. */ + do + { + xNextDelay = prvRand() % xMaxDelay; + + /* Just in case this loop is executed lots of times. */ + vTaskDelay( xTinyDelay ); + + } while ( xNextDelay < xMinDelay ); + + return xNextDelay; +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreStaticAllocationTasksStillRunning( void ) +{ +static UBaseType_t uxLastCycleCounter = 0; +BaseType_t xReturn; + + if( uxCycleCounter == uxLastCycleCounter ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + uxLastCycleCounter = uxCycleCounter; + } + + return xReturn; +} + diff --git a/FreeRTOS/Demo/Common/Minimal/TaskNotify.c b/FreeRTOS/Demo/Common/Minimal/TaskNotify.c index ca02b4bbc..2a65b86c1 100644 --- a/FreeRTOS/Demo/Common/Minimal/TaskNotify.c +++ b/FreeRTOS/Demo/Common/Minimal/TaskNotify.c @@ -425,6 +425,7 @@ static void prvNotifiedTask( void *pvParameters ) { const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0; TickType_t xPeriod; +const uint32_t ulCyclesToRaisePriority = 50UL; /* Remove compiler warnings about unused parameters. */ ( void ) pvParameters; @@ -482,9 +483,28 @@ TickType_t xPeriod; the function call. */ ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod ); - /* Wait for the next notification again, clearing all notifications if - one is received, but this time blocking indefinitely. */ - ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + /* Occasionally raise the priority of the task being notified to test + the path where the task is notified from an ISR and becomes the highest + priority ready state task, but the pxHigherPriorityTaskWoken parameter + is NULL (which it is in the tick hook that sends notifications to this + task. */ + if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 ) + { + vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 ); + + /* Wait for the next notification again, clearing all notifications if + one is received, but this time blocking indefinitely. */ + ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + /* Reset the priority. */ + vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY ); + } + else + { + /* Wait for the next notification again, clearing all notifications if + one is received, but this time blocking indefinitely. */ + ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + } /* Incremented to show the task is still running. */ ulNotifyCycleCount++; diff --git a/FreeRTOS/Demo/Common/Minimal/death.c b/FreeRTOS/Demo/Common/Minimal/death.c index 46c711e9c..9a258bf38 100644 --- a/FreeRTOS/Demo/Common/Minimal/death.c +++ b/FreeRTOS/Demo/Common/Minimal/death.c @@ -114,9 +114,11 @@ task can tell if any of the suicidal tasks have failed to die. */ static volatile UBaseType_t uxTasksRunningAtStart = 0; -/* Tasks are deleted by the idle task. Under heavy load the idle task might -not get much processing time, so it would be legitimate for several tasks to -remain undeleted for a short period. */ +/* When a task deletes itself, it stack and TCB are cleaned up by the Idle task. +Under heavy load the idle task might not get much processing time, so it would +be legitimate for several tasks to remain undeleted for a short period. There +may also be a few other unexpected tasks if, for example, the tasks that test +static allocation are also being used. */ static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3; /* Used to store a handle to the task that should be killed by a suicidal task, @@ -151,7 +153,9 @@ UBaseType_t *puxPriority; If this is done, then uxTasksRunningAtStart needs incrementing again as that too is created when the scheduler is started. */ #if configUSE_TIMERS == 1 + { uxTasksRunningAtStart++; + } #endif } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/Common/Minimal/recmutex.c b/FreeRTOS/Demo/Common/Minimal/recmutex.c index a9a8c9c20..93238e741 100644 --- a/FreeRTOS/Demo/Common/Minimal/recmutex.c +++ b/FreeRTOS/Demo/Common/Minimal/recmutex.c @@ -125,7 +125,7 @@ be overridden by a definition in FreeRTOSConfig.h. */ /* Misc. */ #define recmuSHORT_DELAY ( pdMS_TO_TICKS( 20 ) ) #define recmuNO_DELAY ( ( TickType_t ) 0 ) -#define recmuEIGHT_TICK_DELAY ( ( TickType_t ) 8 ) +#define recmu15ms_DELAY ( pdMS_TO_TICKS( 15 ) ) /* The three tasks as described at the top of this file. */ static void prvRecursiveMutexControllingTask( void *pvParameters ); @@ -199,7 +199,7 @@ UBaseType_t ux; long enough to ensure the polling task will execute again before the block time expires. If the block time does expire then the error flag will be set here. */ - if( xSemaphoreTakeRecursive( xMutex, recmuEIGHT_TICK_DELAY ) != pdPASS ) + if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS ) { xErrorOccurred = pdTRUE; } diff --git a/FreeRTOS/Demo/Common/include/StaticAllocation.h b/FreeRTOS/Demo/Common/include/StaticAllocation.h new file mode 100644 index 000000000..64606270d --- /dev/null +++ b/FreeRTOS/Demo/Common/include/StaticAllocation.h @@ -0,0 +1,79 @@ +/* + FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + 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. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef STATIC_ALLOCATION_H +#define STATIC_ALLOCATION_H + +void vStartStaticallyAllocatedTasks( void ); +BaseType_t xAreStaticAllocationTasksStillRunning( void ); + +#endif /* STATIC_ALLOCATION_H */ + + + diff --git a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h index ce71af2df..37aaf9551 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h +++ b/FreeRTOS/Demo/WIN32-MSVC/FreeRTOSConfig.h @@ -78,7 +78,8 @@ * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See + * http://www.freertos.org/a00110.html *----------------------------------------------------------*/ #define configUSE_PREEMPTION 1 @@ -102,6 +103,7 @@ #define configUSE_ALTERNATIVE_API 1 #define configUSE_QUEUE_SETS 1 #define configUSE_TASK_NOTIFICATIONS 1 +#define configSUPPORT_STATIC_ALLOCATION 1 /* Software timer related configuration options. */ #define configUSE_TIMERS 1 diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj index 45919e965..5349d5037 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj @@ -151,6 +151,7 @@ + diff --git a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters index 47b88f09e..f9181f510 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters +++ b/FreeRTOS/Demo/WIN32-MSVC/WIN32.vcxproj.filters @@ -19,9 +19,6 @@ {34567deb-d5ab-4a56-8640-0aaec609521a} cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - {2d4a700c-06e3-4dd2-afbe-ab1be71ebe2a} - {88f409e6-d396-4ac5-94bd-7a99c914be46} @@ -32,6 +29,15 @@ {90b56567-bab6-4d92-b319-b514d378329d} + + {4ae1665e-a7bb-4c1a-81a3-531d883e6f2d} + + + {2d4a700c-06e3-4dd2-afbe-ab1be71ebe2a} + + + {fb86fa48-ac27-4f87-9215-ce9e1a1a85f9} + @@ -50,46 +56,46 @@ FreeRTOS Source\Source\Portable - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks FreeRTOS Source\Source - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks Demo App Source @@ -113,16 +119,10 @@ Demo App Source\FreeRTOS+Trace Recorder - Demo App Source\Common Demo Tasks - - - Demo App Source - - - Demo App Source + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks FreeRTOS Source\Source @@ -131,16 +131,25 @@ FreeRTOS Source\Source\Portable - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks - Demo App Source\Common Demo Tasks + Demo App Source\Full_Demo\Common Demo Tasks + + + Demo App Source\Full_Demo + + + Demo App Source\Blinky_Demo + + + Demo App Source\Full_Demo\Common Demo Tasks diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c index 6f89e265a..a69126e3d 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main.c @@ -154,6 +154,8 @@ void vApplicationMallocFailedHook( void ); void vApplicationIdleHook( void ); void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); void vApplicationTickHook( void ); +void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ); +void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ); /* * Writes trace data to a disk file when the trace recording is stopped. @@ -390,3 +392,37 @@ const HeapRegion_t xHeapRegions[] = } /*-----------------------------------------------------------*/ +void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) +{ +/* The buffers used by the idle task must be static so they are persistent, and +so exist after this function returns. */ +static DummyTCB_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the + opportunity to supply the buffers that will be used by the Idle task as its + stack and to hold its TCB. If these are set to NULL then the buffers will + be allocated dynamically, just as if xTaskCreate() had been called. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +} +/*-----------------------------------------------------------*/ +DummyTCB_t xTimerTaskTCB; +void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) +{ +/* The buffers used by the Timer/Daemon task must be static so they are +persistent, and so exist after this function returns. */ +//static DummyTCB_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the + opportunity to supply the buffers that will be used by the Timer/RTOS daemon + task as its stack and to hold its TCB. If these are set to NULL then the + buffers will be allocated dynamically, just as if xTaskCreate() had been + called. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +} + diff --git a/FreeRTOS/Demo/WIN32-MSVC/main_full.c b/FreeRTOS/Demo/WIN32-MSVC/main_full.c index b429d8c93..a0ad433f6 100644 --- a/FreeRTOS/Demo/WIN32-MSVC/main_full.c +++ b/FreeRTOS/Demo/WIN32-MSVC/main_full.c @@ -99,7 +99,7 @@ * to ensure it gets processor time. Its main function is to check that all the * standard demo tasks are still operational. While no errors have been * discovered the check task will print out "No Errors" along with some system - * status information. If an error is discovered in the execution of a task + * status information. If an error is discovered in the execution of a task * then the check task will print out an appropriate error message. * */ @@ -135,6 +135,7 @@ #include "IntSemTest.h" #include "TaskNotify.h" #include "QueueSetPolling.h" +#include "StaticAllocation.h" /* Priorities at which the tasks are created. */ #define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) @@ -214,6 +215,7 @@ int main_full( void ) vStartInterruptSemaphoreTasks(); vStartQueueSetPollingTask(); xTaskCreate( prvDemoQueueSpaceFunctions, "QSpace", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); + vStartStaticallyAllocatedTasks(); #if( configUSE_PREEMPTION != 0 ) { @@ -337,6 +339,10 @@ const TickType_t xCycleFrequency = pdMS_TO_TICKS( 2500UL ); { pcStatusMessage = "Error: Queue set polling"; } + else if( xAreStaticAllocationTasksStillRunning() != pdPASS ) + { + pcStatusMessage = "Error: Static allocation"; + } /* 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 8951b25b0..a0e55e6d8 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -681,7 +681,7 @@ extern "C" { #endif #ifndef pvPortMallocAligned - #define pvPortMallocAligned( x, puxStackBuffer ) ( ( ( puxStackBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxStackBuffer ) ) + #define pvPortMallocAligned( x, puxPreallocatedBuffer ) ( ( ( puxPreallocatedBuffer ) == NULL ) ? ( pvPortMalloc( ( x ) ) ) : ( puxPreallocatedBuffer ) ) #endif #ifndef vPortFreeAligned @@ -772,6 +772,10 @@ extern "C" { #define portTICK_TYPE_IS_ATOMIC 0 #endif +#ifndef configSUPPORT_STATIC_ALLOCATION + #define configSUPPORT_STATIC_ALLOCATION 0 +#endif + #if( portTICK_TYPE_IS_ATOMIC == 0 ) /* Either variables of tick type cannot be read atomically, or portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index b8d6dd890..1108d3421 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -128,6 +128,12 @@ typedef enum eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ } eNotifyAction; +/* For data hiding purposes. */ +typedef enum +{ + eNothing = 0 +} eDummy; + /* * Used internally only. */ @@ -183,6 +189,65 @@ typedef enum eNoTasksWaitingTimeout /* No tasks are waiting for a timeout so it is safe to enter a sleep mode that can only be exited by an external interrupt. */ } eSleepModeStatus; +/* Value that can be assigned to the eNotifyState member of the TCB. */ +typedef enum +{ + eNotWaitingNotification = 0, + eWaitingNotification, + eNotified +} eNotifyValue; + +/* + * FreeRTOS implements a strict data hiding policy, so the real task control + * block (TCB) structure is not accessible to the application code. However, if + * the application writer wants to statically allocate a TCB then the size of + * the TCB needs to be know. The dummy TCB structure below is used for this + * purpose. Its size will allows match the size of the real TCB, no matter what + * the FreeRTOSConfig.h settings. + */ +typedef struct xDUMMY_TCB +{ + void *pxDummy1; + #if ( portUSING_MPU_WRAPPERS == 1 ) + xMPU_SETTINGS xDummy2; + #endif + ListItem_t xDummy3[ 2 ]; + UBaseType_t uxDummy5; + void *pxDummy6; + uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; + #if ( portSTACK_GROWTH > 0 ) + void *pxDummy8; + #endif + #if ( portCRITICAL_NESTING_IN_TCB == 1 ) + UBaseType_t uxDummy9; + #endif + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy10[ 2 ]; + #endif + #if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxDummy12[ 2 ]; + #endif + #if ( configUSE_APPLICATION_TASK_TAG == 1 ) + void *pxDummy14; + #endif + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) + void pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + #endif + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulDummy16; + #endif + #if ( configUSE_NEWLIB_REENTRANT == 1 ) + struct _reent xDummy17; + #endif + #if ( configUSE_TASK_NOTIFICATIONS == 1 ) + uint32_t ulDummy18; + eDummy eDummy19; + #endif + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + UBaseType_t uxDummy20; + #endif + +} DummyTCB_t; /** * Defines the priority used by the idle task. This must not be modified. @@ -342,7 +407,112 @@ is used in assert() statements. */ * \defgroup xTaskCreate xTaskCreate * \ingroup Tasks */ -#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) ) +#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ), ( NULL ) ) + +/** + * task. h + *
+ BaseType_t xTaskCreateStatic(
+							  TaskFunction_t pvTaskCode,
+							  const char * const pcName,
+							  uint16_t usStackDepth,
+							  void *pvParameters,
+							  UBaseType_t uxPriority,
+							  TaskHandle_t *pvCreatedTask,
+							  StackType_t *pxStackBuffer,
+							  DummyTCB_t *pxTCBBuffer
+						  );
+ * + * Create a new task and add it to the list of tasks that are ready to run. + * If a task is created using xTaskCreate() then the stack and task control + * block (TCB) used by the task are allocated dynamically. If a task is created + * using xTaskCreateStatic() then the application writer can optionally provide + * the buffers that will hold the task stack and TCB respectively. + * xTaskCreateStatic() therefore allows tasks to be created without any dynamic + * memory allocation. + * + * @param pvTaskCode Pointer to the task entry function. Tasks + * must be implemented to never return (i.e. continuous loop). + * + * @param pcName A descriptive name for the task. This is mainly used to + * facilitate debugging. The maximum length of the string is defined by + * configMAX_TASK_NAME_LEN in FreeRTOSConfig.h. + * + * @param usStackDepth The size of the task stack specified as the number of + * variables the stack can hold - not the number of bytes. For example, if + * the stack is 32-bits wide and usStackDepth is defined as 100 then 400 bytes + * will be allocated for stack storage. + * + * @param pvParameters Pointer that will be used as the parameter for the task + * being created. + * + * @param uxPriority The priority at which the task will run. + * + * @param pvCreatedTask Used to pass back a handle by which the created task + * can be referenced. Pass as NULL if the handle is not required. + * + * @param pxStackBuffer If pxStackBuffer is NULL then the stack used by the + * task will be allocated dynamically, just as if the task was created using + * xTaskCreate(). if pxStackBuffer is not NULL then it must point to a + * StackType_t array that has at least usStackDepth indexes - the array will + * then be used as the task's stack. + * + * @param pxTCBBuffer If pxTCBBuffer is NULL then the TCB (which is the + * structures used internally within FreeRTOS to hold information on the task) + * will be allocated dynamically, just as when xTaskCreate() is used. If + * pxTCBBuffer is not NULL then it must point to a variable of type DummyTCB_T, + * which will then be used as the TCB of the task being created. + * + * @return pdPASS if the task was successfully created and added to a ready + * list, otherwise an error code defined in the file projdefs.h + * + * Example usage: +
+
+ // Dimensions the buffer that the task being created will use as its stack.
+ // NOTE:  This is the number of words the stack will hold, not the number of
+ // bytes.  For example, if each stack item is 32-bits, and this is set to 100,
+ // then 400 bytes (100 * 32-bits) will be allocated.
+ #define STACK_SIZE 200
+
+ // Structure that will hold the TCB of the task being created.
+ DummyTCB_t xTCB;
+
+ // Buffer that the task being created will use as its stack.
+ StackType_t xStack[ STACK_SIZE ];
+   
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+	 for( ;; )
+	 {
+		 // Task code goes here.
+	 }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ static uint8_t ucParameterToPass;
+ TaskHandle_t xHandle = NULL;
+
+	 // Create the task without using any dynamic memory allocation.
+	 xTaskCreate( vTaskCode,          // As per xTaskCreate() parameter.
+				  "NAME",             // As per xTaskCreate() parameter.
+				  STACK_SIZE,         // As per xTaskCreate() parameter.
+				  &ucParameterToPass, // As per xTaskCreate() parameter. 
+				  tskIDLE_PRIORITY,   // As per xTaskCreate() parameter.
+				  &xHandle,           // As per xTaskCreate() parameter.
+				  xStack,             // Pointer to the buffer that the task being created will use as its stack.
+				  &xTCB );            // Pointer to a structure in which the TCB of the task being created will be stored.
+ }
+   
+ * \defgroup xTaskCreateStatic xTaskCreateStatic + * \ingroup Tasks + */ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xTaskCreateStatic( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, puxStackBuffer, pxDummyTCB ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( puxStackBuffer ), ( pxDummyTCB ), ( NULL ) ) +#endif /** * task. h @@ -411,7 +581,7 @@ TaskHandle_t xHandle; * \defgroup xTaskCreateRestricted xTaskCreateRestricted * \ingroup Tasks */ -#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ((x)->xRegions) ) +#define xTaskCreateRestricted( x, pxCreatedTask ) xTaskGenericCreate( ((x)->pvTaskCode), ((x)->pcName), ((x)->usStackDepth), ((x)->pvParameters), ((x)->uxPriority), (pxCreatedTask), ((x)->puxStackBuffer), ( NULL ), ((x)->xRegions) ) /** * task. h @@ -1983,7 +2153,7 @@ BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGE * Generic version of the task creation function which is in turn called by the * xTaskCreate() and xTaskCreateRestricted() macros. */ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, DummyTCB_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index 7b0406d2a..b74b4efa1 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.c @@ -1935,8 +1935,8 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { - /* The task waiting has a higher priority so record that a - context switch is required. */ + /* The task waiting has a higher priority so record that + a context switch is required. */ vTaskMissedYield(); } else diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index fe2f5ae1a..04208ca4a 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -105,6 +105,10 @@ functions but without including stdio.h here. */ #endif /* INCLUDE_vTaskSuspend */ #endif /* configUSE_TICKLESS_IDLE */ +#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION != 1 ) ) + #error configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h when the MPU is used. +#endif + /* * Defines the size, in words, of the stack allocated to the idle task. */ @@ -118,13 +122,12 @@ functions but without including stdio.h here. */ #define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API() #endif -/* Value that can be assigned to the eNotifyState member of the TCB. */ -typedef enum -{ - eNotWaitingNotification = 0, - eWaitingNotification, - eNotified -} eNotifyValue; +/* Bits that can be set in tskTCB->uxStaticAllocationFlags to indicate that the +stack and TCB were statically allocated respectively. When these are statically +allocated they won't be freed if the task using the stack and TCB gets +deleted. */ +#define taskSTATICALLY_ALLOCATED_STACK ( ( UBaseType_t ) 0x01 ) +#define taskSTATICALLY_ALLOCATED_TCB ( ( UBaseType_t ) 0x02 ) /* * Task control block. A task control block (TCB) is allocated for each task, @@ -137,7 +140,6 @@ typedef struct tskTaskControlBlock #if ( portUSING_MPU_WRAPPERS == 1 ) xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */ - BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ #endif ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ @@ -151,17 +153,17 @@ typedef struct tskTaskControlBlock #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) - UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ + UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */ #endif #if ( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */ - UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ + UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */ #endif #if ( configUSE_MUTEXES == 1 ) - UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ - UBaseType_t uxMutexesHeld; + UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */ + UBaseType_t uxMutexesHeld; #endif #if ( configUSE_APPLICATION_TASK_TAG == 1 ) @@ -184,7 +186,7 @@ typedef struct tskTaskControlBlock newlib and must provide system-wide implementations of the necessary stubs. Be warned that (at the time of writing) the current newlib design implements a system-wide malloc() that must be provided with locks. */ - struct _reent xNewLib_reent; + struct _reent xNewLib_reent; #endif #if ( configUSE_TASK_NOTIFICATIONS == 1 ) @@ -192,7 +194,11 @@ typedef struct tskTaskControlBlock volatile eNotifyValue eNotifyState; #endif -} tskTCB; + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + UBaseType_t uxStaticAllocationFlags; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */ + #endif + + } tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name below to enable the use of older kernel aware debuggers. */ @@ -232,12 +238,6 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r #endif -#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) - - PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ - -#endif - /* Other file private variables. --------------------------------*/ PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U; @@ -248,6 +248,7 @@ PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE; PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0; PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U; PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U; /* Initialised to portMAX_DELAY before the scheduler starts. */ +PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */ /* Context switches are held pending while the scheduler is suspended. Also, interrupts must not manipulate the xGenericListItem of a TCB, or any of the @@ -409,21 +410,25 @@ being used for another purpose. The following bit definition is used to inform the scheduler that the value should not be changed - in which case it is the responsibility of whichever module is using the value to ensure it gets set back to its original value when it is released. */ -#if configUSE_16_BIT_TICKS == 1 +#if( configUSE_16_BIT_TICKS == 1 ) #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U #else #define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL #endif /* Callback function prototypes. --------------------------*/ -#if configCHECK_FOR_STACK_OVERFLOW > 0 +#if( configCHECK_FOR_STACK_OVERFLOW > 0 ) extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ); #endif -#if configUSE_TICK_HOOK > 0 +#if( configUSE_TICK_HOOK > 0 ) extern void vApplicationTickHook( void ); #endif +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + extern void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ); +#endif + /* File private functions. --------------------------------*/ /* @@ -490,7 +495,7 @@ static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) PRIVI * Allocates memory from the heap for a TCB and associated stack. Checks the * allocation was successful. */ -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION; +static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer, TCB_t * const pucTCBBuffer ) PRIVILEGED_FUNCTION; /* * Fills an TaskStatus_t structure with information on each task that is @@ -549,7 +554,7 @@ static void prvResetNextTaskUnblockTime( void ); #endif /*-----------------------------------------------------------*/ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, DummyTCB_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { BaseType_t xReturn; TCB_t * pxNewTCB; @@ -560,7 +565,7 @@ StackType_t *pxTopOfStack; /* Allocate the memory required by the TCB and stack for the new task, checking that the allocation was successful. */ - pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); + pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer, ( TCB_t* ) pxTCBBuffer ); /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ if( pxNewTCB != NULL ) { @@ -576,20 +581,6 @@ StackType_t *pxTopOfStack; xRunPrivileged = pdFALSE; } uxPriority &= ~portPRIVILEGE_BIT; - - if( puxStackBuffer != NULL ) - { - /* The application provided its own stack. Note this so no - attempt is made to delete the stack should that task be - deleted. */ - pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE; - } - else - { - /* The stack was allocated dynamically. Note this so it can be - deleted again if the task is deleted. */ - pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE; - } #endif /* portUSING_MPU_WRAPPERS == 1 */ /* Calculate the top of stack address. This depends on whether the @@ -1045,7 +1036,7 @@ StackType_t *pxTopOfStack; else if( ( pxStateList == &xTasksWaitingTermination ) || ( pxStateList == NULL ) ) { /* The task being queried is referenced from the deleted - tasks list, or it is not referenced from any lists at + tasks list, or it is not referenced from any lists at all. */ eReturn = eDeleted; } @@ -1555,20 +1546,18 @@ StackType_t *pxTopOfStack; void vTaskStartScheduler( void ) { BaseType_t xReturn; +DummyTCB_t *pxIdleTaskTCBBuffer = NULL; +StackType_t *pxIdleTaskStackBuffer = NULL; +uint16_t usIdleTaskStackSize = tskIDLE_STACK_SIZE; - /* Add the idle task at the lowest priority. */ - #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { - /* Create the idle task, storing its handle in xIdleTaskHandle so it can - be returned by the xTaskGetIdleTaskHandle() function. */ - xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &usIdleTaskStackSize ); } - #else - { - /* Create the idle task without storing its handle. */ - xReturn = xTaskCreate( prvIdleTask, "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - } - #endif /* INCLUDE_xTaskGetIdleTaskHandle */ + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + /* Add the idle task at the lowest priority. */ + xReturn = xTaskGenericCreate( prvIdleTask, "IDLE", usIdleTaskStackSize, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle, pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer, NULL ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ #if ( configUSE_TIMERS == 1 ) { @@ -1628,6 +1617,10 @@ BaseType_t xReturn; or the timer task. */ configASSERT( xReturn ); } + + /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0, + meaning xIdleTaskHandle is not used anywhere else. */ + ( void ) xIdleTaskHandle; } /*-----------------------------------------------------------*/ @@ -3145,10 +3138,17 @@ static void prvAddCurrentTaskToDelayedList( const TickType_t xTimeToWake ) } /*-----------------------------------------------------------*/ -static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) +static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer, TCB_t * const pxTCBBuffer ) { TCB_t *pxNewTCB; + #if( configASSERT_DEFINED == 1 ) + { + volatile size_t xSize = sizeof( DummyTCB_t ); + configASSERT( xSize == sizeof( TCB_t ) ); + } + #endif /* configASSERT_DEFINED */ + /* If the stack grows down then allocate the stack then the TCB so the stack does not grow into the TCB. Likewise if the stack grows up then allocate the TCB then the stack. */ @@ -3156,7 +3156,7 @@ TCB_t *pxNewTCB; { /* Allocate space for the TCB. Where the memory comes from depends on the implementation of the port malloc function. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + pxNewTCB = ( TCB_t * ) pvPortMallocAligned( sizeof( TCB_t ), pxTCBBuffer ); if( pxNewTCB != NULL ) { @@ -3167,8 +3167,12 @@ TCB_t *pxNewTCB; if( pxNewTCB->pxStack == NULL ) { - /* Could not allocate the stack. Delete the allocated TCB. */ - vPortFree( pxNewTCB ); + /* Could not allocate the stack. Delete the allocated TCB - if + it was allocated dynamically. */ + if( pxTCBBuffer == NULL ) + { + vPortFree( pxNewTCB ); + } pxNewTCB = NULL; } } @@ -3182,9 +3186,8 @@ TCB_t *pxNewTCB; if( pxStack != NULL ) { - /* Allocate space for the TCB. Where the memory comes from depends - on the implementation of the port malloc function. */ - pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); + /* Allocate space for the TCB. */ + pxNewTCB = ( TCB_t * ) pvPortMallocAligned( sizeof( TCB_t ), pxTCBBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */ if( pxNewTCB != NULL ) { @@ -3199,6 +3202,10 @@ TCB_t *pxNewTCB; { vPortFree( pxStack ); } + else + { + mtCOVERAGE_TEST_MARKER(); + } } } else @@ -3217,6 +3224,34 @@ TCB_t *pxNewTCB; ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) ); } #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */ + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + pxNewTCB->uxStaticAllocationFlags = 0; + + if( puxStackBuffer != NULL ) + { + /* The application provided its own stack - note the fact so no + attempt is made to delete the stack if the task is deleted. */ + pxNewTCB->uxStaticAllocationFlags |= taskSTATICALLY_ALLOCATED_STACK; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( pxTCBBuffer != NULL ) + { + /* The application provided its own TCB. Note the fact so no + attempt is made to delete the TCB if the task is deleted. */ + pxNewTCB->uxStaticAllocationFlags |= taskSTATICALLY_ALLOCATED_TCB; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } return pxNewTCB; @@ -3373,22 +3408,34 @@ TCB_t *pxNewTCB; } #endif /* configUSE_NEWLIB_REENTRANT */ - #if( portUSING_MPU_WRAPPERS == 1 ) + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { - /* Only free the stack if it was allocated dynamically in the first - place. */ - if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE ) + /* Only free the stack and TCB if they were allocated dynamically in + the first place. */ + if( ( pxTCB->uxStaticAllocationFlags & taskSTATICALLY_ALLOCATED_STACK ) == ( UBaseType_t ) 0 ) { vPortFreeAligned( pxTCB->pxStack ); } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( pxTCB->uxStaticAllocationFlags & taskSTATICALLY_ALLOCATED_TCB ) == ( UBaseType_t ) 0 ) + { + vPortFreeAligned( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } #else { vPortFreeAligned( pxTCB->pxStack ); + vPortFree( pxTCB ); } #endif - - vPortFree( pxTCB ); } #endif /* INCLUDE_vTaskDelete */ @@ -4392,6 +4439,13 @@ TickType_t uxReturn; { *pxHigherPriorityTaskWoken = pdTRUE; } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter to an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } } else { @@ -4475,6 +4529,13 @@ TickType_t uxReturn; { *pxHigherPriorityTaskWoken = pdTRUE; } + else + { + /* Mark that a yield is pending in case the user is not + using the "xHigherPriorityTaskWoken" parameter in an ISR + safe FreeRTOS function. */ + xYieldPending = pdTRUE; + } } else { @@ -4496,11 +4557,9 @@ TickType_t uxReturn; TCB_t *pxTCB; BaseType_t xReturn; - pxTCB = ( TCB_t * ) xTask; - /* If null is passed in here then it is the calling task that is having its notification state cleared. */ - pxTCB = prvGetTCBFromHandle( pxTCB ); + pxTCB = prvGetTCBFromHandle( xTask ); taskENTER_CRITICAL(); { @@ -4520,6 +4579,8 @@ TickType_t uxReturn; } #endif /* configUSE_TASK_NOTIFICATIONS */ +/*-----------------------------------------------------------*/ + #ifdef FREERTOS_MODULE_TEST #include "tasks_test_access_functions.h" diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index c7ab9023f..0aef5ad71 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -178,6 +178,16 @@ PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; /*-----------------------------------------------------------*/ +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + + /* If static allocation is supported then the application must provide the + following callback function - which enables the application to optionally + provide the memory that will be used by the timer task as the task's stack + and TCB. */ + extern void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ); + +#endif + /* * Initialise the infrastructure used by the timer service task if it has not * been initialised already. @@ -240,6 +250,10 @@ static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseTy BaseType_t xTimerCreateTimerTask( void ) { BaseType_t xReturn = pdFAIL; +DummyTCB_t *pxTimerTaskTCBBuffer = NULL; +StackType_t *pxTimerTaskStackBuffer = NULL; +uint16_t usTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; + /* This function is called when the scheduler is started if configUSE_TIMERS is set to 1. Check that the infrastructure used by the @@ -249,16 +263,24 @@ BaseType_t xReturn = pdFAIL; if( xTimerQueue != NULL ) { + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &usTimerTaskStackSize ); + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + #if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 ) { /* Create the timer task, storing its handle in xTimerTaskHandle so it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */ - xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle ); + xReturn = xTaskGenericCreate( prvTimerTask, "Tmr Svc", usTimerTaskStackSize, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle, pxTimerTaskStackBuffer, pxTimerTaskTCBBuffer, NULL ); } #else { /* Create the timer task without storing its handle. */ - xReturn = xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL); + xReturn = xTaskGenericCreate( prvTimerTask, "Tmr Svc", usTimerTaskStackSize, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL, pxTimerTaskStackBuffer, pxTimerTaskTCBBuffer, NULL ); } #endif } -- 2.39.5