mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-10-09 23:53:04 -04:00
Merge 476f045fcc into 8be86d4a24
This commit is contained in:
commit
2fe1ef80b4
6 changed files with 275 additions and 6 deletions
28
portable/ThirdParty/GCC/Posix/port.c
vendored
28
portable/ThirdParty/GCC/Posix/port.c
vendored
|
|
@ -129,6 +129,8 @@ static void prvInitThreadKey( void );
|
||||||
static void prvMarkAsFreeRTOSThread( void );
|
static void prvMarkAsFreeRTOSThread( void );
|
||||||
static BaseType_t prvIsFreeRTOSThread( void );
|
static BaseType_t prvIsFreeRTOSThread( void );
|
||||||
static void prvDestroyThreadKey( void );
|
static void prvDestroyThreadKey( void );
|
||||||
|
static void prvFatalError( const char * pcCall,
|
||||||
|
int iErrno ) __attribute__( ( __noreturn__ ) );
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvThreadKeyDestructor( void * pvData )
|
static void prvThreadKeyDestructor( void * pvData )
|
||||||
|
|
@ -139,7 +141,13 @@ static void prvThreadKeyDestructor( void * pvData )
|
||||||
|
|
||||||
static void prvInitThreadKey( void )
|
static void prvInitThreadKey( void )
|
||||||
{
|
{
|
||||||
pthread_key_create( &xThreadKey, prvThreadKeyDestructor );
|
int iRet = pthread_key_create( &xThreadKey, prvThreadKeyDestructor );
|
||||||
|
|
||||||
|
if( iRet != 0 )
|
||||||
|
{
|
||||||
|
prvFatalError( "pthread_key_create", iRet );
|
||||||
|
}
|
||||||
|
|
||||||
/* Destroy xThreadKey when the process exits. */
|
/* Destroy xThreadKey when the process exits. */
|
||||||
atexit( prvDestroyThreadKey );
|
atexit( prvDestroyThreadKey );
|
||||||
}
|
}
|
||||||
|
|
@ -148,15 +156,26 @@ static void prvInitThreadKey( void )
|
||||||
static void prvMarkAsFreeRTOSThread( void )
|
static void prvMarkAsFreeRTOSThread( void )
|
||||||
{
|
{
|
||||||
uint8_t * pucThreadData = NULL;
|
uint8_t * pucThreadData = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
( void ) pthread_once( &hThreadKeyOnce, prvInitThreadKey );
|
( void ) pthread_once( &hThreadKeyOnce, prvInitThreadKey );
|
||||||
|
|
||||||
pucThreadData = malloc( 1 );
|
pucThreadData = malloc( 1 );
|
||||||
configASSERT( pucThreadData != NULL );
|
|
||||||
|
if( pucThreadData == NULL )
|
||||||
|
{
|
||||||
|
prvFatalError( "malloc", ENOMEM );
|
||||||
|
}
|
||||||
|
|
||||||
*pucThreadData = 1;
|
*pucThreadData = 1;
|
||||||
|
|
||||||
pthread_setspecific( xThreadKey, pucThreadData );
|
iRet = pthread_setspecific( xThreadKey, pucThreadData );
|
||||||
|
|
||||||
|
if( iRet != 0 )
|
||||||
|
{
|
||||||
|
free( pucThreadData );
|
||||||
|
prvFatalError( "pthread_setspecific", iRet );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
@ -184,9 +203,6 @@ static void prvDestroyThreadKey( void )
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvFatalError( const char * pcCall,
|
|
||||||
int iErrno ) __attribute__( ( __noreturn__ ) );
|
|
||||||
|
|
||||||
void prvFatalError( const char * pcCall,
|
void prvFatalError( const char * pcCall,
|
||||||
int iErrno )
|
int iErrno )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
33
portable/ThirdParty/GCC/Posix/tests/CMakeLists.txt
vendored
Normal file
33
portable/ThirdParty/GCC/Posix/tests/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(posix_port_tests C)
|
||||||
|
enable_testing()
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
get_filename_component(KERNEL_ROOT "../../../../.." ABSOLUTE)
|
||||||
|
add_library(freertos_config INTERFACE)
|
||||||
|
target_include_directories(freertos_config INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
set(FREERTOS_PORT GCC_POSIX CACHE STRING "" FORCE)
|
||||||
|
set(FREERTOS_HEAP 4 CACHE STRING "" FORCE)
|
||||||
|
add_subdirectory("${KERNEL_ROOT}" kernel)
|
||||||
|
|
||||||
|
foreach(assert_enabled 0 1)
|
||||||
|
set(target thread_marker_${assert_enabled})
|
||||||
|
add_executable(${target} thread_marker.c)
|
||||||
|
target_include_directories(${target} PRIVATE . .. "${KERNEL_ROOT}/include")
|
||||||
|
target_compile_definitions(${target} PRIVATE TEST_ASSERT_ENABLED=${assert_enabled})
|
||||||
|
target_compile_options(${target} PRIVATE -Wall -Wextra -Werror -ffunction-sections -fdata-sections)
|
||||||
|
target_link_libraries(${target} PRIVATE Threads::Threads)
|
||||||
|
target_link_options(${target} PRIVATE -Wl,--gc-sections
|
||||||
|
-Wl,--wrap=pthread_key_create -Wl,--wrap=pthread_setspecific
|
||||||
|
-Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=abort)
|
||||||
|
foreach(scenario success key_create key_query allocation setspecific)
|
||||||
|
add_test(NAME ${target}_${scenario} COMMAND ${target} ${scenario})
|
||||||
|
set_tests_properties(${target}_${scenario} PROPERTIES TIMEOUT 10)
|
||||||
|
endforeach()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_executable(scheduler_smoke scheduler_smoke.c)
|
||||||
|
target_link_libraries(scheduler_smoke PRIVATE freertos_kernel)
|
||||||
|
target_compile_options(scheduler_smoke PRIVATE -Wall -Wextra -Werror)
|
||||||
|
add_test(NAME scheduler_smoke COMMAND scheduler_smoke)
|
||||||
|
set_tests_properties(scheduler_smoke PROPERTIES TIMEOUT 10)
|
||||||
28
portable/ThirdParty/GCC/Posix/tests/FreeRTOSConfig.h
vendored
Normal file
28
portable/ThirdParty/GCC/Posix/tests/FreeRTOSConfig.h
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
#ifndef FREERTOS_CONFIG_H
|
||||||
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define configUSE_PREEMPTION 1
|
||||||
|
#define configUSE_IDLE_HOOK 0
|
||||||
|
#define configUSE_TICK_HOOK 0
|
||||||
|
#define configTICK_RATE_HZ 100
|
||||||
|
#define configMAX_PRIORITIES 4
|
||||||
|
#define configMINIMAL_STACK_SIZE 4096
|
||||||
|
#define configTOTAL_HEAP_SIZE ( 256 * 1024 )
|
||||||
|
#define configMAX_TASK_NAME_LEN 16
|
||||||
|
#define configUSE_16_BIT_TICKS 0
|
||||||
|
#define configUSE_MUTEXES 1
|
||||||
|
#define configUSE_TIMERS 0
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define INCLUDE_vTaskDelay 1
|
||||||
|
#define INCLUDE_vTaskDelete 1
|
||||||
|
#define INCLUDE_xTaskGetCurrentTaskHandle 1
|
||||||
|
|
||||||
|
#if TEST_ASSERT_ENABLED
|
||||||
|
#define configASSERT( x ) do { if( !( x ) ) { abort(); } } while( 0 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef FREERTOS_CONFIG_H */
|
||||||
23
portable/ThirdParty/GCC/Posix/tests/README.md
vendored
Normal file
23
portable/ThirdParty/GCC/Posix/tests/README.md
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# POSIX thread-marker regression tests
|
||||||
|
|
||||||
|
Run on Linux with GCC, CMake, and a GNU-compatible linker:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -S portable/ThirdParty/GCC/Posix/tests -B build/posix-tests
|
||||||
|
cmake --build build/posix-tests
|
||||||
|
ctest --test-dir build/posix-tests --output-on-failure
|
||||||
|
```
|
||||||
|
|
||||||
|
The failure-injection executable includes the actual port implementation to
|
||||||
|
reach its private helpers. Linker wrappers inject key-creation, allocation, and
|
||||||
|
TLS-storage failures. Each failure must terminate via the fatal handler; failed
|
||||||
|
TLS storage must first free the allocated marker. Tests run with assertions
|
||||||
|
both enabled and disabled. The success case checks thread identity, isolation
|
||||||
|
from the calling thread, and automatic destructor cleanup after pthread exit.
|
||||||
|
The separate smoke test links the full kernel and runs a real scheduled task
|
||||||
|
through a tick delay and scheduler shutdown.
|
||||||
|
|
||||||
|
For sanitizer validation, configure another build directory with
|
||||||
|
`-DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"`.
|
||||||
|
These tests are specific to the POSIX simulator; they do not validate hardware
|
||||||
|
ports. The kernel's main CMock suite lives in the parent FreeRTOS repository.
|
||||||
24
portable/ThirdParty/GCC/Posix/tests/scheduler_smoke.c
vendored
Normal file
24
portable/ThirdParty/GCC/Posix/tests/scheduler_smoke.c
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
static volatile int iTaskRan;
|
||||||
|
|
||||||
|
static void prvTask( void * pvUnused )
|
||||||
|
{
|
||||||
|
( void ) pvUnused;
|
||||||
|
vTaskDelay( 2 );
|
||||||
|
iTaskRan = 1;
|
||||||
|
vTaskEndScheduler();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main( void )
|
||||||
|
{
|
||||||
|
if( xTaskCreate( prvTask, "smoke", configMINIMAL_STACK_SIZE, NULL, 1, NULL ) != pdPASS )
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskStartScheduler();
|
||||||
|
return iTaskRan ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
145
portable/ThirdParty/GCC/Posix/tests/thread_marker.c
vendored
Normal file
145
portable/ThirdParty/GCC/Posix/tests/thread_marker.c
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
/* Include the implementation to exercise its private TLS helpers unchanged.
|
||||||
|
* Unused scheduler sections are discarded by the linker. */
|
||||||
|
#include "../port.c"
|
||||||
|
|
||||||
|
static const char * pcScenario;
|
||||||
|
static void * pvMarker;
|
||||||
|
static int iAllocations;
|
||||||
|
static int iFrees;
|
||||||
|
static int iStores;
|
||||||
|
|
||||||
|
extern void * __real_malloc( size_t xSize );
|
||||||
|
extern void __real_free( void * pvPointer );
|
||||||
|
extern int __real_pthread_key_create( pthread_key_t * pxKey,
|
||||||
|
void ( * pxDestructor )( void * ) );
|
||||||
|
extern int __real_pthread_setspecific( pthread_key_t xKey,
|
||||||
|
const void * pvValue );
|
||||||
|
|
||||||
|
int __wrap_pthread_key_create( pthread_key_t * pxKey,
|
||||||
|
void ( * pxDestructor )( void * ) )
|
||||||
|
{
|
||||||
|
if( ( strcmp( pcScenario, "key_create" ) == 0 ) || ( strcmp( pcScenario, "key_query" ) == 0 ) )
|
||||||
|
{
|
||||||
|
return EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __real_pthread_key_create( pxKey, pxDestructor );
|
||||||
|
}
|
||||||
|
|
||||||
|
void * __wrap_malloc( size_t xSize )
|
||||||
|
{
|
||||||
|
if( xSize == 1 )
|
||||||
|
{
|
||||||
|
iAllocations++;
|
||||||
|
|
||||||
|
if( strcmp( pcScenario, "allocation" ) == 0 )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pvMarker = __real_malloc( xSize );
|
||||||
|
return pvMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __real_malloc( xSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_free( void * pvPointer )
|
||||||
|
{
|
||||||
|
if( ( pvPointer != NULL ) && ( pvPointer == pvMarker ) )
|
||||||
|
{
|
||||||
|
iFrees++;
|
||||||
|
}
|
||||||
|
|
||||||
|
__real_free( pvPointer );
|
||||||
|
}
|
||||||
|
|
||||||
|
int __wrap_pthread_setspecific( pthread_key_t xKey,
|
||||||
|
const void * pvValue )
|
||||||
|
{
|
||||||
|
iStores++;
|
||||||
|
|
||||||
|
if( strcmp( pcScenario, "setspecific" ) == 0 )
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __real_pthread_setspecific( xKey, pvValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_abort( void )
|
||||||
|
{
|
||||||
|
int iPassed = 0;
|
||||||
|
|
||||||
|
if( ( strcmp( pcScenario, "key_create" ) == 0 ) || ( strcmp( pcScenario, "key_query" ) == 0 ) )
|
||||||
|
{
|
||||||
|
iPassed = ( iAllocations == 0 ) && ( iStores == 0 );
|
||||||
|
}
|
||||||
|
else if( strcmp( pcScenario, "allocation" ) == 0 )
|
||||||
|
{
|
||||||
|
iPassed = ( iAllocations == 1 ) && ( iStores == 0 );
|
||||||
|
}
|
||||||
|
else if( strcmp( pcScenario, "setspecific" ) == 0 )
|
||||||
|
{
|
||||||
|
iPassed = ( iAllocations == 1 ) && ( iStores == 1 ) && ( iFrees == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
_Exit( iPassed ? EXIT_SUCCESS : EXIT_FAILURE );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void * prvMarkedThread( void * pvUnused )
|
||||||
|
{
|
||||||
|
( void ) pvUnused;
|
||||||
|
|
||||||
|
if( prvIsFreeRTOSThread() != pdFALSE )
|
||||||
|
{
|
||||||
|
return ( void * ) 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
prvMarkAsFreeRTOSThread();
|
||||||
|
return ( void * ) ( intptr_t ) ( prvIsFreeRTOSThread() != pdTRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
int main( int argc,
|
||||||
|
char ** argv )
|
||||||
|
{
|
||||||
|
pthread_t xThread;
|
||||||
|
void * pvResult;
|
||||||
|
|
||||||
|
if( argc != 2 )
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcScenario = argv[ 1 ];
|
||||||
|
|
||||||
|
if( strcmp( pcScenario, "success" ) == 0 )
|
||||||
|
{
|
||||||
|
if( pthread_create( &xThread, NULL, prvMarkedThread, NULL ) != 0 )
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pthread_join( xThread, &pvResult ) != 0 )
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( ( pvResult == NULL ) && ( iAllocations == 1 ) && ( iFrees == 1 ) &&
|
||||||
|
( prvIsFreeRTOSThread() == pdFALSE ) ) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( strcmp( pcScenario, "key_query" ) == 0 )
|
||||||
|
{
|
||||||
|
( void ) prvIsFreeRTOSThread();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prvMarkAsFreeRTOSThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( stderr, "Continued after injected %s failure\n", pcScenario );
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue