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 BaseType_t prvIsFreeRTOSThread( void );
|
||||
static void prvDestroyThreadKey( void );
|
||||
static void prvFatalError( const char * pcCall,
|
||||
int iErrno ) __attribute__( ( __noreturn__ ) );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvThreadKeyDestructor( void * pvData )
|
||||
|
|
@ -139,7 +141,13 @@ static void prvThreadKeyDestructor( void * pvData )
|
|||
|
||||
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. */
|
||||
atexit( prvDestroyThreadKey );
|
||||
}
|
||||
|
|
@ -148,15 +156,26 @@ static void prvInitThreadKey( void )
|
|||
static void prvMarkAsFreeRTOSThread( void )
|
||||
{
|
||||
uint8_t * pucThreadData = NULL;
|
||||
int iRet;
|
||||
|
||||
( void ) pthread_once( &hThreadKeyOnce, prvInitThreadKey );
|
||||
|
||||
pucThreadData = malloc( 1 );
|
||||
configASSERT( pucThreadData != NULL );
|
||||
|
||||
if( pucThreadData == NULL )
|
||||
{
|
||||
prvFatalError( "malloc", ENOMEM );
|
||||
}
|
||||
|
||||
*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,
|
||||
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