diff --git a/.gitmodules b/.gitmodules index 9a4230ca9ae..61b53b5e8ae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "FreeRTOS/Source"] path = FreeRTOS/Source - url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git + url = https://github.com/chinglee-iot/FreeRTOS-Kernel.git [submodule "FreeRTOS/Test/CMock/CMock"] path = FreeRTOS/Test/CMock/CMock url = https://github.com/ThrowTheSwitch/CMock.git diff --git a/FreeRTOS/Source b/FreeRTOS/Source index f0609db5ccf..4b7ac8411e8 160000 --- a/FreeRTOS/Source +++ b/FreeRTOS/Source @@ -1 +1 @@ -Subproject commit f0609db5ccfdbfbcf713108f6b785d6ac2aaff72 +Subproject commit 4b7ac8411e896301f679d2ff328139a96fc5d872 diff --git a/FreeRTOS/Test/CMock/smp/Makefile b/FreeRTOS/Test/CMock/smp/Makefile index 948942e367a..4d33f50a5b8 100644 --- a/FreeRTOS/Test/CMock/smp/Makefile +++ b/FreeRTOS/Test/CMock/smp/Makefile @@ -16,6 +16,10 @@ SUITES += multiple_priorities_no_timeslice_mock # SUITS for configASSERT SUITES += config_assert +# SUITS for granular lock feature +SUITES += granular_lock +SUITES += granular_lock_timer + # PROJECT and SUITE variables are determined based on path like so: # $(UT_ROOT_DIR)/$(PROJECT)/$(SUITE) PROJECT := $(lastword $(subst /, ,$(dir $(abspath $(MAKEFILE_ABSPATH))))) diff --git a/FreeRTOS/Test/CMock/smp/granular_lock/FreeRTOSConfig.h b/FreeRTOS/Test/CMock/smp/granular_lock/FreeRTOSConfig.h new file mode 100644 index 00000000000..a2504e8a522 --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock/FreeRTOSConfig.h @@ -0,0 +1,156 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include "fake_assert.h" + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See +* https://www.FreeRTOS.org/a00110.html +*----------------------------------------------------------*/ + +/* SMP test specific configuration */ +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configNUMBER_OF_CORES 16 +#define configUSE_CORE_AFFINITY 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configTICK_CORE 0 + +/* OS Configuration */ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configTICK_RATE_HZ ( 1000 ) +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 70 ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 52 * 1024 ) ) +#define configMAX_TASK_NAME_LEN ( 12 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 20 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 5 +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configINITIAL_TICK_COUNT ( ( TickType_t ) 0 ) +#define configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN 1 +#define portREMOVE_STATIC_QUALIFIER 1 +#define portCRITICAL_NESTING_IN_TCB 0 +#define portSTACK_GROWTH ( 1 ) +#define configUSE_PASSIVE_IDLE_HOOK 0 +#define configUSE_TICKLESS_IDLE 1 +#define configSTACK_DEPTH_TYPE uint32_t + +/* Software timer related configuration options. */ +#define configUSE_TIMERS 0 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +#define configMAX_PRIORITIES ( 7 ) + +/* Run time stats gathering configuration options. */ +unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ +void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() +#define portUSING_MPU_WRAPPERS 0 +#define portHAS_STACK_OVERFLOW_CHECKING 0 +#define configENABLE_MPU 0 + +/* Co-routine related configuration options. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. In most cases the linker will remove unused + * functions anyway. */ +#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_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 + +/* It is a good idea to define configASSERT() while developing. configASSERT() + * uses the same semantics as the standard C assert() macro. */ +#define configASSERT( x ) \ + do \ + { \ + if( x ) \ + { \ + vFakeAssert( true, __FILE__, __LINE__ ); \ + } \ + else \ + { \ + vFakeAssert( false, __FILE__, __LINE__ ); \ + } \ + } while( 0 ) + +#define configINCLUDE_MESSAGE_BUFFER_AMP_DEMO 0 +#if ( configINCLUDE_MESSAGE_BUFFER_AMP_DEMO == 1 ) + extern void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ); + #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) +#endif /* configINCLUDE_MESSAGE_BUFFER_AMP_DEMO */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Test/CMock/smp/granular_lock/Makefile b/FreeRTOS/Test/CMock/smp/granular_lock/Makefile new file mode 100644 index 00000000000..1480b81cc04 --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock/Makefile @@ -0,0 +1,48 @@ +# indent with spaces +.RECIPEPREFIX := $(.RECIPEPREFIX) $(.RECIPEPREFIX) + +# Do not move this line below the include +MAKEFILE_ABSPATH := $(abspath $(lastword $(MAKEFILE_LIST))) +include ../../makefile.in + +# PROJECT_SRC lists the .c files under test +PROJECT_SRC := tasks.c queue.c stream_buffer.c event_groups.c + +# PROJECT_DEPS_SRC list the .c file that are dependencies of PROJECT_SRC files +# Files in PROJECT_DEPS_SRC are excluded from coverage measurements +PROJECT_DEPS_SRC := list.c + +# PROJECT_HEADER_DEPS: headers that should be excluded from coverage measurements. +PROJECT_HEADER_DEPS := FreeRTOS.h + +# SUITE_UT_SRC: .c files that contain test cases (must end in _utest.c) +SUITE_UT_SRC := granular_lock_utest.c + +# SUITE_SUPPORT_SRC: .c files used for testing that do not contain test cases. +# Paths are relative to PROJECT_DIR +SUITE_SUPPORT_SRC := smp_utest_common.c + +# List the headers used by PROJECT_SRC that you would like to mock +MOCK_FILES_FP += $(KERNEL_DIR)/include/timers.h +MOCK_FILES_FP += $(UT_ROOT_DIR)/config/fake_assert.h +MOCK_FILES_FP += $(UT_ROOT_DIR)/config/fake_port.h +MOCK_FILES_FP += $(UT_ROOT_DIR)//smp/granular_lock/portmacro.h + +# List any addiitonal flags needed by the preprocessor +CPPFLAGS += + +# List any addiitonal flags needed by the compiler +CFLAGS += + +# Try not to edit beyond this line unless necessary. + +# Project is determined based on path: $(UT_ROOT_DIR)/$(PROJECT) +PROJECT := $(lastword $(subst /, ,$(dir $(abspath $(MAKEFILE_ABSPATH)/../)))) +SUITE := $(lastword $(subst /, ,$(dir $(MAKEFILE_ABSPATH)))) + +# Make variables available to included makefile +export + +include ../../testdir.mk + + diff --git a/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock.yml b/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock.yml new file mode 100644 index 00000000000..e149b08f25f --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock.yml @@ -0,0 +1,32 @@ +:cmock: + :mock_prefix: mock_ + :when_no_prototypes: :warn + :when_ptr: :compare_ptr + :treat_externs: :include + :enforce_strict_ordering: TRUE + :plugins: + - :ignore + - :ignore_arg + - :expect_any_args + - :callback + - :return_thru_ptr + :callback_include_count: true # include a count arg when calling the callback + :callback_after_arg_check: false # check arguments before calling the callback + :treat_as: + uint8: HEX8 + uint16: HEX16 + uint32: UINT32 + int8: INT8 + bool: UINT8 + :includes: # This will add these includes to each mock. + - + - "FreeRTOS.h" + :treat_externs: :exclude # Now the extern-ed functions will be mocked. + :weak: __attribute__((weak)) + :verbosity: 3 + :attributes: + - PRIVILEGED_FUNCTION + :strippables: + - PRIVILEGED_FUNCTION + - portDONT_DISCARD + :treat_externs: :include diff --git a/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock_utest.c b/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock_utest.c new file mode 100644 index 00000000000..927f6782720 --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock/granular_lock_utest.c @@ -0,0 +1,280 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ +/*! @file granular_lock_utest.c */ + +/* C runtime includes. */ +#include +#include +#include +#include + +/* Task includes */ +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" +#include "event_groups.h" +#include "queue.h" +#include "semphr.h" + +/* Test includes. */ +#include "unity.h" +#include "unity_memory.h" +#include "../global_vars.h" +#include "../smp_utest_common.h" + +/* Mock includes. */ +//#include "mock_timers.h" +#include "mock_fake_assert.h" +#include "mock_fake_port.h" +#include "mock_portmacro.h" + +/* =========================== EXTERN VARIABLES =========================== */ +extern portSPINLOCK_TYPE xTaskSpinlock; +extern portSPINLOCK_TYPE xISRSpinlock; + +/* =========================== GLOBAL VARIABLES =========================== */ + +static TaskHandle_t xTaskHandles[ configNUMBER_OF_CORES ] = { NULL }; +uint32_t xPortCriticalNestingCount[ configNUMBER_OF_CORES ] = { 0U }; + +static BaseType_t xCoreYields[ configNUMBER_OF_CORES ] = { 0 }; + +static UBaseType_t xInterruptMaskCount[ configNUMBER_OF_CORES ] = { 0U }; +static BaseType_t xInterruptDisableStatus[ configNUMBER_OF_CORES ] = { 0U }; + +/* ============================ Callback Functions ============================ */ +static void vFakePortInitSpinlock_callback( portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + + pxSpinlock->uxLockCount = 0; + pxSpinlock->xOwnerCore = -1; +} + +static void vYieldCores( void ) +{ + BaseType_t i; + BaseType_t xPreviousCoreId = portGET_CORE_ID(); + + if( ( xTaskSpinlock.uxLockCount == 0U ) && ( xISRSpinlock.uxLockCount == 0U ) ) + { + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + if( ( xCoreYields[ i ] == pdTRUE ) && + ( xInterruptMaskCount[ i ] == 0 ) && + ( xInterruptDisableStatus[ i ] == pdFALSE ) ) + { + vSetCurrentCore( i ); + xCoreYields[ i ] = pdFALSE; + vTaskSwitchContext( i ); + } + } + + vSetCurrentCore( xPreviousCoreId ); + } +} + +static void vFakePortReleaseSpinlock_callback( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + TEST_ASSERT_NOT_EQUAL( -1, pxSpinlock->xOwnerCore ); + TEST_ASSERT_NOT_EQUAL( 0, pxSpinlock->uxLockCount ); + TEST_ASSERT_EQUAL( xCoreID, pxSpinlock->xOwnerCore ); + + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount - 1U; + if( pxSpinlock->uxLockCount == 0U ) + { + pxSpinlock->xOwnerCore = -1; + } + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static void vFakePortGetSpinlock_callback( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + + if( pxSpinlock->uxLockCount == 0 ) + { + // TEST_ASSERT_EQUAL( -1, pxSpinlock->xOwnerCore ); + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount + 1U; + pxSpinlock->xOwnerCore = xCoreID; + } + else + { + TEST_ASSERT_EQUAL( xCoreID, pxSpinlock->xOwnerCore ); + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount + 1U; + } +} + +static void vFakePortYieldCore_callback( int xCoreID, + int cmock_num_calls ) +{ + BaseType_t xCoreInCritical = pdFALSE; + BaseType_t xPreviousCoreId; + + /* Check if the lock is acquired by any core. */ + if( ( xTaskSpinlock.uxLockCount != 0U ) || ( xISRSpinlock.uxLockCount != 0U ) ) + { + xCoreInCritical = pdTRUE; + } + + if( xCoreInCritical == pdTRUE ) + { + /* If a task is in the critical section, pend the core yield until the + * spinlock is released. */ + xCoreYields[ xCoreID ] = pdTRUE; + } + else + { + /* No task is in the critical section. We can yield this core. */ + xPreviousCoreId = portGET_CORE_ID(); + vSetCurrentCore( xCoreID ); + vTaskSwitchContext( xCoreID ); + vSetCurrentCore( xPreviousCoreId ); + } +} + +static UBaseType_t ulFakePortSetInterruptMaskFromISR_callback( int cmock_num_calls ) +{ + ( void )cmock_num_calls; + xInterruptMaskCount[ portGET_CORE_ID() ]++; + return xInterruptMaskCount[ portGET_CORE_ID() ]; +} + +static void vFakePortClearInterruptMaskFromISR_callback( UBaseType_t uxNewMaskValue, int cmock_num_calls ) +{ + ( void )uxNewMaskValue; + ( void )cmock_num_calls; + TEST_ASSERT_EQUAL( uxNewMaskValue, xInterruptMaskCount[ portGET_CORE_ID() ] ); + TEST_ASSERT_NOT_EQUAL( 0, xInterruptMaskCount[ portGET_CORE_ID() ] ); + xInterruptMaskCount[ portGET_CORE_ID() ]--; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static UBaseType_t ulFakePortSetInterruptMask_callback( int cmock_num_calls ) +{ + ( void )cmock_num_calls; + xInterruptMaskCount[ portGET_CORE_ID() ]++; + return xInterruptMaskCount[ portGET_CORE_ID() ]; +} + +static void vFakePortClearInterruptMask_callback( UBaseType_t uxNewMaskValue, int cmock_num_calls ) +{ + ( void )uxNewMaskValue; + ( void )cmock_num_calls; + TEST_ASSERT_EQUAL( uxNewMaskValue, xInterruptMaskCount[ portGET_CORE_ID() ] ); + TEST_ASSERT_NOT_EQUAL( 0, xInterruptMaskCount[ portGET_CORE_ID() ] ); + xInterruptMaskCount[ portGET_CORE_ID() ]--; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static uint32_t vFakePortDisableInterrupts_callback( int cmock_num_calls ) +{ + xInterruptDisableStatus[ portGET_CORE_ID() ] = pdTRUE; + return 0; +} + +static void vFakePortEnableInterrupts_callback( int cmock_num_calls ) +{ + xInterruptDisableStatus[ portGET_CORE_ID() ] = pdFALSE; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +/* ============================ Unity Fixtures ============================ */ + +/*! called before each testcase */ +void setUp( void ) +{ + /* Use the common setup for the testing. */ + commonSetUp(); + /* Specify the granular lock specific implementation. */ + vFakePortInitSpinlock_Stub( vFakePortInitSpinlock_callback ); + vFakePortReleaseSpinlock_Stub( vFakePortReleaseSpinlock_callback ); + vFakePortGetSpinlock_Stub( vFakePortGetSpinlock_callback ); + vFakePortYieldCore_Stub( vFakePortYieldCore_callback ); + + /* Interrupt masks. */ + memset( xInterruptMaskCount, 0, sizeof( UBaseType_t ) * configNUMBER_OF_CORES ); + ulFakePortSetInterruptMaskFromISR_StopIgnore(); + ulFakePortSetInterruptMaskFromISR_Stub( ulFakePortSetInterruptMaskFromISR_callback ); + vFakePortClearInterruptMaskFromISR_StopIgnore(); + vFakePortClearInterruptMaskFromISR_Stub( vFakePortClearInterruptMaskFromISR_callback ); + + ulFakePortSetInterruptMask_StopIgnore(); + ulFakePortSetInterruptMask_Stub( ulFakePortSetInterruptMask_callback ); + vFakePortClearInterruptMask_StopIgnore(); + vFakePortClearInterruptMask_Stub( vFakePortClearInterruptMask_callback ); + + memset( xInterruptDisableStatus, 0, sizeof( BaseType_t ) * configNUMBER_OF_CORES ); + vFakePortDisableInterrupts_StopIgnore(); + vFakePortDisableInterrupts_Stub( vFakePortDisableInterrupts_callback ); + vFakePortEnableInterrupts_StopIgnore(); + vFakePortEnableInterrupts_Stub( vFakePortEnableInterrupts_callback ); +} + +/*! called after each testcase */ +void tearDown( void ) +{ + commonTearDown(); +} + +/*! called at the beginning of the whole suite */ +void suiteSetUp() +{ +} + +/*! called at the end of the whole suite */ +int suiteTearDown( int numFailures ) +{ + return numFailures; +} + +/* ============================== Test Cases ============================== */ + +void test_granular_locks_smoke(void) +{ + uint32_t i; + + /* Create configNUMBER_OF_CORES tasks of equal priority */ + for( i = 0; i < configNUMBER_OF_CORES; i++ ){ + xTaskCreate( vSmpTestTask, "SMP Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandles[ i ] ); + } + + vTaskStartScheduler(); + + /* Verify all configNUMBER_OF_CORES tasks are in the running state */ + for( i = 0; i < configNUMBER_OF_CORES ; i++ ) + { + verifySmpTask( &xTaskHandles[ i ], eRunning, i ); + } +} diff --git a/FreeRTOS/Test/CMock/smp/granular_lock/portmacro.h b/FreeRTOS/Test/CMock/smp/granular_lock/portmacro.h new file mode 100644 index 00000000000..10db0b8676f --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock/portmacro.h @@ -0,0 +1,209 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* + * Changes from V3.2.3 + * + + Modified portENTER_SWITCHING_ISR() to allow use with GCC V4.0.1. + + + + Changes from V3.2.4 + + + + Removed the use of the %0 parameter within the assembler macros and + + replaced them with hard coded registers. This will ensure the + + assembler does not select the link register as the temp register as + + was occasionally happening previously. + + + + The assembler statements are now included in a single asm block rather + + than each line having its own asm block. + + + + Changes from V4.5.0 + + + + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros + + and replaced them with portYield_FROM_ISR() macro. Application code + + should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT() + + macros as per the V4.5.1 demo code. + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +#include + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL +#endif +#define portPOINTER_SIZE_TYPE uint64_t +/*-----------------------------------------------------------*/ + +/* Requires definition of UBaseType_t */ +#include "fake_port.h" +#include + +/* Hardware specifics. */ +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +#define portNOP() __asm volatile ( "NOP" ) + +/* + * These define the timer to use for generating the tick interrupt. + * They are put in this file so they can be shared between "port.c" + * and "portisr.c". + */ +#define portTIMER_REG_BASE_PTR +#define portTIMER_CLK_ENABLE_BIT +#define portTIMER_AIC_CHANNEL + +/*-----------------------------------------------------------*/ + +/* Task utilities. */ + +/* + * portRESTORE_CONTEXT, portRESTORE_CONTEXT, portENTER_SWITCHING_ISR + * and portEXIT_SWITCHING_ISR can only be called from ARM mode, but + * are included here for efficiency. An attempt to call one from + * THUMB mode code will result in a compile time error. + */ + +#define portRESTORE_CONTEXT() +/*-----------------------------------------------------------*/ + +#define portSAVE_CONTEXT() +#define portYIELD() vFakePortYield() +#define portYIELD_WITHIN_API() vFakePortYieldWithinAPI() +#define portYIELD_FROM_ISR() vFakePortYieldFromISR() + +/* Critical section handling. */ +#define portDISABLE_INTERRUPTS() vFakePortDisableInterrupts() +#define portENABLE_INTERRUPTS() vFakePortEnableInterrupts() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) \ + vFakePortClearInterruptMaskFromISR( x ) +#define portSET_INTERRUPT_MASK_FROM_ISR() \ + ulFakePortSetInterruptMaskFromISR() +#define portSET_INTERRUPT_MASK() ulFakePortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vFakePortClearInterruptMask( x ) +#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() \ + vFakePortAssertIfInterruptPriorityInvalid() +#define portENTER_CRITICAL() vFakePortEnterCriticalSection() +#define portEXIT_CRITICAL() vFakePortExitCriticalSection() + +#define portCHECK_IF_IN_ISR() vFakePortCheckIfInISR() +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) \ + vPortCurrentTaskDying( ( pvTaskToDelete ), ( pxPendYield ) ) +#define portSETUP_TCB( pxTCB ) portSetupTCB_CB( pxTCB ); +#define portASSERT_IF_IN_ISR() vFakePortAssertIfISR(); + +#define portGET_CORE_ID() vFakePortGetCoreID() +#define portYIELD_CORE( x ) vFakePortYieldCore( x ) + +#define portENTER_CRITICAL_FROM_ISR vFakePortEnterCriticalFromISR +#define portEXIT_CRITICAL_FROM_ISR vFakePortExitCriticalFromISR + +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +/* We need to define it here because CMock does not recognize the + * #if ( portUSING_MPU_WRAPPERS == 1 ) guard around xTaskGetMPUSettings + * and then complains about the missing xMPU_SETTINGS type in the + * generated mocks. */ +typedef struct MPU_SETTINGS +{ + uint32_t ulDummy; +} xMPU_SETTINGS; + +#define portUSING_GRANULAR_LOCKS ( 1 ) + +typedef struct xPortSpinlock +{ + volatile uint32_t uxLockCount; + volatile BaseType_t xOwnerCore; +} xPortSpinlock_t; + +#define portSPINLOCK_TYPE xPortSpinlock_t + +void vFakePortGetSpinlock( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock ); +#define portGET_SPINLOCK vFakePortGetSpinlock + +void vFakePortReleaseSpinlock( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock ); +#define portRELEASE_SPINLOCK vFakePortReleaseSpinlock + +void vFakePortInitSpinlock( portSPINLOCK_TYPE *pxSpinlock ); +#define portINIT_SPINLOCK vFakePortInitSpinlock +#define portINIT_SPINLOCK_STATIC { 0 } + +#define portENTER_CRITICAL_DATA_GROUP vFakePortEnterCriticalDataGroup +#define portEXIT_CRITICAL_DATA_GROUP vFakePortExitCriticalDataGroup +void vFakePortEnterCriticalDataGroup( portSPINLOCK_TYPE *pxTaskSpinLock, portSPINLOCK_TYPE *pxISRSpinLock ); +void vFakePortExitCriticalDataGroup( portSPINLOCK_TYPE *pxTaskSpinLock, portSPINLOCK_TYPE *pxISRSpinLock ); + +extern uint32_t xPortCriticalNestingCount[ configNUMBER_OF_CORES ]; +#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) xPortCriticalNestingCount[ ( xCoreID ) ] +#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) do{ xPortCriticalNestingCount[ ( xCoreID ) ] = ( x ); } while( 0 ) +#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) do{ xPortCriticalNestingCount[ ( xCoreID ) ]++; } while( 0 ) +#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) do{ xPortCriticalNestingCount[ ( xCoreID ) ]--; } while( 0 ) + + +/*-----------------------------------------------------------*/ + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ +#endif /* PORTMACRO_H */ diff --git a/FreeRTOS/Test/CMock/smp/granular_lock_timer/FreeRTOSConfig.h b/FreeRTOS/Test/CMock/smp/granular_lock_timer/FreeRTOSConfig.h new file mode 100644 index 00000000000..92e610c36cc --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock_timer/FreeRTOSConfig.h @@ -0,0 +1,156 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + + + #ifndef FREERTOS_CONFIG_H + #define FREERTOS_CONFIG_H + + #include "fake_assert.h" + + /*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See + * https://www.FreeRTOS.org/a00110.html + *----------------------------------------------------------*/ + + /* SMP test specific configuration */ + #define configRUN_MULTIPLE_PRIORITIES 1 + #define configNUMBER_OF_CORES 16 + #define configUSE_CORE_AFFINITY 0 + #define configUSE_TIME_SLICING 0 + #define configUSE_TASK_PREEMPTION_DISABLE 1 + #define configTICK_CORE 0 + + /* OS Configuration */ + #define configUSE_PREEMPTION 1 + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 + #define configUSE_IDLE_HOOK 0 + #define configUSE_TICK_HOOK 0 + #define configUSE_DAEMON_TASK_STARTUP_HOOK 1 + #define configTICK_RATE_HZ ( 1000 ) + #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 70 ) + #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 52 * 1024 ) ) + #define configMAX_TASK_NAME_LEN ( 12 ) + #define configUSE_TRACE_FACILITY 1 + #define configUSE_16_BIT_TICKS 0 + #define configIDLE_SHOULD_YIELD 1 + #define configUSE_MUTEXES 1 + #define configCHECK_FOR_STACK_OVERFLOW 0 + #define configUSE_RECURSIVE_MUTEXES 1 + #define configQUEUE_REGISTRY_SIZE 20 + #define configUSE_MALLOC_FAILED_HOOK 1 + #define configUSE_APPLICATION_TASK_TAG 1 + #define configUSE_COUNTING_SEMAPHORES 1 + #define configUSE_ALTERNATIVE_API 0 + #define configUSE_QUEUE_SETS 1 + #define configUSE_TASK_NOTIFICATIONS 1 + #define configTASK_NOTIFICATION_ARRAY_ENTRIES 5 + #define configSUPPORT_STATIC_ALLOCATION 0 + #define configINITIAL_TICK_COUNT ( ( TickType_t ) 0 ) + #define configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN 1 + #define portREMOVE_STATIC_QUALIFIER 1 + #define portCRITICAL_NESTING_IN_TCB 0 + #define portSTACK_GROWTH ( 1 ) + #define configUSE_PASSIVE_IDLE_HOOK 0 + #define configUSE_TICKLESS_IDLE 1 + + /* Software timer related configuration options. */ + #define configUSE_TIMERS 1 + #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) + #define configTIMER_QUEUE_LENGTH 20 + #define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + + #define configMAX_PRIORITIES ( 7 ) + + /* Run time stats gathering configuration options. */ + unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ + void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */ + #define configGENERATE_RUN_TIME_STATS 0 + #define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() + #define portUSING_MPU_WRAPPERS 0 + #define portHAS_STACK_OVERFLOW_CHECKING 0 + #define configENABLE_MPU 0 + + /* Co-routine related configuration options. */ + #define configUSE_CO_ROUTINES 0 + #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + + /* This demo makes use of one or more example stats formatting functions. These + * format the raw data provided by the uxTaskGetSystemState() function in to human + * readable ASCII form. See the notes in the implementation of vTaskList() within + * FreeRTOS/Source/tasks.c for limitations. */ + #define configUSE_STATS_FORMATTING_FUNCTIONS 1 + + /* Set the following definitions to 1 to include the API function, or zero + * to exclude the API function. In most cases the linker will remove unused + * functions anyway. */ + #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_xTaskGetCurrentTaskHandle 1 + #define INCLUDE_xTaskGetHandle 1 + #define INCLUDE_eTaskGetState 1 + #define INCLUDE_xSemaphoreGetMutexHolder 1 + #define INCLUDE_xTimerPendFunctionCall 1 + #define INCLUDE_xTaskAbortDelay 1 + #define INCLUDE_xTaskGetCurrentTaskHandle 1 + + /* It is a good idea to define configASSERT() while developing. configASSERT() + * uses the same semantics as the standard C assert() macro. */ + #define configASSERT( x ) \ + do \ + { \ + if( x ) \ + { \ + vFakeAssert( true, __FILE__, __LINE__ ); \ + } \ + else \ + { \ + vFakeAssert( false, __FILE__, __LINE__ ); \ + } \ + } while( 0 ) + + #define configINCLUDE_MESSAGE_BUFFER_AMP_DEMO 0 + #if ( configINCLUDE_MESSAGE_BUFFER_AMP_DEMO == 1 ) + extern void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ); + #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) + #endif /* configINCLUDE_MESSAGE_BUFFER_AMP_DEMO */ + + #endif /* FREERTOS_CONFIG_H */ + \ No newline at end of file diff --git a/FreeRTOS/Test/CMock/smp/granular_lock_timer/Makefile b/FreeRTOS/Test/CMock/smp/granular_lock_timer/Makefile new file mode 100644 index 00000000000..ceb2b9213bb --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock_timer/Makefile @@ -0,0 +1,48 @@ +# indent with spaces +.RECIPEPREFIX := $(.RECIPEPREFIX) $(.RECIPEPREFIX) + +# Do not move this line below the include +MAKEFILE_ABSPATH := $(abspath $(lastword $(MAKEFILE_LIST))) +include ../../makefile.in + +# PROJECT_SRC lists the .c files under test +PROJECT_SRC := timers.c + +# PROJECT_DEPS_SRC list the .c file that are dependencies of PROJECT_SRC files +# Files in PROJECT_DEPS_SRC are excluded from coverage measurements +PROJECT_DEPS_SRC := list.c tasks.c queue.c + +# PROJECT_HEADER_DEPS: headers that should be excluded from coverage measurements. +PROJECT_HEADER_DEPS := FreeRTOS.h + +# SUITE_UT_SRC: .c files that contain test cases (must end in _utest.c) +SUITE_UT_SRC := granular_lock_timers_utest.c + +# SUITE_SUPPORT_SRC: .c files used for testing that do not contain test cases. +# Paths are relative to PROJECT_DIR +SUITE_SUPPORT_SRC := smp_utest_common.c + +# List the headers used by PROJECT_SRC that you would like to mock +MOCK_FILES_FP += $(KERNEL_DIR)/include/timers.h +MOCK_FILES_FP += $(UT_ROOT_DIR)/config/fake_assert.h +MOCK_FILES_FP += $(UT_ROOT_DIR)/config/fake_port.h +MOCK_FILES_FP += $(UT_ROOT_DIR)//smp/granular_lock/portmacro.h + +# List any addiitonal flags needed by the preprocessor +CPPFLAGS += + +# List any addiitonal flags needed by the compiler +CFLAGS += + +# Try not to edit beyond this line unless necessary. + +# Project is determined based on path: $(UT_ROOT_DIR)/$(PROJECT) +PROJECT := $(lastword $(subst /, ,$(dir $(abspath $(MAKEFILE_ABSPATH)/../)))) +SUITE := $(lastword $(subst /, ,$(dir $(MAKEFILE_ABSPATH)))) + +# Make variables available to included makefile +export + +include ../../testdir.mk + + diff --git a/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock.yml b/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock.yml new file mode 100644 index 00000000000..e149b08f25f --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock.yml @@ -0,0 +1,32 @@ +:cmock: + :mock_prefix: mock_ + :when_no_prototypes: :warn + :when_ptr: :compare_ptr + :treat_externs: :include + :enforce_strict_ordering: TRUE + :plugins: + - :ignore + - :ignore_arg + - :expect_any_args + - :callback + - :return_thru_ptr + :callback_include_count: true # include a count arg when calling the callback + :callback_after_arg_check: false # check arguments before calling the callback + :treat_as: + uint8: HEX8 + uint16: HEX16 + uint32: UINT32 + int8: INT8 + bool: UINT8 + :includes: # This will add these includes to each mock. + - + - "FreeRTOS.h" + :treat_externs: :exclude # Now the extern-ed functions will be mocked. + :weak: __attribute__((weak)) + :verbosity: 3 + :attributes: + - PRIVILEGED_FUNCTION + :strippables: + - PRIVILEGED_FUNCTION + - portDONT_DISCARD + :treat_externs: :include diff --git a/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock_timers_utest.c b/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock_timers_utest.c new file mode 100644 index 00000000000..0327bbb32b7 --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock_timer/granular_lock_timers_utest.c @@ -0,0 +1,282 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ +/*! @file granular_lock_timers_utest.c */ + +/* C runtime includes. */ +#include +#include +#include +#include + +/* Task includes */ +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" +#include "event_groups.h" +#include "queue.h" +#include "semphr.h" + +/* Test includes. */ +#include "unity.h" +#include "unity_memory.h" +#include "../global_vars.h" +#include "../smp_utest_common.h" + +/* Mock includes. */ +#include "mock_fake_assert.h" +#include "mock_fake_port.h" +#include "mock_portmacro.h" + +/* =========================== EXTERN VARIABLES =========================== */ +extern portSPINLOCK_TYPE xTaskSpinlock; +extern portSPINLOCK_TYPE xISRSpinlock; + +/* =========================== GLOBAL VARIABLES =========================== */ + +static TaskHandle_t xTaskHandles[ configNUMBER_OF_CORES ] = { NULL }; +uint32_t xPortCriticalNestingCount[ configNUMBER_OF_CORES ] = { 0U }; + +static BaseType_t xCoreYields[ configNUMBER_OF_CORES ] = { 0 }; + +static UBaseType_t xInterruptMaskCount[ configNUMBER_OF_CORES ] = { 0U }; +static BaseType_t xInterruptDisableStatus[ configNUMBER_OF_CORES ] = { 0U }; + +/* ============================ Callback Functions ============================ */ +static void vFakePortInitSpinlock_callback( portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + + pxSpinlock->uxLockCount = 0; + pxSpinlock->xOwnerCore = -1; +} + +static void vYieldCores( void ) +{ + BaseType_t i; + BaseType_t xPreviousCoreId = portGET_CORE_ID(); + + if( ( xTaskSpinlock.uxLockCount == 0U ) && ( xISRSpinlock.uxLockCount == 0U ) ) + { + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + if( ( xCoreYields[ i ] == pdTRUE ) && + ( xInterruptMaskCount[ i ] == 0 ) && + ( xInterruptDisableStatus[ i ] == pdFALSE ) ) + { + vSetCurrentCore( i ); + xCoreYields[ i ] = pdFALSE; + vTaskSwitchContext( i ); + } + } + + vSetCurrentCore( xPreviousCoreId ); + } +} + +static void vFakePortReleaseSpinlock_callback( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + TEST_ASSERT_NOT_EQUAL( -1, pxSpinlock->xOwnerCore ); + TEST_ASSERT_NOT_EQUAL( 0, pxSpinlock->uxLockCount ); + TEST_ASSERT_EQUAL( xCoreID, pxSpinlock->xOwnerCore ); + + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount - 1U; + if( pxSpinlock->uxLockCount == 0U ) + { + pxSpinlock->xOwnerCore = -1; + } + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static void vFakePortGetSpinlock_callback( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock, int cmock_num_calls ) +{ + TEST_ASSERT_NOT_EQUAL( NULL, pxSpinlock ); + + if( pxSpinlock->uxLockCount == 0 ) + { + // TEST_ASSERT_EQUAL( -1, pxSpinlock->xOwnerCore ); + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount + 1U; + pxSpinlock->xOwnerCore = xCoreID; + } + else + { + TEST_ASSERT_EQUAL( xCoreID, pxSpinlock->xOwnerCore ); + pxSpinlock->uxLockCount = pxSpinlock->uxLockCount + 1U; + } +} + +static void vFakePortYieldCore_callback( int xCoreID, + int cmock_num_calls ) +{ + BaseType_t xCoreInCritical = pdFALSE; + BaseType_t xPreviousCoreId; + + /* Check if the lock is acquired by any core. */ + if( ( xTaskSpinlock.uxLockCount != 0U ) || ( xISRSpinlock.uxLockCount != 0U ) ) + { + xCoreInCritical = pdTRUE; + } + + if( xCoreInCritical == pdTRUE ) + { + /* If a task is in the critical section, pend the core yield until the + * spinlock is released. */ + xCoreYields[ xCoreID ] = pdTRUE; + } + else + { + /* No task is in the critical section. We can yield this core. */ + xPreviousCoreId = portGET_CORE_ID(); + vSetCurrentCore( xCoreID ); + vTaskSwitchContext( xCoreID ); + vSetCurrentCore( xPreviousCoreId ); + } +} + +static UBaseType_t ulFakePortSetInterruptMaskFromISR_callback( int cmock_num_calls ) +{ + ( void )cmock_num_calls; + xInterruptMaskCount[ portGET_CORE_ID() ]++; + return xInterruptMaskCount[ portGET_CORE_ID() ]; +} + +static void vFakePortClearInterruptMaskFromISR_callback( UBaseType_t uxNewMaskValue, int cmock_num_calls ) +{ + ( void )uxNewMaskValue; + ( void )cmock_num_calls; + TEST_ASSERT_EQUAL( uxNewMaskValue, xInterruptMaskCount[ portGET_CORE_ID() ] ); + TEST_ASSERT_NOT_EQUAL( 0, xInterruptMaskCount[ portGET_CORE_ID() ] ); + xInterruptMaskCount[ portGET_CORE_ID() ]--; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static UBaseType_t ulFakePortSetInterruptMask_callback( int cmock_num_calls ) +{ + ( void )cmock_num_calls; + xInterruptMaskCount[ portGET_CORE_ID() ]++; + return xInterruptMaskCount[ portGET_CORE_ID() ]; +} + +static void vFakePortClearInterruptMask_callback( UBaseType_t uxNewMaskValue, int cmock_num_calls ) +{ + ( void )uxNewMaskValue; + ( void )cmock_num_calls; + TEST_ASSERT_EQUAL( uxNewMaskValue, xInterruptMaskCount[ portGET_CORE_ID() ] ); + TEST_ASSERT_NOT_EQUAL( 0, xInterruptMaskCount[ portGET_CORE_ID() ] ); + xInterruptMaskCount[ portGET_CORE_ID() ]--; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +static uint32_t vFakePortDisableInterrupts_callback( int cmock_num_calls ) +{ + xInterruptDisableStatus[ portGET_CORE_ID() ] = pdTRUE; + return 0; +} + +static void vFakePortEnableInterrupts_callback( int cmock_num_calls ) +{ + xInterruptDisableStatus[ portGET_CORE_ID() ] = pdFALSE; + + /* Check if and pending core yield. */ + vYieldCores(); +} + +/* ============================ Unity Fixtures ============================ */ + +/*! called before each testcase */ +void setUp( void ) +{ + /* Use the common setup for the testing. */ + commonSetUp(); + + /* Specify the granular lock specific implementation. */ + vFakePortInitSpinlock_Stub( vFakePortInitSpinlock_callback ); + vFakePortReleaseSpinlock_Stub( vFakePortReleaseSpinlock_callback ); + vFakePortGetSpinlock_Stub( vFakePortGetSpinlock_callback ); + vFakePortYieldCore_Stub( vFakePortYieldCore_callback ); + + /* Interrupt masks. */ + memset( xInterruptMaskCount, 0, sizeof( UBaseType_t ) * configNUMBER_OF_CORES ); + ulFakePortSetInterruptMaskFromISR_StopIgnore(); + ulFakePortSetInterruptMaskFromISR_Stub( ulFakePortSetInterruptMaskFromISR_callback ); + vFakePortClearInterruptMaskFromISR_StopIgnore(); + vFakePortClearInterruptMaskFromISR_Stub( vFakePortClearInterruptMaskFromISR_callback ); + + ulFakePortSetInterruptMask_StopIgnore(); + ulFakePortSetInterruptMask_Stub( ulFakePortSetInterruptMask_callback ); + vFakePortClearInterruptMask_StopIgnore(); + vFakePortClearInterruptMask_Stub( vFakePortClearInterruptMask_callback ); + + memset( xInterruptDisableStatus, 0, sizeof( BaseType_t ) * configNUMBER_OF_CORES ); + vFakePortDisableInterrupts_StopIgnore(); + vFakePortDisableInterrupts_Stub( vFakePortDisableInterrupts_callback ); + vFakePortEnableInterrupts_StopIgnore(); + vFakePortEnableInterrupts_Stub( vFakePortEnableInterrupts_callback ); +} + +/*! called after each testcase */ +void tearDown( void ) +{ + commonTearDown(); +} + +/*! called at the beginning of the whole suite */ +void suiteSetUp() +{ +} + +/*! called at the end of the whole suite */ +int suiteTearDown( int numFailures ) +{ + return numFailures; +} + +/* ============================== Test Cases ============================== */ + +void test_granular_locks_timers_smoke(void) +{ + uint32_t i; + + /* Create configNUMBER_OF_CORES - 1 tasks of equal priority */ + for( i = 1; i < configNUMBER_OF_CORES; i++ ){ + xTaskCreate( vSmpTestTask, "SMP Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandles[ i ] ); + } + + vTaskStartScheduler(); + + /* Timer task at core 0 */ + + /* Verify all configNUMBER_OF_CORES tasks are in the running state */ + for( i = 1; i < configNUMBER_OF_CORES ; i++ ) + { + verifySmpTask( &xTaskHandles[ i ], eRunning, i ); + } +} diff --git a/FreeRTOS/Test/CMock/smp/granular_lock_timer/portmacro.h b/FreeRTOS/Test/CMock/smp/granular_lock_timer/portmacro.h new file mode 100644 index 00000000000..10db0b8676f --- /dev/null +++ b/FreeRTOS/Test/CMock/smp/granular_lock_timer/portmacro.h @@ -0,0 +1,209 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* + * Changes from V3.2.3 + * + + Modified portENTER_SWITCHING_ISR() to allow use with GCC V4.0.1. + + + + Changes from V3.2.4 + + + + Removed the use of the %0 parameter within the assembler macros and + + replaced them with hard coded registers. This will ensure the + + assembler does not select the link register as the temp register as + + was occasionally happening previously. + + + + The assembler statements are now included in a single asm block rather + + than each line having its own asm block. + + + + Changes from V4.5.0 + + + + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros + + and replaced them with portYield_FROM_ISR() macro. Application code + + should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT() + + macros as per the V4.5.1 demo code. + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +#include + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL +#endif +#define portPOINTER_SIZE_TYPE uint64_t +/*-----------------------------------------------------------*/ + +/* Requires definition of UBaseType_t */ +#include "fake_port.h" +#include + +/* Hardware specifics. */ +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +#define portNOP() __asm volatile ( "NOP" ) + +/* + * These define the timer to use for generating the tick interrupt. + * They are put in this file so they can be shared between "port.c" + * and "portisr.c". + */ +#define portTIMER_REG_BASE_PTR +#define portTIMER_CLK_ENABLE_BIT +#define portTIMER_AIC_CHANNEL + +/*-----------------------------------------------------------*/ + +/* Task utilities. */ + +/* + * portRESTORE_CONTEXT, portRESTORE_CONTEXT, portENTER_SWITCHING_ISR + * and portEXIT_SWITCHING_ISR can only be called from ARM mode, but + * are included here for efficiency. An attempt to call one from + * THUMB mode code will result in a compile time error. + */ + +#define portRESTORE_CONTEXT() +/*-----------------------------------------------------------*/ + +#define portSAVE_CONTEXT() +#define portYIELD() vFakePortYield() +#define portYIELD_WITHIN_API() vFakePortYieldWithinAPI() +#define portYIELD_FROM_ISR() vFakePortYieldFromISR() + +/* Critical section handling. */ +#define portDISABLE_INTERRUPTS() vFakePortDisableInterrupts() +#define portENABLE_INTERRUPTS() vFakePortEnableInterrupts() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) \ + vFakePortClearInterruptMaskFromISR( x ) +#define portSET_INTERRUPT_MASK_FROM_ISR() \ + ulFakePortSetInterruptMaskFromISR() +#define portSET_INTERRUPT_MASK() ulFakePortSetInterruptMask() +#define portCLEAR_INTERRUPT_MASK( x ) vFakePortClearInterruptMask( x ) +#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() \ + vFakePortAssertIfInterruptPriorityInvalid() +#define portENTER_CRITICAL() vFakePortEnterCriticalSection() +#define portEXIT_CRITICAL() vFakePortExitCriticalSection() + +#define portCHECK_IF_IN_ISR() vFakePortCheckIfInISR() +#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) \ + vPortCurrentTaskDying( ( pvTaskToDelete ), ( pxPendYield ) ) +#define portSETUP_TCB( pxTCB ) portSetupTCB_CB( pxTCB ); +#define portASSERT_IF_IN_ISR() vFakePortAssertIfISR(); + +#define portGET_CORE_ID() vFakePortGetCoreID() +#define portYIELD_CORE( x ) vFakePortYieldCore( x ) + +#define portENTER_CRITICAL_FROM_ISR vFakePortEnterCriticalFromISR +#define portEXIT_CRITICAL_FROM_ISR vFakePortExitCriticalFromISR + +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +/* We need to define it here because CMock does not recognize the + * #if ( portUSING_MPU_WRAPPERS == 1 ) guard around xTaskGetMPUSettings + * and then complains about the missing xMPU_SETTINGS type in the + * generated mocks. */ +typedef struct MPU_SETTINGS +{ + uint32_t ulDummy; +} xMPU_SETTINGS; + +#define portUSING_GRANULAR_LOCKS ( 1 ) + +typedef struct xPortSpinlock +{ + volatile uint32_t uxLockCount; + volatile BaseType_t xOwnerCore; +} xPortSpinlock_t; + +#define portSPINLOCK_TYPE xPortSpinlock_t + +void vFakePortGetSpinlock( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock ); +#define portGET_SPINLOCK vFakePortGetSpinlock + +void vFakePortReleaseSpinlock( BaseType_t xCoreID, portSPINLOCK_TYPE *pxSpinlock ); +#define portRELEASE_SPINLOCK vFakePortReleaseSpinlock + +void vFakePortInitSpinlock( portSPINLOCK_TYPE *pxSpinlock ); +#define portINIT_SPINLOCK vFakePortInitSpinlock +#define portINIT_SPINLOCK_STATIC { 0 } + +#define portENTER_CRITICAL_DATA_GROUP vFakePortEnterCriticalDataGroup +#define portEXIT_CRITICAL_DATA_GROUP vFakePortExitCriticalDataGroup +void vFakePortEnterCriticalDataGroup( portSPINLOCK_TYPE *pxTaskSpinLock, portSPINLOCK_TYPE *pxISRSpinLock ); +void vFakePortExitCriticalDataGroup( portSPINLOCK_TYPE *pxTaskSpinLock, portSPINLOCK_TYPE *pxISRSpinLock ); + +extern uint32_t xPortCriticalNestingCount[ configNUMBER_OF_CORES ]; +#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) xPortCriticalNestingCount[ ( xCoreID ) ] +#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) do{ xPortCriticalNestingCount[ ( xCoreID ) ] = ( x ); } while( 0 ) +#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) do{ xPortCriticalNestingCount[ ( xCoreID ) ]++; } while( 0 ) +#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) do{ xPortCriticalNestingCount[ ( xCoreID ) ]--; } while( 0 ) + + +/*-----------------------------------------------------------*/ + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ +#endif /* PORTMACRO_H */ diff --git a/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice/covg_multiple_priorities_no_timeslice_utest.c b/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice/covg_multiple_priorities_no_timeslice_utest.c index 2863a381a82..57351c4e7ac 100644 --- a/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice/covg_multiple_priorities_no_timeslice_utest.c +++ b/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice/covg_multiple_priorities_no_timeslice_utest.c @@ -399,6 +399,7 @@ void test_coverage_vTaskPreemptionEnable_task_running( void ) /* Setup variables. */ xTaskTCB.xPreemptionDisable = pdTRUE; xTaskTCB.xTaskRunState = 0; + xYieldPendings[ 0 ] = pdTRUE; xSchedulerRunning = pdTRUE; @@ -2060,6 +2061,11 @@ void test_coverage_vTaskExitCritical_task_enter_critical_mt_1( void ) pxCurrentTCBs[ 0 ] = &xTaskTCB; xSchedulerRunning = pdTRUE; + portGET_TASK_LOCK(0); + portGET_TASK_LOCK(0); + portGET_ISR_LOCK(0); + portGET_ISR_LOCK(0); + /* Clear callback in commonSetUp. */ vFakePortGetCoreID_StubWithCallback( NULL ); @@ -2098,6 +2104,9 @@ void test_coverage_vTaskExitCritical_task_not_in_critical( void ) pxCurrentTCBs[ 0 ] = &xTaskTCB; xSchedulerRunning = pdTRUE; + portGET_TASK_LOCK(0); + portGET_ISR_LOCK(0); + /* Clear callback in commonSetUp. */ vFakePortGetCoreID_StubWithCallback( NULL ); diff --git a/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice_mock/covg_multiple_priorities_no_timeslice_mock_utest.c b/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice_mock/covg_multiple_priorities_no_timeslice_mock_utest.c index c85c39add2b..341335c8eb4 100644 --- a/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice_mock/covg_multiple_priorities_no_timeslice_mock_utest.c +++ b/FreeRTOS/Test/CMock/smp/multiple_priorities_no_timeslice_mock/covg_multiple_priorities_no_timeslice_mock_utest.c @@ -422,7 +422,9 @@ void test_coverage_prvYieldCore_core_id_ne_current_coreid( void ) TaskHandle_t xTaskHandle; task.xTaskRunState = 1; /* running on core 1 */ + task.xPreemptionDisable = 1; task2.xTaskRunState = -2; /* running on core 2 taskTASK_YIELDING */ + xYieldPendings[ 1 ] = pdTRUE; xTaskHandle = &task; pxCurrentTCBs[ 0 ] = &task; pxCurrentTCBs[ 1 ] = &task; @@ -465,6 +467,7 @@ void test_coverage_prvYieldCore_runstate_eq_yielding( void ) TaskHandle_t xTaskHandle; task.xTaskRunState = 1; /* running on core 1 */ + task.xPreemptionDisable = 1; task2.xTaskRunState = -2; /* running on core 2 taskTASK_YIELDING */ xTaskHandle = &task; pxCurrentTCBs[ 0 ] = &task;