diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ca9292..819df8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ endif() ############################################################################### project(threadx_demo C ASM) option(NX_DEBUG "compile netxduo debug output in" OFF) +option(ENABLE_THREADX_REGRESSION "Build ThreadX regression test executables" OFF) set(TARGET_MEM "ram" CACHE STRING "memory map to use") set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") @@ -88,6 +89,10 @@ function(setup_target TARGET) ) endfunction() +if(ENABLE_THREADX_REGRESSION) + add_subdirectory(test) +endif() + setup_target(thread_demo LIBRARIES threadx SOURCES src/thread_demo/main.c) setup_target(tcp_demo LIBRARIES threadx netxduo SOURCES src/tcp_demo/main.c) setup_target(smp_demo LIBRARIES threadx_smp SOURCES src/thread_demo/main.c) diff --git a/port/threadx/inc/tx_port.h b/port/threadx/inc/tx_port.h index 1e57546..7ee7252 100644 --- a/port/threadx/inc/tx_port.h +++ b/port/threadx/inc/tx_port.h @@ -203,6 +203,109 @@ typedef unsigned short USHORT; #define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) #define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) +/* Define automated regression test extensions. These are required for the + ThreadX regression tests. */ + +typedef unsigned int TEST_FLAG; +extern TEST_FLAG threadx_byte_allocate_loop_test; +extern TEST_FLAG threadx_byte_release_loop_test; +extern TEST_FLAG threadx_mutex_suspension_put_test; +extern TEST_FLAG threadx_mutex_suspension_priority_test; +#ifndef TX_TIMER_PROCESS_IN_ISR +extern TEST_FLAG threadx_delete_timer_thread; +#endif + +extern void abort_and_resume_byte_allocating_thread(void); +extern void abort_all_threads_suspended_on_mutex(void); +extern void suspend_lowest_priority(void); +#ifndef TX_TIMER_PROCESS_IN_ISR +extern void delete_timer_thread(void); +#endif +extern TEST_FLAG test_stack_analyze_flag; +extern TEST_FLAG test_initialize_flag; +extern TEST_FLAG test_forced_mutex_timeout; + +#ifdef TX_REGRESSION_TEST + +/* Define extension macros for automated coverage tests. */ + +#define TX_BYTE_ALLOCATE_EXTENSION \ + if (threadx_byte_allocate_loop_test == ((TEST_FLAG)1)) \ + { \ + pool_ptr->tx_byte_pool_owner = TX_NULL; \ + threadx_byte_allocate_loop_test = ((TEST_FLAG)0); \ + } + +#define TX_BYTE_RELEASE_EXTENSION \ + if (threadx_byte_release_loop_test == ((TEST_FLAG)1)) \ + { \ + threadx_byte_release_loop_test = ((TEST_FLAG)0); \ + abort_and_resume_byte_allocating_thread(); \ + } + +#define TX_MUTEX_PUT_EXTENSION_1 \ + if (threadx_mutex_suspension_put_test == ((TEST_FLAG)1)) \ + { \ + threadx_mutex_suspension_put_test = ((TEST_FLAG)0); \ + abort_all_threads_suspended_on_mutex(); \ + } + +#define TX_MUTEX_PUT_EXTENSION_2 \ + if (test_forced_mutex_timeout == ((TEST_FLAG)1)) \ + { \ + test_forced_mutex_timeout = ((TEST_FLAG)0); \ + _tx_thread_wait_abort(mutex_ptr->tx_mutex_suspension_list); \ + } + +#define TX_MUTEX_PRIORITY_CHANGE_EXTENSION \ + if (threadx_mutex_suspension_priority_test == ((TEST_FLAG)1)) \ + { \ + threadx_mutex_suspension_priority_test = ((TEST_FLAG)0); \ + suspend_lowest_priority(); \ + } + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define TX_TIMER_INITIALIZE_EXTENSION(a) \ + if (threadx_delete_timer_thread == ((TEST_FLAG)1)) \ + { \ + threadx_delete_timer_thread = ((TEST_FLAG)0); \ + delete_timer_thread(); \ + (a) = ((UINT)1); \ + } + +#endif + +#define TX_THREAD_STACK_ANALYZE_EXTENSION \ + if (test_stack_analyze_flag == ((TEST_FLAG)1)) \ + { \ + thread_ptr->tx_thread_id = ((TEST_FLAG)0); \ + test_stack_analyze_flag = ((TEST_FLAG)0); \ + } \ + else if (test_stack_analyze_flag == ((TEST_FLAG)2)) \ + { \ + stack_ptr = thread_ptr->tx_thread_stack_start; \ + test_stack_analyze_flag = ((TEST_FLAG)0); \ + } \ + else if (test_stack_analyze_flag == ((TEST_FLAG)3)) \ + { \ + *stack_ptr = TX_STACK_FILL; \ + test_stack_analyze_flag = ((TEST_FLAG)0); \ + } \ + else \ + { \ + test_stack_analyze_flag = ((TEST_FLAG)0); \ + } + +#define TX_INITIALIZE_KERNEL_ENTER_EXTENSION \ + if (test_initialize_flag == ((TEST_FLAG)1)) \ + { \ + test_initialize_flag = ((TEST_FLAG)0); \ + return; \ + } + +#endif + /* Define the ThreadX object creation extensions for the remaining objects. */ #define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..f456146 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.21) + +add_subdirectory(threadx) diff --git a/test/threadx/CMakeLists.txt b/test/threadx/CMakeLists.txt new file mode 100644 index 0000000..8352b07 --- /dev/null +++ b/test/threadx/CMakeLists.txt @@ -0,0 +1,65 @@ +cmake_minimum_required(VERSION 3.21) + +enable_testing() + +set(TX_REGRESSION_DIR + ${CMAKE_SOURCE_DIR}/third-party/threadx/test/tx/regression +) +set(TX_CMAKE_DIR + ${CMAKE_SOURCE_DIR}/third-party/threadx/test/tx/cmake +) + +set(TX_REGRESSION_CASES + ${TX_REGRESSION_DIR}/threadx_block_memory_basic_test.c + ${TX_REGRESSION_DIR}/threadx_byte_memory_basic_test.c + ${TX_REGRESSION_DIR}/threadx_event_flag_basic_test.c + ${TX_REGRESSION_DIR}/threadx_mutex_basic_test.c + ${TX_REGRESSION_DIR}/threadx_queue_basic_one_word_test.c + ${TX_REGRESSION_DIR}/threadx_semaphore_basic_test.c + ${TX_REGRESSION_DIR}/threadx_thread_basic_execution_test.c + ${TX_REGRESSION_DIR}/threadx_timer_simple_test.c +) + +set(TX_REGRESSION_TARGETS) +set(TX_REGRESSION_OUTPUT_DIR ${CMAKE_BINARY_DIR}/test) +set(TX_REGRESSION_TARGET_MEM ram_dram) + +add_library( + threadx_regression_support STATIC + ${TX_REGRESSION_DIR}/testcontrol.c + ${TX_CMAKE_DIR}/samples/fake.c +) +target_link_libraries(threadx_regression_support PUBLIC threadx c) +target_compile_definitions( + threadx_regression_support + PUBLIC + CTEST + BATCH_TEST + TEST_STACK_SIZE_PRINTF=4096 +) +function(add_threadx_regression_test TEST_SOURCE) + get_filename_component(TEST_NAME ${TEST_SOURCE} NAME_WE) + + setup_target( + ${TEST_NAME} + OUTPUT_DIR ${TX_REGRESSION_OUTPUT_DIR} + TARGET_MEM ${TX_REGRESSION_TARGET_MEM} + LIBRARIES threadx_regression_support + SOURCES ${TEST_SOURCE} + ) + + list(APPEND TX_REGRESSION_TARGETS ${TEST_NAME}) + set(TX_REGRESSION_TARGETS ${TX_REGRESSION_TARGETS} PARENT_SCOPE) + + # The executable is embedded and not directly host-runnable. + # Add a real add_test() command here once a QEMU or board runner exists. +endfunction() + +foreach(test_case ${TX_REGRESSION_CASES}) + add_threadx_regression_test(${test_case}) +endforeach() + +add_custom_target( + threadx_regression_build + DEPENDS ${TX_REGRESSION_TARGETS} +)