Added win64 ports of ThreadX and ThreadX SMP (#529)

Windows x64 port and regression suite

 This PR adds the Windows x64 (Win64) simulation port for both the standalone
 and SMP variants of ThreadX, along with the full CMake build and test
 infrastructure needed to run the regression suite on Windows.


 New ports

 Win64 standalone (ports/win64/vs_2022): self-contained Windows simulation
 port using Win32 threading primitives as virtual cores. Includes CMake
 integration, build/test scripts, and MSVC project files.

 Win64 SMP (ports/win64_smp/vs_2022): multi-core Windows simulation port.
 Supports up to 4 virtual cores backed by Windows host threads.


 Scheduler and timer improvements

 The initial port used coarse polling and synchronous SuspendThread/ResumeThread
 pairs throughout the scheduler hot path. Several rounds of optimization reduced
 the SMP regression suite runtime from ~150 s to ~78 s (-48%), with no
 regressions:

 - Replaced scheduler polling with an event-driven wake path; switched the
   simulated timer to one-shot rearming to eliminate catch-up ticks.
 - Skip SuspendThread when _tx_thread_preempt_disable != 0 (new suspension
   type 3) -- the primary optimization, yielding up to 7.9x speedup on
   preemption-heavy tests.
 - Skip SuspendThread when a thread is spinning on the Win32 critical section
   (suspension type 4), and fix a stale-TLS bug in
   _tx_win32_critical_section_obtain that could stamp mutex_access on the
   wrong virtual core.
 - Added a 2 ms scheduler event timeout (matching the Linux SMP port) to
   prevent stalls on any missed SetEvent.
 - Enabled high-resolution waitable timers (SetWaitableTimerEx) for accurate
   100 Hz tick cadence.
 - Increased TX_WIN32_CONTENTION_PAUSE_COUNT from 64 to 256 to reduce
   SwitchToThread overhead under heavy CS contention.


 Build and test infrastructure

 - Hardened the Windows build wrapper (scripts/build_tx.ps1): invoke Ninja
   directly for Ninja build trees, fix timeout detection, add a default build
   timeout, and limit fallback replay to real timeout cases.
 - Added -Clean support to Windows test scripts to remove stale CTest state
   before each run.
 - Skip Visual Studio DevShell re-entry when the active MSVC environment
   already matches the requested architecture.
 - Fixed scripts/build_tx.sh (Linux) regression source generation: replaced
   brittle exact-string insertion with line-based matching so the interrupt
   dispatcher hook is inserted reliably for both simulator ports.


 Test suite updates

 - Introduced test/tx/regression/threadx_test_port.h with portable macros
   (TX_TEST_POINTER_WORD, TX_TEST_STORE_POINTER) for storing pointers in test
   arrays on 64-bit targets where ULONG remains 32-bit.
 - Adjusted pool-capacity and pointer-storage patterns in regression tests to
   use ALIGN_TYPE-sized slots, making the suite correct on 64-bit hosts.
 - Restored stricter event flag, sleep, and timer expectations now that
   port-level fixes make prior Windows accommodations unnecessary.
 - Tightened SMP watchdog and clean-build timeout defaults.


 Version metadata

 Updated Win32, Win64, and Win64 SMP port version strings to 6.5.1.202602.

 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
 Co-authored-by: Codex (gpt 5.5) <codex@openai.com>
This commit is contained in:
Frédéric Desbiens
2026-05-26 17:17:40 -04:00
committed by GitHub
parent e031a3d506
commit 2c16114a45
108 changed files with 7614 additions and 395 deletions
+19 -6
View File
@@ -1,10 +1,5 @@
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
# Set up the project
project(threadx
LANGUAGES C ASM
)
if(NOT DEFINED THREADX_ARCH)
message(FATAL_ERROR "Error: THREADX_ARCH not defined")
endif()
@@ -12,6 +7,24 @@ if(NOT DEFINED THREADX_TOOLCHAIN)
message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined")
endif()
# The Windows simulation ports build cleanly without executable try-compiles.
if((THREADX_ARCH STREQUAL "win32") OR (THREADX_ARCH STREQUAL "win64"))
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
endif()
# Set up the project. The Windows simulation ports do not use assembly and
# avoiding ASM language enablement keeps MSVC configuration on the CLI path
# deterministic.
if((THREADX_ARCH STREQUAL "win32") OR (THREADX_ARCH STREQUAL "win64"))
project(threadx
LANGUAGES C
)
else()
project(threadx
LANGUAGES C ASM
)
endif()
option(THREADX_SMP "Build ThreadX SMP version" OFF)
if(THREADX_SMP)
@@ -95,4 +108,4 @@ set(CPACK_SOURCE_IGNORE_FILES
".*~$"
)
set(CPACK_VERBATIM_VARIABLES YES)
include(CPack)
include(CPack)
+3 -9
View File
@@ -1,15 +1,9 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_SYSTEM_PROCESSOR x86)
set(THREADX_ARCH "win32")
set(THREADX_TOOLCHAIN "vs_2019")
set(WIN32_FLAGS "")
set(CMAKE_C_FLAGS "${WIN32_FLAGS} " CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS "${WIN32_FLAGS} -fno-rtti -fno-exceptions" CACHE INTERNAL "cxx compiler flags")
set(CMAKE_ASM_FLAGS "${WIN32_FLAGS} -x assembler-with-cpp" CACHE INTERNAL "asm compiler flags")
set(CMAKE_EXE_LINKER_FLAGS "${WIN32_FLAGS} ${LD_FLAGS}" CACHE INTERNAL "exe link flags")
# this makes the test compiles use static library option so that we don't need to pre-set linker flags and scripts
# This makes the test compiles use the static library option so that the
# compiler environment can be discovered from the active MSVC shell.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+9
View File
@@ -0,0 +1,9 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR AMD64)
set(THREADX_ARCH "win64")
set(THREADX_TOOLCHAIN "vs_2022")
# This makes the test compiles use the static library option so that the
# compiler environment can be discovered from the active MSVC shell.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+6 -1
View File
@@ -111,17 +111,22 @@ VOID _tx_initialize_high_level(VOID)
/* Initialize the event log, if enabled. */
TX_EL_INITIALIZE
/* Call the thread control initialization function. */
_tx_thread_initialize();
#ifndef TX_NO_TIMER
/* Call the timer control initialization function. */
_tx_timer_initialize();
#endif
#ifndef TX_DISABLE_REDUNDANT_CLEARING
/* Call the semaphore initialization function. */
_tx_semaphore_initialize();
@@ -139,6 +144,6 @@ VOID _tx_initialize_high_level(VOID)
/* Call the mutex initialization function. */
_tx_mutex_initialize();
#endif
}
+3 -1
View File
@@ -101,15 +101,18 @@ VOID _tx_initialize_kernel_enter(VOID)
/* Call any port specific preprocessing. */
TX_PORT_SPECIFIC_PRE_INITIALIZATION
/* Invoke the low-level initialization to handle all processor specific
initialization issues. */
_tx_initialize_low_level();
/* Invoke the high-level initialization to exercise all of the
ThreadX components and the application's initialization
function. */
_tx_initialize_high_level();
/* Call any port specific post-processing. */
TX_PORT_SPECIFIC_POST_INITIALIZATION
}
@@ -150,4 +153,3 @@ VOID _tx_initialize_kernel_enter(VOID)
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}
+2 -1
View File
@@ -245,6 +245,7 @@ UINT status;
do
{
/* Create the system timer thread. */
status = _tx_thread_create(&_tx_timer_thread,
TX_CONST_CHAR_TO_CHAR_POINTER_CONVERT("System Timer Thread"),
@@ -253,6 +254,7 @@ UINT status;
_tx_timer_stack_start, _tx_timer_stack_size,
_tx_timer_priority, _tx_timer_priority, TX_NO_TIME_SLICE, TX_DONT_START);
#ifdef TX_SAFETY_CRITICAL
/* Check return from thread create - if an error is detected throw an exception. */
@@ -295,4 +297,3 @@ UINT status;
#endif
#endif
}
-1
View File
@@ -960,4 +960,3 @@ VOID _tx_thread_system_ni_resume(TX_THREAD *thread_ptr)
_tx_thread_system_resume(thread_ptr);
}
#endif
@@ -984,4 +984,3 @@ VOID _tx_thread_system_ni_suspend(TX_THREAD *thread_ptr, ULONG timeout)
_tx_thread_system_suspend(thread_ptr);
}
#endif
+96 -9
View File
@@ -26,7 +26,7 @@
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* tx_port.h Win32/Visual */
/* 6.1 */
/* 6.5.1.202602 */
/* */
/* AUTHOR */
/* */
@@ -66,6 +66,95 @@
#include <stdlib.h>
#include <string.h>
/* Define automated coverage test extensions required by the 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 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 performance metric symbols. */
@@ -101,7 +190,6 @@
#define TX_TIMER_ENABLE_PERFORMANCE_INFO
#endif
/* Enable trace info. */
#ifndef TX_ENABLE_EVENT_TRACE
@@ -198,7 +286,7 @@ void _tx_win32_debug_entry_insert(char *action, char *file, unsigned long lin
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
*/
*/
#ifndef TX_TRACE_TIME_SOURCE
#define TX_TRACE_TIME_SOURCE ((ULONG) (_tx_win32_time_stamp.LowPart));
@@ -232,7 +320,6 @@ void _tx_initialize_start_interrupts(void);
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION _tx_initialize_start_interrupts();
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
@@ -413,7 +500,7 @@ VOID _tx_thread_interrupt_restore(UINT previous_posture);
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
"(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Win32/Visual Studio Version 6.5.0.202601 *";
"(c) 2024 Microsoft Corp. (c) 2026-present Eclipse ThreadX contributors. * ThreadX Win32/Visual Studio Version 6.5.1.202602 *";
#else
extern CHAR _tx_version_id[];
#endif
@@ -437,11 +524,11 @@ extern LARGE_INTEGER _tx_win32_time_stamp;
#endif
#ifndef TX_TIMER_PERIODIC
#ifdef TX_WIN32_SLOW_TIMER
#define TX_TIMER_PERIODIC TX_WIN32_SLOW_TIMER
#else
#define TX_TIMER_PERIODIC 10
#endif
#endif
#endif
@@ -9,6 +9,7 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
/**************************************************************************/
/**************************************************************************/
@@ -280,4 +281,4 @@ VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD dwUser, D
/* Call ThreadX context restore for interrupt completion. */
_tx_thread_context_restore();
}
}
+19
View File
@@ -0,0 +1,19 @@
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,180 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_restore Win64/MSVC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function restores the interrupt context if it is processing a */
/* nested interrupt. If not, it returns to the interrupt thread if no */
/* preemption is necessary. Otherwise, if preemption is necessary or */
/* if no thread was running, the function returns to the scheduler. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* ReleaseSemaphore Win32 release semaphore */
/* ResumeThread Win32 resume thread */
/* _tx_win32_critical_section_obtain Obtain critical section */
/* _tx_win32_critical_section_release Release critical section */
/* */
/* CALLED BY */
/* */
/* ISRs Interrupt Service Routines */
/* */
/**************************************************************************/
VOID _tx_thread_context_restore(VOID)
{
TX_THREAD *execute_thread;
/* Enter critical section to ensure other threads are not playing with
the core ThreadX data structures. */
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
/* Debug entry. */
_tx_win32_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__);
/* Decrement the nested interrupt count. */
_tx_thread_system_state--;
/* Pickup the execute thread pointer. */
execute_thread = _tx_thread_execute_ptr;
/* Determine if this is the first nested interrupt and if a ThreadX
application thread was running at the time. */
if ((!_tx_thread_system_state) && (_tx_thread_current_ptr))
{
/* Yes, this is the first and last interrupt processed. */
/* Check to see if preemption is required. */
if ((_tx_thread_preempt_disable == 0) && (_tx_thread_current_ptr != _tx_thread_execute_ptr))
{
/* Preempt the running application thread. We don't need to suspend the
application thread since that is done in the context save processing. */
/* Indicate that this thread was suspended asynchronously. */
_tx_thread_current_ptr -> tx_thread_win32_suspension_type = 1;
/* Save the remaining time-slice and disable it. */
if (_tx_timer_time_slice)
{
_tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
_tx_timer_time_slice = 0;
}
/* Clear the current thread pointer. */
_tx_thread_current_ptr = TX_NULL;
/* Block the timer ISR until the resumed thread has observed the wakeup. */
_tx_win32_timer_waiting = TX_TRUE;
/* Wakeup the system thread by setting the system semaphore. */
ReleaseSemaphore(_tx_win32_scheduler_semaphore, 1, NULL);
_tx_win32_scheduler_wake();
/* If the timer made a solicited wakeup ready, let that thread run before
the host timer ISR continues. */
if ((execute_thread != TX_NULL) &&
(execute_thread -> tx_thread_win32_suspension_type == 0))
{
/* Release the critical section while the scheduler runs. */
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
WaitForSingleObject(_tx_win32_isr_semaphore, INFINITE);
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) == WAIT_OBJECT_0)
{
}
}
/* The timer ISR no longer needs to hold off future ticks. */
_tx_win32_timer_waiting = TX_FALSE;
}
else
{
/* Since preemption is not required, resume the interrupted thread. */
ResumeThread(_tx_thread_current_ptr -> tx_thread_win32_thread_handle);
}
}
else if ((!_tx_thread_system_state) && (execute_thread != TX_NULL))
{
/* The timer made a thread ready while the scheduler was idle. Keep the
timer ISR blocked until the solicited wakeup has started running. */
_tx_win32_timer_waiting = TX_TRUE;
_tx_win32_scheduler_wake();
if (execute_thread -> tx_thread_win32_suspension_type == 0)
{
/* Release the critical section while the scheduler runs. */
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
WaitForSingleObject(_tx_win32_isr_semaphore, INFINITE);
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) == WAIT_OBJECT_0)
{
}
}
_tx_win32_timer_waiting = TX_FALSE;
}
/* Leave Win32 critical section. */
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
}
@@ -0,0 +1,111 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_save Win64/MSVC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function saves the context of an executing thread in the */
/* beginning of interrupt processing. The function also ensures that */
/* the system stack is used upon return to the calling ISR. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* SuspendThread Win32 thread suspend */
/* _tx_win32_critical_section_obtain Obtain critical section */
/* _tx_win32_critical_section_release Release critical section */
/* */
/* CALLED BY */
/* */
/* ISRs */
/* */
/**************************************************************************/
VOID _tx_thread_context_save(VOID)
{
TX_THREAD *thread_ptr;
/* Enter critical section to ensure other threads are not playing with
the core ThreadX data structures. */
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
/* Debug entry. */
_tx_win32_debug_entry_insert("CONTEXT_SAVE", __FILE__, __LINE__);
/* Pickup the current thread pointer. */
thread_ptr = _tx_thread_current_ptr;
/* If an application thread is running, suspend it to simulate preemption. */
if ((thread_ptr) && (_tx_thread_system_state == 0))
{
/* Yes, this is the first interrupt and an application thread is running...
suspend it! */
/* Suspend the thread to simulate preemption. Note that the thread is suspended BEFORE the protection get
flag is checked to ensure there is not a race condition between this thread and the update of that flag. */
SuspendThread(thread_ptr -> tx_thread_win32_thread_handle);
/* Debug entry. */
_tx_win32_debug_entry_insert("CONTEXT_SAVE-suspend_thread", __FILE__, __LINE__);
}
/* Increment the nested interrupt condition. */
_tx_thread_system_state++;
/* Exit Win32 critical section. */
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,151 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_interrupt Win64/MSVC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes the hardware timer interrupt. This */
/* processing includes incrementing the system clock and checking for */
/* time slice and/or timer expiration. If either is found, the */
/* interrupt context save/restore functions are called along with the */
/* expiration functions. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_time_slice Time slice interrupted thread */
/* _tx_timer_expiration_process Timer expiration processing */
/* _tx_win32_critical_section_obtain Obtain critical section */
/* _tx_win32_critical_section_release Release critical section */
/* */
/* CALLED BY */
/* */
/* interrupt vector */
/* */
/**************************************************************************/
VOID _tx_timer_interrupt(VOID)
{
/* Enter critical section to ensure other threads are not playing with
the core ThreadX data structures. */
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
/* Debug entry. */
_tx_win32_debug_entry_insert("TIMER INTERRUPT", __FILE__, __LINE__);
/* Increment the system clock. */
_tx_timer_system_clock++;
/* Test for time-slice expiration. */
if (_tx_timer_time_slice)
{
/* Decrement the time_slice. */
_tx_timer_time_slice--;
/* Check for expiration. */
if (_tx_timer_time_slice == 0)
{
/* Set the time-slice expired flag. */
_tx_timer_expired_time_slice = TX_TRUE;
}
}
/* Test for timer expiration. */
if (*_tx_timer_current_ptr)
{
/* Set expiration flag. */
_tx_timer_expired = TX_TRUE;
}
else
{
/* No timer expired, increment the timer pointer. */
_tx_timer_current_ptr++;
/* Check for wrap-around. */
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
/* Wrap to beginning of list. */
_tx_timer_current_ptr = _tx_timer_list_start;
}
}
/* See if anything has expired. */
if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
{
/* Did a timer expire? */
if (_tx_timer_expired)
{
/* Process timer expiration. */
_tx_timer_expiration_process();
}
/* Did time slice expire? */
if (_tx_timer_expired_time_slice)
{
/* Time slice interrupted thread. */
_tx_thread_time_slice();
}
}
/* Exit Win32 critical section. */
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
+28
View File
@@ -0,0 +1,28 @@
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_core_get.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_core_preempt.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_current_state_get.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_current_thread_get.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_initialize_wait.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_low_level_initialize.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_protect.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_time_get.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_smp_unprotect.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.c
${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
This port provides a Windows-hosted SMP simulation environment for ThreadX.
The implementation models virtual ThreadX cores on top of Win64 host threads.
It is intended for validation and regression testing only. It is not a
production runtime port for deploying ThreadX applications on Windows.
Key characteristics:
- ThreadX cores are virtual scheduler-owned mappings, not Windows CPU numbers.
- One Windows host thread is created for each ThreadX thread.
- A dedicated scheduler thread and a dedicated timer/ISR thread coordinate the
simulation.
- SuspendThread and ResumeThread are used only to emulate asynchronous
preemption in the simulator.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,139 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.5).
// Some portions generated by GitHub Copilot (claude-sonnet-4.6).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
VOID _tx_thread_context_restore(VOID)
{
TX_THREAD *current_thread;
TX_THREAD *execute_thread;
_tx_win32_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__);
_tx_thread_system_state[0]--;
current_thread = _tx_thread_current_ptr[0];
execute_thread = _tx_thread_execute_ptr[0];
if (_tx_thread_system_state[0] == 0UL)
{
if (current_thread != TX_NULL)
{
if ((_tx_thread_preempt_disable == 0U) && (current_thread != execute_thread))
{
/* If context_save skipped SuspendThread because the thread was spinning
* on the Win32 CS (suspension_type == 4), suspend it now. The ISR still
* holds the CS so the spinning thread cannot make forward progress, making
* SuspendThread safe to call here. mutex_access remains TRUE; the thread
* will clear it naturally when it acquires the CS after being resumed. */
if (current_thread -> tx_thread_win32_suspension_type == 4U)
{
_tx_win32_thread_suspend(current_thread -> tx_thread_win32_thread_handle);
}
current_thread -> tx_thread_win32_suspension_type = 1U;
if (_tx_timer_time_slice[0] != 0U)
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[0];
_tx_timer_time_slice[0] = 0U;
}
_tx_thread_current_ptr[0] = TX_NULL;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_handle = NULL;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_id = 0U;
_tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread = TX_NULL;
current_thread -> tx_thread_smp_core_control = 1U;
/* Signal the scheduler to assign the next execute_thread. Wait for the
* scheduler to signal isr_semaphore before returning: the scheduler holds
* the CS while waiting for start_ack from the execute_thread, which forces
* any thread calling TX_DISABLE to spin with mutex_access=TRUE while
* preempt_disable may be non-zero — exactly the window needed to satisfy
* the condition in tests such as wait_abort_and_isr. */
_tx_win32_timer_waiting = 1U;
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
if ((execute_thread != TX_NULL) &&
(execute_thread -> tx_thread_win32_suspension_type == 2U))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
_tx_win32_wait_for_isr_rendezvous();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
_tx_win32_semaphore_reset(_tx_win32_isr_semaphore);
}
_tx_win32_timer_waiting = 0U;
}
else
{
if ((current_thread -> tx_thread_win32_suspension_type == 3U) ||
(current_thread -> tx_thread_win32_suspension_type == 4U))
{
/* context_save did not call SuspendThread (type 3: preempt_disable≠0;
* type 4: thread was spinning on Win32 CS). Clear the flag; do not
* issue a matching ResumeThread. The thread will continue
* automatically once the ISR releases the Win32 critical section. */
current_thread -> tx_thread_win32_suspension_type = 0U;
}
else
{
/* suspension_type 0: context_save called SuspendThread. Always issue
* the matching ResumeThread here, regardless of mutex_access.
*
* Do NOT gate this on mutex_access: a thread on a different virtual core
* that happens to share the same stale TLS slot can momentarily stamp
* mutex_access = TRUE on this thread's struct while it is OS-suspended,
* which would otherwise cause context_restore to skip ResumeThread and
* leave the thread permanently suspended (deadlock). */
_tx_win32_thread_resume(current_thread -> tx_thread_win32_thread_handle);
}
}
}
else if (execute_thread != TX_NULL)
{
_tx_win32_timer_waiting = 1U;
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
if (execute_thread -> tx_thread_win32_suspension_type == 2U)
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
_tx_win32_wait_for_isr_rendezvous();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
_tx_win32_semaphore_reset(_tx_win32_isr_semaphore);
}
_tx_win32_timer_waiting = 0U;
}
}
_tx_thread_smp_unprotect(TX_INT_ENABLE);
}
@@ -0,0 +1,83 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
// Some portions generated by GitHub Copilot (claude-sonnet-4.6).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
VOID _tx_thread_context_save(VOID)
{
TX_THREAD *thread_ptr;
UINT interrupt_posture;
interrupt_posture = _tx_thread_smp_protect();
if (interrupt_posture != TX_FALSE)
{
_tx_win32_system_error++;
}
_tx_win32_debug_entry_insert("CONTEXT_SAVE", __FILE__, __LINE__);
thread_ptr = _tx_thread_current_ptr[0];
if ((thread_ptr != TX_NULL) && (_tx_thread_system_state[0] == 0UL))
{
if (thread_ptr -> tx_thread_win32_mutex_access == TX_FALSE)
{
if (_tx_thread_preempt_disable == 0U)
{
/* Thread is not in a preempt-disabled section; suspend it normally so
* context_restore can preempt it if a higher-priority thread is ready. */
_tx_win32_thread_suspend(thread_ptr -> tx_thread_win32_thread_handle);
_tx_win32_debug_entry_insert("CONTEXT_SAVE-suspend_thread", __FILE__, __LINE__);
}
else
{
/* Thread holds the SMP preemption lock (_tx_thread_preempt_disable != 0).
* Issuing SuspendThread/ResumeThread here would cost ~100 µs for zero
* benefit: context_restore will skip preemption anyway because
* _tx_thread_preempt_disable is still non-zero when it runs (the ISR
* cannot lower the count below its value at ISR entry while it holds the
* Win32 critical section). Flag the thread so context_restore knows not
* to issue a matching ResumeThread.
*
* MISRA C 2012 Rule 10.3 deviation: suspension_type is a UINT field used
* as a small state tag; value 3 is a port-local extension of the existing
* 0/1/2 enumeration. */
thread_ptr -> tx_thread_win32_suspension_type = 3U;
}
}
else
{
/* Thread is spinning on the Win32 critical section (mutex_access TRUE).
* It is blocked waiting to acquire the CS and cannot execute any protected
* ThreadX code, so SuspendThread is unnecessary. Tag the thread with
* suspension_type 4 so context_restore handles it correctly:
* - no-preemption path: just clear the flag (no ResumeThread).
* - preemption path: call SuspendThread retrospectively and proceed.
*
* MISRA C 2012 Rule 10.3 deviation: value 4 is a port-local extension. */
thread_ptr -> tx_thread_win32_suspension_type = 4U;
}
}
_tx_thread_system_state[0]++;
}
@@ -0,0 +1,104 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
UINT _tx_thread_interrupt_disable(void)
{
UINT previous_value;
previous_value = _tx_thread_interrupt_control(TX_INT_DISABLE);
return(previous_value);
}
VOID _tx_thread_interrupt_restore(UINT previous_posture)
{
previous_posture = _tx_thread_interrupt_control(previous_posture);
TX_PARAMETER_NOT_USED(previous_posture);
}
UINT _tx_thread_interrupt_control(UINT new_posture)
{
UINT old_posture;
TX_THREAD *thread_ptr;
DWORD thread_id;
UINT core;
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
#ifdef TX_WIN32_DEBUG_ENABLE
if (new_posture == TX_INT_ENABLE)
{
_tx_win32_debug_entry_insert("RESTORE", __FILE__, __LINE__);
}
else
{
_tx_win32_debug_entry_insert("DISABLE", __FILE__, __LINE__);
}
#endif
thread_id = GetCurrentThreadId();
core = _tx_thread_smp_core_get();
thread_ptr = _tx_thread_current_ptr[core];
if ((_tx_win32_threadx_thread != 0) &&
((thread_ptr == TX_NULL) || (thread_ptr -> tx_thread_win32_thread_id != thread_id)))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
ExitThread(0);
}
if (_tx_win32_critical_section.tx_win32_critical_section_nested_count == 1U)
{
old_posture = TX_INT_ENABLE;
}
else
{
old_posture = TX_INT_DISABLE;
}
if (_tx_thread_system_state[core] != 0UL)
{
if (new_posture == TX_INT_ENABLE)
{
_tx_win32_global_int_disabled_flag = TX_FALSE;
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
}
else if (new_posture == TX_INT_DISABLE)
{
_tx_win32_global_int_disabled_flag = TX_TRUE;
}
}
else if (thread_ptr != TX_NULL)
{
if (new_posture == TX_INT_ENABLE)
{
thread_ptr -> tx_thread_win32_int_disabled_flag = TX_FALSE;
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
}
else if (new_posture == TX_INT_DISABLE)
{
thread_ptr -> tx_thread_win32_int_disabled_flag = TX_TRUE;
}
}
return(old_posture);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
UINT _tx_thread_smp_core_get(void)
{
return(_tx_win32_smp_current_core_get());
}
@@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
void _tx_thread_smp_core_preempt(UINT core)
{
TX_THREAD *preempt_thread;
preempt_thread = _tx_thread_current_ptr[core];
if (preempt_thread != TX_NULL)
{
preempt_thread -> tx_thread_win32_deferred_preempt = TX_TRUE;
_tx_win32_debug_entry_insert("CORE_PREEMPT_deferred", __FILE__, __LINE__);
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
}
else if (_tx_thread_execute_ptr[core] != TX_NULL)
{
_tx_win32_debug_entry_insert("CORE_PREEMPT_wake_idle", __FILE__, __LINE__);
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
}
}
@@ -0,0 +1,49 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
ULONG _tx_thread_smp_current_state_get(void)
{
UINT core;
DWORD thread_id;
UINT critical_section_owned;
ULONG current_state;
thread_id = GetCurrentThreadId();
critical_section_owned = (UINT) (_tx_win32_critical_section.tx_win32_critical_section_owner == thread_id);
if (critical_section_owned == TX_FALSE)
{
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
}
core = _tx_win32_smp_current_core_get();
current_state = _tx_thread_system_state[core];
if (critical_section_owned == TX_FALSE)
{
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
return(current_state);
}
@@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
TX_THREAD *_tx_thread_smp_current_thread_get(void)
{
UINT core;
DWORD thread_id;
UINT critical_section_owned;
TX_THREAD *current_thread;
thread_id = GetCurrentThreadId();
critical_section_owned = (UINT) (_tx_win32_critical_section.tx_win32_critical_section_owner == thread_id);
if (critical_section_owned == TX_FALSE)
{
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
}
core = _tx_win32_smp_current_core_get();
current_thread = _tx_thread_current_ptr[core];
if ((_tx_win32_threadx_thread != 0) && (current_thread == TX_NULL))
{
_tx_win32_debug_entry_insert("CURRENT_THREAD_GET_NULL", __FILE__, __LINE__);
}
if (critical_section_owned == TX_FALSE)
{
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
return(current_thread);
}
@@ -0,0 +1,25 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
void _tx_thread_smp_initialize_wait(void)
{
}
@@ -0,0 +1,26 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
void _tx_thread_smp_low_level_initialize(UINT number_of_cores)
{
TX_PARAMETER_NOT_USED(number_of_cores);
}
@@ -0,0 +1,128 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.5).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
UINT _tx_thread_smp_protect(void)
{
DWORD current_thread_id;
UINT core;
UINT interrupt_posture;
TX_THREAD *current_thread;
UINT current_state;
do
{
do
{
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
current_thread_id = GetCurrentThreadId();
core = _tx_thread_smp_core_get();
current_thread = _tx_thread_current_ptr[core];
if ((_tx_win32_threadx_thread != 0) &&
((current_thread == TX_NULL) || (current_thread -> tx_thread_win32_thread_id != current_thread_id)))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
ExitThread(0);
}
if (_tx_win32_threadx_thread == 0)
{
break;
}
if ((current_thread != TX_NULL) && (_tx_thread_preempt_disable == 0U))
{
current_state = current_thread -> tx_thread_state;
if ((current_state == TX_TERMINATED) || (current_state == TX_COMPLETED))
{
current_thread -> tx_thread_win32_deferred_preempt = TX_FALSE;
current_thread -> tx_thread_win32_suspension_type = 1U;
if (_tx_timer_time_slice[core] != 0U)
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[core];
_tx_timer_time_slice[core] = 0U;
}
_tx_thread_current_ptr[core] = TX_NULL;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_handle = NULL;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_id = 0U;
current_thread -> tx_thread_smp_core_control = 1U;
_tx_win32_debug_entry_insert("SCHEDULE-thread_terminate_preempt_complete", __FILE__, __LINE__);
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
ExitThread(0);
}
}
if ((current_thread != TX_NULL) && (current_thread -> tx_thread_win32_deferred_preempt != TX_FALSE))
{
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
_tx_win32_thread_yield();
}
else
{
break;
}
} while (1);
interrupt_posture = (UINT) _tx_win32_global_int_disabled_flag;
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core)
{
_tx_thread_smp_protection.tx_thread_smp_protect_count++;
_tx_win32_global_int_disabled_flag = TX_TRUE;
_tx_win32_debug_entry_insert("PROTECT-obtained-nested", __FILE__, __LINE__);
break;
}
else if (_tx_thread_smp_protection.tx_thread_smp_protect_core == 0xFFFFFFFFUL)
{
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_TRUE;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = current_thread;
_tx_thread_smp_protection.tx_thread_smp_protect_core = core;
_tx_thread_smp_protection.tx_thread_smp_protect_count = 1U;
_tx_thread_smp_protection.tx_thread_smp_protect_thread_id = current_thread_id;
_tx_win32_global_int_disabled_flag = TX_TRUE;
_tx_win32_debug_entry_insert("PROTECT-obtained", __FILE__, __LINE__);
break;
}
else
{
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
} while (1);
_tx_win32_global_int_disabled_flag = TX_TRUE;
return(interrupt_posture);
}
@@ -0,0 +1,27 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
ULONG _tx_thread_smp_time_get(void)
{
QueryPerformanceCounter((LARGE_INTEGER *) &_tx_win32_time_stamp);
return((ULONG) _tx_win32_time_stamp.LowPart);
}
@@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.4).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
void _tx_thread_smp_unprotect(UINT new_interrupt_posture)
{
UINT core;
DWORD current_thread_id;
UINT critical_section_owned;
current_thread_id = GetCurrentThreadId();
critical_section_owned = (UINT) (_tx_win32_critical_section.tx_win32_critical_section_owner == current_thread_id);
if (critical_section_owned == TX_FALSE)
{
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
}
core = _tx_thread_smp_core_get();
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core)
{
_tx_thread_smp_protection.tx_thread_smp_protect_count--;
if (_tx_thread_smp_protection.tx_thread_smp_protect_count == 0U)
{
_tx_win32_global_int_disabled_flag = new_interrupt_posture;
if (_tx_thread_preempt_disable == 0U)
{
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_FALSE;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = TX_NULL;
_tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFFUL;
_tx_thread_smp_protection.tx_thread_smp_protect_thread_id = 0U;
_tx_win32_debug_entry_insert("UNPROTECT-keep", __FILE__, __LINE__);
}
else
{
_tx_win32_debug_entry_insert("UNPROTECT-released", __FILE__, __LINE__);
}
}
else
{
_tx_win32_debug_entry_insert("UNPROTECT-nested", __FILE__, __LINE__);
}
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
else
{
_tx_win32_critical_section_release(&_tx_win32_critical_section);
}
}
@@ -0,0 +1,122 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.5).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include <stdio.h>
static DWORD WINAPI _tx_win32_thread_entry(LPVOID ptr);
VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{
TX_PARAMETER_NOT_USED(function_ptr);
#if (TX_WIN32_USE_ADDRESS_WAIT != 0)
thread_ptr -> tx_thread_win32_thread_run_semaphore = NULL;
thread_ptr -> tx_thread_win32_thread_start_semaphore = NULL;
#else
thread_ptr -> tx_thread_win32_thread_run_semaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
if (thread_ptr -> tx_thread_win32_thread_run_semaphore == NULL)
{
printf("ThreadX SMP Win64 error creating thread run semaphore!\n");
while (1)
{
}
}
thread_ptr -> tx_thread_win32_thread_start_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
if (thread_ptr -> tx_thread_win32_thread_start_semaphore == NULL)
{
printf("ThreadX SMP Win64 error creating thread start semaphore!\n");
while (1)
{
}
}
#endif
thread_ptr -> tx_thread_win32_thread_handle = CreateThread(NULL,
TX_WIN32_THREAD_STACK_SIZE,
_tx_win32_thread_entry,
(LPVOID) thread_ptr,
CREATE_SUSPENDED,
&thread_ptr -> tx_thread_win32_thread_id);
if (thread_ptr -> tx_thread_win32_thread_handle == NULL)
{
printf("ThreadX SMP Win64 error creating thread!\n");
while (1)
{
}
}
SetThreadPriority(thread_ptr -> tx_thread_win32_thread_handle, TX_WIN32_PRIORITY_USER_THREAD);
thread_ptr -> tx_thread_win32_suspension_type = 2U;
thread_ptr -> tx_thread_win32_mutex_access = TX_FALSE;
thread_ptr -> tx_thread_win32_int_disabled_flag = TX_FALSE;
thread_ptr -> tx_thread_win32_deferred_preempt = TX_FALSE;
thread_ptr -> tx_thread_win32_virtual_core = 0U;
thread_ptr -> tx_thread_win32_run_sequence = 0L;
thread_ptr -> tx_thread_win32_run_sequence_seen = 0L;
thread_ptr -> tx_thread_win32_start_sequence = 0L;
thread_ptr -> tx_thread_stack_ptr = (VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8);
*(((ULONG *) thread_ptr -> tx_thread_stack_ptr) - 1) = 0UL;
thread_ptr -> tx_thread_smp_core_control = 1U;
ResumeThread(thread_ptr -> tx_thread_win32_thread_handle);
}
static DWORD WINAPI _tx_win32_thread_entry(LPVOID ptr)
{
TX_THREAD *thread_ptr;
thread_ptr = (TX_THREAD *) ptr;
_tx_win32_threadx_thread = 1;
_tx_win32_debug_entry_insert("THREAD_ENTRY_wait", __FILE__, __LINE__);
_tx_win32_wait_for_thread_run(thread_ptr);
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_mark_run_wake(thread_ptr);
#endif
_tx_win32_debug_entry_insert("THREAD_ENTRY_wake", __FILE__, __LINE__);
/* A delete/reset cleanup may wake a host thread that was never scheduled.
Only treat the wakeup as terminal if the ThreadX thread is already in a
terminal state; otherwise allow the normal startup race to complete. */
if ((thread_ptr -> tx_thread_smp_core_control != 0U) &&
((thread_ptr -> tx_thread_state == TX_TERMINATED) ||
(thread_ptr -> tx_thread_state == TX_COMPLETED)))
{
ExitThread(0U);
}
_tx_win32_current_virtual_core = thread_ptr -> tx_thread_win32_virtual_core;
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_mark_start_ack(thread_ptr);
#endif
_tx_win32_thread_start_ack_signal(thread_ptr);
_tx_win32_debug_entry_insert("THREAD_ENTRY_ack", __FILE__, __LINE__);
_tx_thread_shell_entry();
return(0U);
}
@@ -0,0 +1,117 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
// Some portions generated by Codex (gpt 5.5).
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
VOID _tx_thread_system_return(VOID)
{
TX_THREAD *temp_thread_ptr;
UINT temp_thread_state;
UINT core;
DWORD thread_id;
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
core = _tx_thread_smp_core_get();
thread_id = GetCurrentThreadId();
_tx_win32_debug_entry_insert("SYSTEM_RETURN", __FILE__, __LINE__);
temp_thread_ptr = _tx_thread_current_ptr[core];
if ((_tx_win32_threadx_thread != 0) &&
((temp_thread_ptr == TX_NULL) || (temp_thread_ptr -> tx_thread_win32_thread_id != thread_id)))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
ExitThread(0);
}
if (_tx_timer_time_slice[core] != 0U)
{
temp_thread_ptr -> tx_thread_time_slice = _tx_timer_time_slice[core];
_tx_timer_time_slice[core] = 0U;
}
temp_thread_state = temp_thread_ptr -> tx_thread_state;
temp_thread_ptr -> tx_thread_win32_suspension_type = 2U;
_tx_thread_current_ptr[core] = TX_NULL;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_handle = NULL;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_id = 0U;
_tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_win32_debug_entry_insert("SYSTEM_RETURN-release_sem", __FILE__, __LINE__);
if (temp_thread_ptr != _tx_thread_smp_protection.tx_thread_smp_protect_thread)
{
_tx_win32_system_error++;
}
_tx_thread_smp_protection.tx_thread_smp_protect_count = 0U;
_tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFFUL;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = TX_NULL;
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_FALSE;
_tx_thread_smp_protection.tx_thread_smp_protect_thread_id = 0U;
temp_thread_ptr -> tx_thread_smp_core_control = 1U;
_tx_win32_global_int_disabled_flag = TX_FALSE;
_tx_thread_preempt_disable = 0U;
MemoryBarrier();
if (SetEvent(_tx_win32_scheduler_event) == 0)
{
_tx_win32_system_error++;
}
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
if (temp_thread_state == TX_TERMINATED)
{
ExitThread(0);
}
_tx_win32_wait_for_thread_run(temp_thread_ptr);
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_mark_run_wake(temp_thread_ptr);
#endif
_tx_win32_current_virtual_core = temp_thread_ptr -> tx_thread_win32_virtual_core;
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_mark_start_ack(temp_thread_ptr);
#endif
_tx_win32_thread_start_ack_signal(temp_thread_ptr);
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
_tx_win32_debug_entry_insert("SYSTEM_RETURN-wake_up", __FILE__, __LINE__);
core = _tx_thread_smp_core_get();
temp_thread_ptr = _tx_thread_current_ptr[core];
if ((_tx_win32_threadx_thread != 0) &&
((temp_thread_ptr == TX_NULL) || (temp_thread_ptr -> tx_thread_win32_thread_id != thread_id)))
{
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
ExitThread(0);
}
_tx_win32_debug_entry_insert("SYSTEM_RETURN-finish", __FILE__, __LINE__);
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
}
@@ -0,0 +1,56 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
VOID _tx_timer_interrupt(VOID)
{
UINT saved_posture;
saved_posture = _tx_thread_smp_protect();
_tx_timer_interrupt_active++;
_tx_win32_debug_entry_insert("TIMER INTERRUPT", __FILE__, __LINE__);
_tx_timer_system_clock++;
if (*_tx_timer_current_ptr)
{
_tx_timer_expired = TX_TRUE;
}
else
{
_tx_timer_current_ptr++;
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
_tx_timer_current_ptr = _tx_timer_list_start;
}
}
if (_tx_timer_expired != TX_FALSE)
{
_tx_timer_expiration_process();
}
_tx_thread_time_slice();
_tx_timer_interrupt_active++;
_tx_thread_smp_unprotect(saved_posture);
}
+54
View File
@@ -0,0 +1,54 @@
[CmdletBinding()]
param(
[AllowNull()]
[object]$Configuration = 'all',
[int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount),
[int]$BuildTimeoutSeconds = 180,
[string]$BuildDir,
[switch]$Clean
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'tx_windows_common.ps1')
$repoRoot = Split-Path -Parent $PSScriptRoot
if (-not $BuildDir) {
$BuildDir = Join-Path $repoRoot 'build\tests\win64_smp'
}
$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
Enter-VisualStudioDevShell -VsArch 'amd64'
foreach ($currentConfiguration in $selectedConfigurations) {
$currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
$currentBuildDir = Join-Path $BuildDir $currentBuildDirName
if ($Clean) {
Remove-BuildDirectory -Path $currentBuildDir -RepoRoot $repoRoot
}
Remove-NinjaLock -Path $currentBuildDir
Write-Host "Configuring win64_smp / $currentConfiguration"
Invoke-NativeCommand -FilePath 'cmake' -Arguments @(
'-S', (Join-Path $repoRoot 'test\smp\cmake'),
'-B', $currentBuildDir,
'-G', 'Ninja',
'-DCMAKE_C_COMPILER_FORCED=TRUE',
'-DCMAKE_C_COMPILER_WORKS=TRUE',
'-DCMAKE_C_ABI_COMPILED=TRUE',
"-DCMAKE_BUILD_TYPE=$currentConfiguration",
'-DTHREADX_ARCH=win64',
'-DTHREADX_TOOLCHAIN=vs_2022'
)
Write-Host "Building win64_smp / $currentConfiguration"
Invoke-CMakeBuild -BuildDir $currentBuildDir -Parallel $Parallel -TimeoutSeconds $BuildTimeoutSeconds
}
+58
View File
@@ -0,0 +1,58 @@
[CmdletBinding()]
param(
[ValidateSet('win64', 'win32')]
[string]$Arch = 'win64',
[AllowNull()]
[object]$Configuration = 'all',
[int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount),
[int]$BuildTimeoutSeconds = 60,
[string]$BuildDir,
[switch]$Clean
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'tx_windows_common.ps1')
$repoRoot = Split-Path -Parent $PSScriptRoot
$settings = Get-PortSettings -SelectedArch $Arch
if (-not $BuildDir) {
$BuildDir = Join-Path $repoRoot "build\tests\$Arch"
}
$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
Enter-VisualStudioDevShell -VsArch $settings.VsArch
foreach ($currentConfiguration in $selectedConfigurations) {
$currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
$currentBuildDir = Join-Path $BuildDir $currentBuildDirName
if ($Clean) {
Remove-BuildDirectory -Path $currentBuildDir -RepoRoot $repoRoot
}
Remove-NinjaLock -Path $currentBuildDir
Write-Host "Configuring $Arch / $currentConfiguration"
Invoke-NativeCommand -FilePath 'cmake' -Arguments @(
'-S', (Join-Path $repoRoot 'test\tx\cmake'),
'-B', $currentBuildDir,
'-G', 'Ninja',
'-DCMAKE_C_COMPILER_FORCED=TRUE',
'-DCMAKE_C_COMPILER_WORKS=TRUE',
'-DCMAKE_C_ABI_COMPILED=TRUE',
"-DCMAKE_BUILD_TYPE=$currentConfiguration",
"-DTHREADX_ARCH=$($settings.ThreadXArch)",
"-DTHREADX_TOOLCHAIN=$($settings.ThreadXToolchain)"
)
Write-Host "Building $Arch / $currentConfiguration"
Invoke-CMakeBuild -BuildDir $currentBuildDir -Parallel $Parallel -TimeoutSeconds $BuildTimeoutSeconds
}
+120
View File
@@ -0,0 +1,120 @@
[CmdletBinding()]
param(
[AllowNull()]
[object]$Configuration = 'all',
[int]$Parallel = 1,
[int]$RepeatFailCount = 2,
[int]$TestTimeoutSeconds = 45,
[switch]$CollectFailureDiagnostics = $true,
[string]$TestRegex,
[switch]$RerunFailedOnly,
[string]$BuildDir,
[switch]$Clean
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'tx_windows_common.ps1')
$repoRoot = Split-Path -Parent $PSScriptRoot
if (-not $BuildDir) {
$BuildDir = Join-Path $repoRoot 'build\tests\win64_smp'
}
$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
Enter-VisualStudioDevShell -VsArch 'amd64'
if ($Parallel -ne 1) {
Write-Warning 'Windows SMP simulator regression tests are timing-sensitive. Forcing -Parallel 1.'
$Parallel = 1
}
if ($TestRegex -and -not $PSBoundParameters.ContainsKey('TestTimeoutSeconds')) {
$TestTimeoutSeconds = 60
Write-Host "Targeted run detected; using per-test timeout of $TestTimeoutSeconds seconds."
}
$failedConfigurations = @()
foreach ($currentConfiguration in $selectedConfigurations) {
$currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
$currentBuildDir = Join-Path $BuildDir $currentBuildDirName
$currentTestingTemporaryDir = Join-Path $currentBuildDir 'Testing\Temporary'
try {
if ($Clean) {
$currentTestingDir = Join-Path $currentBuildDir 'Testing'
Remove-CtestTestingDirectory -Path $currentTestingDir
}
if (-not (Test-Path -LiteralPath $currentBuildDir)) {
throw "Build directory does not exist for win64_smp / ${currentConfiguration}: $currentBuildDir"
}
Remove-NinjaLock -Path $currentBuildDir
if (Test-Path -LiteralPath $currentTestingTemporaryDir) {
Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTest.log') -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTestsFailed.log') -Force -ErrorAction SilentlyContinue
}
Write-Host "Testing win64_smp / $currentConfiguration"
$ctestArguments = @(
'--test-dir', $currentBuildDir,
'--output-on-failure',
'--timeout', $TestTimeoutSeconds.ToString(),
'-j', $Parallel.ToString()
)
if ($RepeatFailCount -gt 1) {
$ctestArguments += @('--repeat', "until-pass:$RepeatFailCount")
}
if ($TestRegex) {
$ctestArguments += @('-R', $TestRegex)
}
if ($RerunFailedOnly) {
$ctestArguments += '--rerun-failed'
}
Invoke-NativeCommand -FilePath 'ctest' -Arguments $ctestArguments
}
catch {
if ($CollectFailureDiagnostics -and (Test-Path -LiteralPath $currentBuildDir)) {
try {
Invoke-CtestFailureDiagnostics -BuildDir $currentBuildDir -TestingTemporaryDir $currentTestingTemporaryDir `
-TimeoutSeconds $TestTimeoutSeconds
}
catch {
Write-Warning "Failure diagnostics collection failed for ${currentConfiguration}: $($_.Exception.Message)"
}
}
$failedConfigurations += @{
Configuration = $currentConfiguration
Message = $_.Exception.Message
}
Write-Warning "Configuration failed: $currentConfiguration"
}
}
if ($failedConfigurations.Count -gt 0) {
Write-Host ''
Write-Host 'Configuration failure summary:'
foreach ($failedConfiguration in $failedConfigurations) {
Write-Host "- $($failedConfiguration.Configuration): $($failedConfiguration.Message)"
}
throw "One or more configurations failed: $($failedConfigurations.Configuration -join ', ')"
}
+121
View File
@@ -0,0 +1,121 @@
[CmdletBinding()]
param(
[ValidateSet('win64', 'win32')]
[string]$Arch = 'win64',
[AllowNull()]
[object]$Configuration = 'all',
[int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount),
[int]$RepeatFailCount = 1,
[int]$TestTimeoutSeconds = 20,
[switch]$CollectFailureDiagnostics = $true,
[string]$TestRegex,
[switch]$RerunFailedOnly,
[string]$BuildDir,
[switch]$Clean
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'tx_windows_common.ps1')
$repoRoot = Split-Path -Parent $PSScriptRoot
$settings = Get-PortSettings -SelectedArch $Arch
if (-not $BuildDir) {
$BuildDir = Join-Path $repoRoot "build\tests\$Arch"
}
$selectedConfigurations = Resolve-RegressionConfigurations -RequestedConfigurations $Configuration
Write-Host "Selected configurations: $($selectedConfigurations -join ', ')"
Enter-VisualStudioDevShell -VsArch $settings.VsArch
if (($settings.ThreadXArch -eq 'win32') -or ($settings.ThreadXArch -eq 'win64')) {
if ($Parallel -ne 1) {
Write-Warning "Windows simulator regression tests are timing-sensitive under concurrent ctest execution. Forcing -Parallel 1."
$Parallel = 1
}
}
$failedConfigurations = @()
foreach ($currentConfiguration in $selectedConfigurations) {
$currentBuildDirName = Get-RegressionBuildDirectoryName -ConfigurationName $currentConfiguration
$currentBuildDir = Join-Path $BuildDir $currentBuildDirName
$currentTestingTemporaryDir = Join-Path $currentBuildDir 'Testing\Temporary'
try {
if ($Clean) {
$currentTestingDir = Join-Path $currentBuildDir 'Testing'
Remove-CtestTestingDirectory -Path $currentTestingDir
}
if (-not (Test-Path -LiteralPath $currentBuildDir)) {
throw "Build directory does not exist for $Arch / ${currentConfiguration}: $currentBuildDir"
}
Remove-NinjaLock -Path $currentBuildDir
if (Test-Path -LiteralPath $currentTestingTemporaryDir) {
Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTest.log') -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath (Join-Path $currentTestingTemporaryDir 'LastTestsFailed.log') -Force -ErrorAction SilentlyContinue
}
Write-Host "Testing $Arch / $currentConfiguration"
$ctestArguments = @(
'--test-dir', $currentBuildDir,
'--output-on-failure',
'--timeout', $TestTimeoutSeconds.ToString(),
'-j', $Parallel.ToString()
)
if ($RepeatFailCount -gt 1) {
$ctestArguments += @('--repeat', "until-pass:$RepeatFailCount")
}
if ($TestRegex) {
$ctestArguments += @('-R', $TestRegex)
}
if ($RerunFailedOnly) {
$ctestArguments += '--rerun-failed'
}
Invoke-NativeCommand -FilePath 'ctest' -Arguments $ctestArguments
}
catch {
if ($CollectFailureDiagnostics -and (Test-Path -LiteralPath $currentBuildDir)) {
try {
Invoke-CtestFailureDiagnostics -BuildDir $currentBuildDir -TestingTemporaryDir $currentTestingTemporaryDir `
-TimeoutSeconds $TestTimeoutSeconds
}
catch {
Write-Warning "Failure diagnostics collection failed for ${currentConfiguration}: $($_.Exception.Message)"
}
}
$failedConfigurations += @{
Configuration = $currentConfiguration
Message = $_.Exception.Message
}
Write-Warning "Configuration failed: $currentConfiguration"
}
}
if ($failedConfigurations.Count -gt 0) {
Write-Host ''
Write-Host 'Configuration failure summary:'
foreach ($failedConfiguration in $failedConfigurations) {
Write-Host "- $($failedConfiguration.Configuration): $($failedConfiguration.Message)"
}
throw "One or more configurations failed: $($failedConfigurations.Configuration -join ', ')"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
/***************************************************************************
* Copyright (C) 2026 Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4).
* The AI-generated portions may be considered public domain (CC0-1.0)
* and not subject to the project's licence. The human contributor has
* reviewed and verified that the code is correct.
*
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
#ifdef _MSC_VER
#if defined(_M_IX86)
#define TX_TEST_LINKER_ALIAS(symbol, default_symbol) __pragma(comment(linker, "/alternatename:_" #symbol "=_" #default_symbol))
#else
#define TX_TEST_LINKER_ALIAS(symbol, default_symbol) __pragma(comment(linker, "/alternatename:" #symbol "=" #default_symbol))
#endif
void tx_test_default_abort_all_threads_suspended_on_mutex(void)
{
}
TX_TEST_LINKER_ALIAS(abort_all_threads_suspended_on_mutex, tx_test_default_abort_all_threads_suspended_on_mutex)
void tx_test_default_suspend_lowest_priority(void)
{
}
TX_TEST_LINKER_ALIAS(suspend_lowest_priority, tx_test_default_suspend_lowest_priority)
void tx_test_default_abort_and_resume_byte_allocating_thread(void)
{
}
TX_TEST_LINKER_ALIAS(abort_and_resume_byte_allocating_thread, tx_test_default_abort_and_resume_byte_allocating_thread)
#else
__attribute__((weak)) void abort_all_threads_suspended_on_mutex(void)
{
}
__attribute__((weak)) void suspend_lowest_priority(void)
{
}
__attribute__((weak)) void abort_and_resume_byte_allocating_thread(void)
{
}
#endif
+59 -41
View File
@@ -2,11 +2,19 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0057 NEW)
if((DEFINED THREADX_ARCH) AND (THREADX_ARCH STREQUAL "win64"))
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
endif()
project(threadx_smp_test LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
# Set build configurations
set(BUILD_CONFIGURATIONS default_build_coverage
disable_notify_callbacks_build stack_checking_build stack_checking_rand_fill_build
set(BUILD_CONFIGURATIONS default_build_coverage disable_notify_callbacks_build
stack_checking_build stack_checking_rand_fill_build
trace_build)
set(CMAKE_CONFIGURATION_TYPES
${BUILD_CONFIGURATIONS}
@@ -23,26 +31,31 @@ endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
set(default_build_coverage -DTX_QUEUE_MESSAGE_MAX_SIZE=32)
set(disable_notify_callbacks_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_DISABLE_NOTIFY_CALLBACKS)
set(stack_checking_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_STACK_CHECKING)
set(stack_checking_rand_fill_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_STACK_CHECKING -DTX_ENABLE_RANDOM_NUMBER_STACK_FILLING)
set(trace_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_EVENT_TRACE)
set(default_build_coverage TX_QUEUE_MESSAGE_MAX_SIZE=32)
set(disable_notify_callbacks_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_DISABLE_NOTIFY_CALLBACKS)
set(stack_checking_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING)
set(stack_checking_rand_fill_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING TX_ENABLE_RANDOM_NUMBER_STACK_FILLING)
set(trace_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_EVENT_TRACE)
add_compile_options(
-m32
-std=c99
-ggdb
-g3
-gdwarf-2
-fdiagnostics-color
# -Werror
-DTX_THREAD_SMP_ONLY_CORE_0_DEFAULT
-DTX_SMP_NOT_POSSIBLE
-DTX_REGRESSION_TEST
-DTEST_STACK_SIZE_PRINTF=4096
add_compile_definitions(
TX_THREAD_SMP_ONLY_CORE_0_DEFAULT
TX_SMP_NOT_POSSIBLE
TX_REGRESSION_TEST
TEST_STACK_SIZE_PRINTF=4096
${${CMAKE_BUILD_TYPE}})
add_link_options(-m32)
if(MSVC)
add_compile_options(/W3 /Zi)
add_link_options(/DEBUG /INCREMENTAL:NO)
else()
add_compile_options(
-m32
-ggdb
-g3
-gdwarf-2
-fdiagnostics-color)
add_link_options(-m32)
endif()
enable_testing()
@@ -52,26 +65,31 @@ add_subdirectory(samples)
# Coverage
if(CMAKE_BUILD_TYPE MATCHES ".*_coverage")
target_compile_options(threadx_smp PRIVATE -fprofile-arcs -ftest-coverage)
target_link_options(threadx_smp PRIVATE -fprofile-arcs -ftest-coverage)
if(NOT MSVC)
target_compile_options(threadx_smp PRIVATE -fprofile-arcs -ftest-coverage)
target_link_options(threadx_smp PRIVATE -fprofile-arcs -ftest-coverage)
endif()
endif()
target_compile_options(
threadx_smp
PRIVATE # -Werror
-Wall
-Wextra
-pedantic
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-Wunused
-Wuninitialized
-Wmissing-declarations
-Wconversion
-Wpointer-arith
# -Wshadow
-Wlogical-op
-Waggregate-return
-Wfloat-equal)
if(MSVC)
target_compile_options(threadx_smp PRIVATE /W3)
else()
target_compile_options(
threadx_smp
PRIVATE
-Wall
-Wextra
-pedantic
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-Wunused
-Wuninitialized
-Wmissing-declarations
-Wconversion
-Wpointer-arith
-Wlogical-op
-Waggregate-return
-Wfloat-equal)
endif()
+32 -8
View File
@@ -4,6 +4,16 @@ cmake_policy(SET CMP0057 NEW)
project(regression_test LANGUAGES C)
set(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../regression)
set(REPO_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../../..)
set(PORT_LOW_LEVEL_SOURCE ${REPO_ROOT}/ports_smp/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/src/tx_initialize_low_level.c)
set(GENERATED_LOW_LEVEL_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/tx_initialize_low_level.c)
set(TESTCONTROL_WEAK_DEFAULTS_SOURCE ${REPO_ROOT}/test/shared/regression/testcontrol_weak_defaults.c)
include_directories(${REPO_ROOT}/test/tx/regression)
if(NOT EXISTS ${PORT_LOW_LEVEL_SOURCE})
message(FATAL_ERROR "Unable to locate tx_initialize_low_level.c for ${THREADX_ARCH}/${THREADX_TOOLCHAIN}")
endif()
set(regression_test_cases
${SOURCE_DIR}/threadx_block_memory_basic_test.c
@@ -117,18 +127,32 @@ set(regression_test_cases
${SOURCE_DIR}/threadx_initialize_kernel_setup_test.c)
add_custom_command(
OUTPUT ${SOURCE_DIR}/tx_initialize_low_level.c
COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.sh
OUTPUT ${GENERATED_LOW_LEVEL_SOURCE}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_FILE=${PORT_LOW_LEVEL_SOURCE}
-DOUTPUT_FILE=${GENERATED_LOW_LEVEL_SOURCE}
-P ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.cmake
DEPENDS ${PORT_LOW_LEVEL_SOURCE} ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.cmake
COMMENT "Generating tx_initialize_low_level.c for test")
add_library(test_utility ${SOURCE_DIR}/tx_initialize_low_level.c
${SOURCE_DIR}/testcontrol.c)
target_link_libraries(test_utility PUBLIC azrtos::threadx_smp)
target_compile_definitions(test_utility PUBLIC CTEST BATCH_TEST)
add_library(test_utility OBJECT ${GENERATED_LOW_LEVEL_SOURCE}
${SOURCE_DIR}/testcontrol.c
${TESTCONTROL_WEAK_DEFAULTS_SOURCE})
target_link_libraries(test_utility PRIVATE azrtos::threadx_smp)
target_compile_definitions(test_utility PRIVATE CTEST BATCH_TEST
TEST_STACK_SIZE_PRINTF=4096)
foreach(test_case ${regression_test_cases})
get_filename_component(test_name ${test_case} NAME_WE)
add_executable(${test_name} ${test_case})
target_link_libraries(${test_name} PRIVATE test_utility)
if(test_name STREQUAL "threadx_initialize_kernel_setup_test")
add_executable(${test_name} ${test_case})
else()
add_executable(${test_name} ${test_case} $<TARGET_OBJECTS:test_utility>)
target_compile_definitions(${test_name} PRIVATE CTEST BATCH_TEST
TEST_STACK_SIZE_PRINTF=4096)
endif()
target_link_libraries(${test_name} PRIVATE azrtos::threadx_smp)
add_test(${CMAKE_BUILD_TYPE}::${test_name} ${test_name})
endforeach()
@@ -0,0 +1,44 @@
if(NOT DEFINED SOURCE_FILE)
message(FATAL_ERROR "SOURCE_FILE is required")
endif()
if(NOT DEFINED OUTPUT_FILE)
message(FATAL_ERROR "OUTPUT_FILE is required")
endif()
file(STRINGS "${SOURCE_FILE}" FILE_LINES)
set(UPDATED_FILE_CONTENTS "")
set(DISPATCH_DECLARATION "VOID test_interrupt_dispatch(VOID);")
set(DISPATCH_CALL "test_interrupt_dispatch();")
set(DECLARATION_INSERTED FALSE)
set(CALL_INSERTED FALSE)
foreach(FILE_LINE IN LISTS FILE_LINES)
if((NOT DECLARATION_INSERTED) AND
((FILE_LINE MATCHES "^void[ \t]+\\*_tx_linux_timer_interrupt\\(void \\*p\\);[ \t]*$")
OR
(FILE_LINE MATCHES "^VOID[ \t]+_tx_win32_timer_interrupt\\(VOID\\);[ \t]*$")
OR
(FILE_LINE MATCHES "^VOID CALLBACK[ \t]+_tx_win32_timer_interrupt\\(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2\\);[ \t]*$")))
string(APPEND UPDATED_FILE_CONTENTS "${FILE_LINE}\n${DISPATCH_DECLARATION}\n")
set(DECLARATION_INSERTED TRUE)
elseif((NOT CALL_INSERTED) AND (FILE_LINE MATCHES "^([ \t]*)_tx_timer_interrupt\\(\\);[ \t]*$"))
string(APPEND UPDATED_FILE_CONTENTS "${CMAKE_MATCH_1}${DISPATCH_CALL}\n${FILE_LINE}\n")
set(CALL_INSERTED TRUE)
else()
string(APPEND UPDATED_FILE_CONTENTS "${FILE_LINE}\n")
endif()
endforeach()
if(NOT CALL_INSERTED)
message(FATAL_ERROR "Unable to insert test interrupt dispatcher call into ${SOURCE_FILE}")
endif()
if(NOT DECLARATION_INSERTED)
message(FATAL_ERROR "Unable to insert test interrupt dispatcher declaration into ${SOURCE_FILE}")
endif()
get_filename_component(OUTPUT_DIRECTORY "${OUTPUT_FILE}" DIRECTORY)
file(MAKE_DIRECTORY "${OUTPUT_DIRECTORY}")
file(WRITE "${OUTPUT_FILE}" "${UPDATED_FILE_CONTENTS}")
+12 -7
View File
@@ -1,11 +1,5 @@
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
# Set up the project
project(threadx_smp
VERSION 6.0.0
LANGUAGES C ASM
)
if(NOT DEFINED THREADX_ARCH)
message(FATAL_ERROR "Error: THREADX_ARCH not defined")
endif()
@@ -13,6 +7,17 @@ if(NOT DEFINED THREADX_TOOLCHAIN)
message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined")
endif()
set(THREADX_SMP_PROJECT_LANGUAGES C)
if(NOT ((THREADX_ARCH STREQUAL "win64") AND (THREADX_TOOLCHAIN STREQUAL "vs_2022")))
list(APPEND THREADX_SMP_PROJECT_LANGUAGES ASM)
endif()
# Set up the project
project(threadx_smp
VERSION 6.0.0
LANGUAGES ${THREADX_SMP_PROJECT_LANGUAGES}
)
set(PROJECT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
# Define our target library and an alias for consumers
@@ -57,4 +62,4 @@ set(CPACK_SOURCE_IGNORE_FILES
".*~$"
)
set(CPACK_VERBATIM_VARIABLES YES)
include(CPack)
include(CPack)
@@ -0,0 +1,29 @@
set(CURRENT_DIR ${PROJECT_DIR}/ports_smp/win64/vs_2022)
target_sources(${PROJECT_NAME}
PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CURRENT_DIR}/src/tx_initialize_low_level.c
${CURRENT_DIR}/src/tx_thread_context_restore.c
${CURRENT_DIR}/src/tx_thread_context_save.c
${CURRENT_DIR}/src/tx_thread_interrupt_control.c
${CURRENT_DIR}/src/tx_thread_schedule.c
${CURRENT_DIR}/src/tx_thread_smp_core_get.c
${CURRENT_DIR}/src/tx_thread_smp_core_preempt.c
${CURRENT_DIR}/src/tx_thread_smp_current_state_get.c
${CURRENT_DIR}/src/tx_thread_smp_current_thread_get.c
${CURRENT_DIR}/src/tx_thread_smp_initialize_wait.c
${CURRENT_DIR}/src/tx_thread_smp_low_level_initialize.c
${CURRENT_DIR}/src/tx_thread_smp_protect.c
${CURRENT_DIR}/src/tx_thread_smp_time_get.c
${CURRENT_DIR}/src/tx_thread_smp_unprotect.c
${CURRENT_DIR}/src/tx_thread_stack_build.c
${CURRENT_DIR}/src/tx_thread_system_return.c
${CURRENT_DIR}/src/tx_timer_interrupt.c
# {{END_TARGET_SOURCES}}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CURRENT_DIR}/inc
)
+54 -55
View File
@@ -1,4 +1,5 @@
/* This is the test control routine of the ThreadX kernel. All tests are dispatched from this routine. */
// Some portions generated by Codex (gpt 5.5).
#define TX_THREAD_SMP_SOURCE_CODE
@@ -1355,6 +1356,10 @@ UINT i;
/* Clear the ISR dispatch. */
test_isr_dispatch = TX_NULL;
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_reset();
#endif
/* Dispatch the test. */
(test_control_tests[i++].test_entry)(test_free_memory_ptr);
@@ -1435,6 +1440,10 @@ UINT old_posture = TX_INT_ENABLE;
test_control_system_errors++;
}
#ifdef TX_WIN32_PROFILE_ENABLE
_tx_win32_profile_report("smp_test");
#endif
/* Resume the control thread to fully exit the test. */
tx_thread_resume(&test_control_thread);
}
@@ -1447,6 +1456,51 @@ TX_MUTEX *mutex_ptr;
TX_THREAD *thread_ptr;
/* Delete all threads, except for timer thread, and test control thread.
This ensures application-owned objects are no longer referenced before
the object cleanup loops below attempt to delete them. */
while (_tx_thread_created_ptr)
{
/* Setup working pointer. */
thread_ptr = _tx_thread_created_ptr;
#ifdef TX_TIMER_PROCESS_IN_ISR
/* Determine if there are more threads to delete. */
if (_tx_thread_created_count == 1)
break;
/* Determine if this thread is the test control thread. */
if (thread_ptr == &test_control_thread)
{
/* Move to the next thread pointer. */
thread_ptr = thread_ptr -> tx_thread_created_next;
}
#else
/* Determine if there are more threads to delete. */
if (_tx_thread_created_count == 2)
break;
/* Move to the thread not protected. */
while ((thread_ptr == &_tx_timer_thread) || (thread_ptr == &test_control_thread))
{
/* Yes, move to the next thread. */
thread_ptr = thread_ptr -> tx_thread_created_next;
}
#endif
/* First terminate the thread to ensure it is ready for deletion. */
tx_thread_terminate(thread_ptr);
/* Delete the thread. */
tx_thread_delete(thread_ptr);
}
/* Delete all queues. */
while(_tx_queue_created_ptr)
{
@@ -1524,49 +1578,6 @@ TX_THREAD *thread_ptr;
tx_mutex_delete(mutex_ptr);
}
/* Delete all threads, except for timer thread, and test control thread. */
while (_tx_thread_created_ptr)
{
/* Setup working pointer. */
thread_ptr = _tx_thread_created_ptr;
#ifdef TX_TIMER_PROCESS_IN_ISR
/* Determine if there are more threads to delete. */
if (_tx_thread_created_count == 1)
break;
/* Determine if this thread is the test control thread. */
if (thread_ptr == &test_control_thread)
{
/* Move to the next thread pointer. */
thread_ptr = thread_ptr -> tx_thread_created_next;
}
#else
/* Determine if there are more threads to delete. */
if (_tx_thread_created_count == 2)
break;
/* Move to the thread not protected. */
while ((thread_ptr == &_tx_timer_thread) || (thread_ptr == &test_control_thread))
{
/* Yes, move to the next thread. */
thread_ptr = thread_ptr -> tx_thread_created_next;
}
#endif
/* First terminate the thread to ensure it is ready for deletion. */
tx_thread_terminate(thread_ptr);
/* Delete the thread. */
tx_thread_delete(thread_ptr);
}
/* At this point, only the test control thread and the system timer thread and/or mutex should still be
in the system. */
}
@@ -1609,15 +1620,3 @@ void test_exit_notify(TX_THREAD *thread_ptr, UINT type)
/* Clear the suspending flag to short-circuit the suspension. */
thread_ptr -> tx_thread_suspending = TX_FALSE;
}
__attribute__((weak)) void abort_all_threads_suspended_on_mutex(void)
{
}
__attribute__((weak)) void suspend_lowest_priority(void)
{
}
__attribute__((weak)) void abort_and_resume_byte_allocating_thread(void)
{
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
typedef struct BLOCK_MEMORY_TEST_STRUCT
{
@@ -86,7 +87,7 @@ CHAR *pointer;
/* Attempt to create a block pool from a timer. */
pointer = (CHAR *) 0x30000;
status = tx_block_pool_create(&pool_3, "pool 3", 100, pointer, 320);
status = tx_block_pool_create(&pool_3, "pool 3", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -146,7 +147,7 @@ UINT status;
}
/* Attempt to create a block pool from an ISR. */
status = tx_block_pool_create(&pool_3, "pool 3", 100, (void *) 0x100000, 320);
status = tx_block_pool_create(&pool_3, "pool 3", 100, (void *) 0x100000, TX_TEST_BLOCK_POOL_BYTES(100, 3));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -217,8 +218,8 @@ CHAR *pointer;
}
/* Create block pools 0 and 1. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -228,8 +229,8 @@ CHAR *pointer;
test_control_return(1);
}
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -241,7 +242,7 @@ CHAR *pointer;
/* Check the no-blocks path. */
status = _tx_block_pool_create(&pool_2, "pool 2", 100, pointer, 50);
pointer = pointer + 320;
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SIZE_ERROR)
@@ -265,7 +266,7 @@ CHAR *pointer_2;
CHAR *pointer_3;
CHAR *pointer_4;
INT i;
unsigned long fake_block[20];
TX_TEST_POINTER_WORD fake_block[20];
/* Inform user. */
@@ -316,7 +317,7 @@ unsigned long fake_block[20];
/* Try to release a block that points to a non-pool. */
fake_block[0] = 0;
fake_block[1] = (unsigned long) &fake_block[0];
TX_TEST_STORE_POINTER(fake_block[1], &fake_block[0]);
status = tx_block_release(&fake_block[2]);
/* Check status. */
@@ -519,7 +520,7 @@ unsigned long fake_block[20];
{
/* Block memory error. */
printf("ERROR #20\n");
printf("ERROR #20 (%lu %lu %lu)\n", error, timer_executed, isr_executed);
test_control_return(1);
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -49,18 +50,18 @@ INT status;
pointer = pointer + TEST_STACK_SIZE_PRINTF;
/* Create block pool 0. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
#ifndef TX_DISABLE_ERROR_CHECKING /* skip this test and pretend it passed */
/* Create block pool again to get pool_ptr error. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_POOL_ERROR)
return;
/* Create block pool with NULL pointer. */
status = tx_block_pool_create(TX_NULL, "pool 0", 100, pointer, 320);
status = tx_block_pool_create(TX_NULL, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_POOL_ERROR)
{
@@ -69,7 +70,7 @@ INT status;
}
/* Create block pool pointer if NULL start. */
status = tx_block_pool_create(&pool_1, "pool 0", 100, NULL, 320);
status = tx_block_pool_create(&pool_1, "pool 0", 100, NULL, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_PTR_ERROR)
{
@@ -128,11 +129,11 @@ INT i;
#ifndef TX_DISABLE_ERROR_CHECKING /* skip this test and pretend it passed */
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Attempt to create a pool with an invalid size. */
status = _txe_block_pool_create(&pool_2, "pool 2", 100, pointer, 320, 777777);
status = _txe_block_pool_create(&pool_2, "pool 2", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3), 777777);
if (status != TX_POOL_ERROR)
{
@@ -384,4 +385,3 @@ INT i;
printf("SUCCESS!\n");
test_control_return(0);
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -83,8 +84,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -308,4 +309,3 @@ CHAR *pointer_1;
}
}
@@ -1,7 +1,10 @@
/* This test is designed to test timeouts on suspension on memory block pools. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -84,8 +87,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -135,15 +138,15 @@ CHAR *pointer_3;
/* Set all the memory of the blocks. */
TX_MEMSET(pointer_3, (CHAR) 0xEF, 100);
/* Sleep for 64 ticks to allow the other thread 6 timeouts on the block
pool. */
/* Sleep long enough to allow the other threads to complete their expected
timeout cycles on the block pool. */
tx_thread_sleep(64);
/* Incrment the run counter. */
thread_0_counter++;
/* Check the counter of the other thread. */
if ((thread_1_counter != 6) || (thread_2_counter != 3))
if ((thread_1_counter != 6UL) || (thread_2_counter != 3UL))
{
/* Block memory error. */
@@ -209,4 +212,3 @@ CHAR *pointer_1;
thread_2_counter++;
}
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -69,8 +70,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
pointer = pointer + 320;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -182,4 +183,3 @@ CHAR *pointer_1;
thread_1_counter++;
}
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
typedef struct BYTE_MEMORY_TEST_STRUCT
{
@@ -91,7 +92,7 @@ CHAR *pointer;
/* Attempt to create a byte pool from a timer. */
pointer = (CHAR *) 0x30000;
status = tx_byte_pool_create(&pool_2, "pool 2", pointer, 108);
status = tx_byte_pool_create(&pool_2, "pool 2", pointer, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -103,7 +104,7 @@ CHAR *pointer;
/* Attempt to create a byte pool with an invalid size. */
status = _txe_byte_pool_create(&pool_3, "pool 3", pointer,
108, (sizeof(TX_BYTE_POOL)+1));
TX_TEST_BYTE_POOL_BYTES(108), (sizeof(TX_BYTE_POOL)+1));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -186,7 +187,7 @@ UINT status;
/* Attempt to create a byte pool from an ISR. */
status = tx_byte_pool_create(&pool_2, "pool 0", (void *) 0x100000, 108);
status = tx_byte_pool_create(&pool_2, "pool 0", (void *) 0x100000, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -256,8 +257,8 @@ CHAR *pointer;
}
/* Create byte pools 0 and 1. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_CAPACITY_BYTES(24, 3));
pointer = pointer + TX_TEST_BYTE_POOL_CAPACITY_BYTES(24, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -267,8 +268,8 @@ CHAR *pointer;
test_control_return(1);
}
status = tx_byte_pool_create(&pool_1, "pool 1", pointer, 200);
pointer = pointer + 200;
status = tx_byte_pool_create(&pool_1, "pool 1", pointer, TX_TEST_BYTE_POOL_BYTES(200));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(200);
/* Check status. */
if (status != TX_SUCCESS)
@@ -279,9 +280,9 @@ CHAR *pointer;
}
/* Test for search pointer issue on wrapped seach with prior block to search pointer merged. */
status = tx_byte_pool_create(&pool_4, "pool 4", pointer, 300);
status = tx_byte_pool_create(&pool_4, "pool 4", pointer, TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3));
pool_4_memory = pointer;
pointer = pointer + 300;
pointer = pointer + TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -353,7 +354,7 @@ CHAR *pointer_2;
CHAR *pointer_3;
CHAR *pointer_4;
INT i;
ULONG array[20];
TX_TEST_POINTER_WORD array[20];
UCHAR *save_search;
@@ -394,7 +395,7 @@ UCHAR *save_search;
/* Try to create a NULL pool. */
pointer_1 = (CHAR *) 0x30000;
status = tx_byte_pool_create(TX_NULL, "pool 0", pointer_1, 108);
status = tx_byte_pool_create(TX_NULL, "pool 0", pointer_1, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -406,7 +407,7 @@ UCHAR *save_search;
}
/* Try to create the same pool. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer_1, 108);
status = tx_byte_pool_create(&pool_0, "pool 0", pointer_1, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -418,7 +419,7 @@ UCHAR *save_search;
}
/* Try to create a pool with a NULL start address. */
status = tx_byte_pool_create(&pool_2, "pool 2", TX_NULL, 108);
status = tx_byte_pool_create(&pool_2, "pool 2", TX_NULL, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_PTR_ERROR)
@@ -626,7 +627,7 @@ UCHAR *save_search;
/* Test another bad block release.... pool pointer is not a valid pool! */
array[0] = 0;
array[1] = (ULONG) &array[3];
TX_TEST_STORE_POINTER(array[1], &array[3]);
array[2] = 0;
array[3] = 0;
status = _tx_byte_release(&array[2]);
@@ -865,7 +866,7 @@ UCHAR *save_search;
}
/* Move the search pointer to the third block to exercise that code in the byte search algorithm. */
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3-8;
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - TX_TEST_BYTE_POOL_SEARCH_OFFSET;
/* Now allocate the block again. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer_2, 24, TX_NO_WAIT);
@@ -885,7 +886,7 @@ UCHAR *save_search;
status += tx_byte_release(pointer_1);
/* Move the search pointer to the third block to exercise that code in the byte search algorithm. */
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3-8;
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - TX_TEST_BYTE_POOL_SEARCH_OFFSET;
/* Allocate a large block to force the search pointer update. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer_3, 88, TX_NO_WAIT);
@@ -961,7 +962,7 @@ UCHAR *save_search;
}
/* Create pool 4. */
status = tx_byte_pool_create(&pool_4, "pool 4", pool_4_memory, 300);
status = tx_byte_pool_create(&pool_4, "pool 4", pool_4_memory, TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3));
/* Check status. */
if (status != TX_SUCCESS)
@@ -1061,4 +1062,3 @@ UCHAR *save_search;
printf("SUCCESS!\n");
test_control_return(0);
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
#include "tx_byte_pool.h"
@@ -193,7 +194,7 @@ CHAR *pointer;
}
/* Create the byte_pool with one byte. */
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, 100);
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(100));
pointer = pointer + 100;
/* Check for status. */
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
/* Define the ISR dispatch. */
@@ -197,7 +198,7 @@ CHAR *pointer;
}
/* Create the byte_pool with one byte. */
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, 100);
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(100));
pointer = pointer + 100;
/* Check for status. */
@@ -495,4 +496,3 @@ VOID *pointer;
thread_6_counter++;
}
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -121,8 +122,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -1,7 +1,10 @@
/* This test is designed to test suspension timeout on a memory byte pool. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -85,8 +88,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -126,12 +129,12 @@ CHAR *pointer;
test_control_return(1);
}
/* Sleep to allow the other thread to suspend and timeout on the memory
pool once. */
/* Sleep long enough to allow the other threads to complete their expected
timeout cycles on the byte pool. */
tx_thread_sleep(64);
/* Check the counter of the other thread. */
if ((thread_1_counter != 6) || (thread_2_counter != 3))
if ((thread_1_counter != 6UL) || (thread_2_counter != 3UL))
{
/* Block memory error. */
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -89,8 +90,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Save off the intial pool size. */
initial_pool_size = pool_0.tx_byte_pool_available;
@@ -126,7 +127,6 @@ CHAR *pointer;
while(1)
{
/* Allocate memory from the pool. This size will cause merge activity
because the search pointer will sit in this large block about half
the time. */
@@ -195,10 +195,8 @@ static void thread_1_entry(ULONG thread_input)
UINT status;
CHAR *pointer;
while(test_done == TX_FALSE)
{
/* Allocate memory from the pool. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer, 30, TX_WAIT_FOREVER);
@@ -228,10 +226,8 @@ static void thread_2_entry(ULONG thread_input)
UINT status;
CHAR *pointer;
while(test_done == TX_FALSE)
{
/* Allocate memory from the pool. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer, 12, TX_WAIT_FOREVER);
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -68,8 +69,8 @@ CHAR *pointer;
}
/* Create byte pools 0 and 1. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -174,4 +175,3 @@ CHAR *pointer;
thread_1_counter++;
}
}
@@ -240,14 +240,12 @@ ULONG actual;
/* Inform user. */
printf("Running Event Flag Set/Clear from ISR Test.......................... ");
/* Setup the test ISR. */
test_isr_dispatch = test_isr;
/* Loop to exploit the probability window inside tx_event_flags_set call. */
while (condition_count < 40)
{
/* Suspend on the event_flags that is going to be set via the ISR. */
status = tx_event_flags_get(&event_flags_0, 2, TX_OR_CLEAR, &actual, 4);
@@ -354,5 +352,3 @@ static void timer_0_entry(ULONG input)
{
timer_0_counter++;
}
@@ -32,7 +32,6 @@ static unsigned long condition_count = 0;
static TX_EVENT_FLAGS_GROUP event_flags_0;
/* Define thread prototypes. */
static void thread_0_entry(ULONG thread_input);
@@ -33,18 +33,6 @@ UINT mutex_priority_change_extension_selection;
UINT priority_change_extension_selection;
__attribute__((weak)) void abort_all_threads_suspended_on_mutex(void)
{
}
__attribute__((weak)) void suspend_lowest_priority(void)
{
}
__attribute__((weak)) void abort_and_resume_byte_allocating_thread(void)
{
}
void main()
{
@@ -80,4 +68,4 @@ void delete_timer_thread(void)
_tx_thread_delete(&_tx_timer_thread);
}
#endif
#endif
@@ -1,7 +1,9 @@
/* Define the ThreadX SMP random resume/suspend/exclude/pt test. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include "tx_api.h"
#include "tx_thread.h"
//#define MAX_PASSES 50000000
//#define MAX_PASSES 50000
@@ -2370,4 +2370,3 @@ TX_THREAD *thread_ptr;
tx_thread_suspend(thread_ptr);
}
}
@@ -2325,5 +2325,3 @@ static void thread_entry(ULONG id)
tx_thread_suspend(_smp_randomized_source_array[id]);
}
}
@@ -362,4 +362,3 @@ static void thread_31h_entry(ULONG thread_input)
thread_31h_counter++;
}
}
@@ -1,5 +1,7 @@
/* Define the ThreadX SMP time-slice test. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include "tx_api.h"
@@ -243,7 +245,7 @@ UINT status;
status += tx_thread_resume(&thread_31g);
status += tx_thread_resume(&thread_31h);
/* Now sleep for 20 ticks to let see if all the threads execute. */
/* Sleep long enough to see if all the threads execute. */
tx_thread_sleep(20);
/* Now check and make sure all the threads ran. */
@@ -358,4 +360,3 @@ static void thread_31h_entry(ULONG thread_input)
thread_31h_counter++;
}
}
@@ -11,6 +11,7 @@
#include "tx_queue.h"
#include "tx_semaphore.h"
#include "tx_thread.h"
#include "tx_timer.h"
typedef struct THREAD_MEMORY_TEST_STRUCT
@@ -33,6 +34,7 @@ static THREAD_MEMORY_TEST thread_memory;
/* Define the ISR dispatch. */
extern VOID (*test_isr_dispatch)(void);
extern TX_TIMER_INTERNAL *_tx_timer_expired_timer_ptr;
static unsigned long thread_0_counter = 0;
@@ -314,7 +316,22 @@ VOID (*temp_mutex_release)(TX_THREAD *thread_ptr);
test_thread.tx_thread_timer.tx_timer_internal_list_head = TX_NULL;
test_thread.tx_thread_suspending = TX_TRUE;
test_thread.tx_thread_delayed_suspend = TX_TRUE;
#if defined(_WIN64)
{
TX_TIMER_INTERNAL timeout_timer;
TX_TIMER_INTERNAL *saved_expired_timer_ptr;
TX_MEMSET(&timeout_timer, 0, sizeof(TX_TIMER_INTERNAL));
saved_expired_timer_ptr = _tx_timer_expired_timer_ptr;
_tx_timer_expired_timer_ptr = &timeout_timer;
timeout_timer.tx_timer_internal_extension_ptr = (VOID *) &test_thread;
_tx_thread_timeout(0);
_tx_timer_expired_timer_ptr = saved_expired_timer_ptr;
}
#else
_tx_thread_timeout((ULONG) &test_thread);
#endif
/* Setup test thread to make sure _tx_thread_terminate can handle a NULL mutex release function pointer. */
temp_mutex_release = _tx_thread_mutex_release;
@@ -227,7 +227,6 @@ UINT status;
/* Inform user. */
printf("Running Thread Delayed Suspension Clearing Test..................... ");
/* Relinquish to the other thread. */
tx_thread_relinquish();
@@ -270,7 +269,6 @@ UINT status;
/* Wait until we see the delayed suspension set flag. */
while(delayed_suspend_set == 0)
{
/* Abort the suspension for thread 2. */
tx_thread_wait_abort(&thread_2);
@@ -1,5 +1,7 @@
/* This test is designed to test multiple threads sleeping for 33 ticks. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include "tx_api.h"
@@ -154,14 +156,14 @@ static void thread_2_entry(ULONG thread_input)
static void thread_3_entry(ULONG thread_input)
{
/* Inform user. */
printf("Running Thread Multiple Thread Sleep for 33 Test.................... ");
/* Clear the tick count. */
tx_time_set(0);
/* Sleep for 100 ticks (+1 in case tick before threads 0,1,2 have run). */
/* Sleep for the target interval, with one extra tick in the default case
in case the first tick arrives before threads 0, 1, and 2 have run. */
tx_thread_sleep(101);
/* Determine if the sleep was accurate. */
@@ -181,4 +183,3 @@ static void thread_3_entry(ULONG thread_input)
test_control_return(1);
}
}
@@ -218,7 +218,6 @@ CHAR *pointer;
static void thread_0_entry(ULONG thread_input)
{
/* Check for correct input value and execution of other threads. */
if ((thread_input != 0) || (thread_1_counter) || (thread_2_counter) ||
(thread_3_counter))
@@ -234,7 +233,6 @@ static void thread_0_entry(ULONG thread_input)
static void thread_1_entry(ULONG thread_input)
{
/* Check for correct input value and execution of other threads. */
if ((thread_input != 1) || (thread_0_counter != 1) || (thread_2_counter) ||
(thread_3_counter))
@@ -250,7 +248,6 @@ static void thread_1_entry(ULONG thread_input)
static void thread_2_entry(ULONG thread_input)
{
/* Check for correct input value and execution of other threads. */
if ((thread_input != 2) || (thread_0_counter != 1) || (thread_1_counter != 1) ||
(thread_3_counter))
@@ -455,5 +452,3 @@ static void thread_9_entry(ULONG thread_input)
tx_thread_relinquish();
}
}
@@ -311,7 +311,6 @@ volatile ULONG value = 0;
#endif
while (isr_test_suspend_interrupted_condition != TX_TRUE)
{
/* Sleep to get a frest timer slot. */
tx_thread_sleep(1);
@@ -432,4 +431,3 @@ volatile ULONG value = 0;
test_control_return(0);
}
}
@@ -269,4 +269,3 @@ static void timer_0_entry(ULONG input)
{
timer_0_counter++;
}
@@ -183,4 +183,3 @@ static void timer_2_expiration(ULONG timer_input)
/* Process timer expiration. */
timer_2_counter++;
}
@@ -596,7 +596,6 @@ ULONG exclusion_map;
/* Create a timer for the test. */
tx_timer_create(&timer_0, "timer 0", timer_entry, 0, 1, 1, TX_AUTO_ACTIVATE);
/* Setup the ISR. */
test_isr_dispatch = test_isr;
+57 -37
View File
@@ -2,8 +2,16 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0057 NEW)
if((DEFINED THREADX_ARCH) AND ((THREADX_ARCH STREQUAL "win32") OR (THREADX_ARCH STREQUAL "win64")))
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
endif()
project(threadx_test LANGUAGES C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
# Set build configurations
set(BUILD_CONFIGURATIONS default_build_coverage disable_notify_callbacks_build
stack_checking_build stack_checking_rand_fill_build trace_build)
@@ -22,24 +30,30 @@ endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
set(default_build_coverage -DTX_QUEUE_MESSAGE_MAX_SIZE=32)
set(disable_notify_callbacks_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_DISABLE_NOTIFY_CALLBACKS)
set(stack_checking_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_STACK_CHECKING)
set(stack_checking_rand_fill_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_STACK_CHECKING -DTX_ENABLE_RANDOM_NUMBER_STACK_FILLING)
set(trace_build -DTX_QUEUE_MESSAGE_MAX_SIZE=32 -DTX_ENABLE_EVENT_TRACE)
set(default_build_coverage TX_QUEUE_MESSAGE_MAX_SIZE=32)
set(disable_notify_callbacks_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_DISABLE_NOTIFY_CALLBACKS)
set(stack_checking_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING)
set(stack_checking_rand_fill_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING TX_ENABLE_RANDOM_NUMBER_STACK_FILLING)
set(trace_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_EVENT_TRACE)
add_compile_options(
-m32
-std=c99
-ggdb
-g3
-gdwarf-2
-fdiagnostics-color
-Werror
-DTX_REGRESSION_TEST
-DTEST_STACK_SIZE_PRINTF=4096
add_compile_definitions(
TX_REGRESSION_TEST
TEST_STACK_SIZE_PRINTF=4096
${${CMAKE_BUILD_TYPE}})
add_link_options(-m32)
if(MSVC)
add_compile_options(/W3 /Zi)
add_link_options(/DEBUG /INCREMENTAL:NO)
else()
add_compile_options(
-m32
-ggdb
-g3
-gdwarf-2
-fdiagnostics-color
-Werror)
add_link_options(-m32)
endif()
enable_testing()
@@ -49,26 +63,32 @@ add_subdirectory(samples)
# Coverage
if(CMAKE_BUILD_TYPE MATCHES ".*_coverage")
target_compile_options(threadx PRIVATE -fprofile-arcs -ftest-coverage)
target_link_options(threadx PRIVATE -fprofile-arcs -ftest-coverage)
if(NOT MSVC)
target_compile_options(threadx PRIVATE -fprofile-arcs -ftest-coverage)
target_link_options(threadx PRIVATE -fprofile-arcs -ftest-coverage)
endif()
endif()
target_compile_options(
threadx
PRIVATE -Werror
-Wall
-Wextra
-pedantic
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-Wunused
-Wuninitialized
-Wmissing-declarations
-Wconversion
-Wpointer-arith
# -Wshadow
-Wlogical-op
-Waggregate-return
-Wfloat-equal)
if(MSVC)
target_compile_options(threadx PRIVATE /W3)
else()
target_compile_options(
threadx
PRIVATE -Werror
-Wall
-Wextra
-pedantic
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-Wunused
-Wuninitialized
-Wmissing-declarations
-Wconversion
-Wpointer-arith
# -Wshadow
-Wlogical-op
-Waggregate-return
-Wfloat-equal)
endif()
+30 -9
View File
@@ -4,6 +4,14 @@ cmake_policy(SET CMP0057 NEW)
project(regression_test LANGUAGES C)
set(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../regression)
set(REPO_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../../..)
set(PORT_LOW_LEVEL_SOURCE ${REPO_ROOT}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/src/tx_initialize_low_level.c)
set(GENERATED_LOW_LEVEL_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/tx_initialize_low_level.c)
set(TESTCONTROL_WEAK_DEFAULTS_SOURCE ${REPO_ROOT}/test/shared/regression/testcontrol_weak_defaults.c)
if(NOT EXISTS ${PORT_LOW_LEVEL_SOURCE})
message(FATAL_ERROR "Unable to locate tx_initialize_low_level.c for ${THREADX_ARCH}/${THREADX_TOOLCHAIN}")
endif()
set(regression_test_cases
${SOURCE_DIR}/threadx_block_memory_basic_test.c
@@ -104,19 +112,32 @@ set(regression_test_cases
${SOURCE_DIR}/threadx_initialize_kernel_setup_test.c)
add_custom_command(
OUTPUT ${SOURCE_DIR}/tx_initialize_low_level.c
COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.sh
OUTPUT ${GENERATED_LOW_LEVEL_SOURCE}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_FILE=${PORT_LOW_LEVEL_SOURCE}
-DOUTPUT_FILE=${GENERATED_LOW_LEVEL_SOURCE}
-P ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.cmake
DEPENDS ${PORT_LOW_LEVEL_SOURCE} ${CMAKE_CURRENT_LIST_DIR}/generate_test_file.cmake
COMMENT "Generating tx_initialize_low_level.c for test")
add_library(test_utility ${SOURCE_DIR}/tx_initialize_low_level.c
${SOURCE_DIR}/testcontrol.c)
target_link_libraries(test_utility PUBLIC azrtos::threadx)
target_compile_definitions(test_utility PUBLIC CTEST BATCH_TEST
TEST_STACK_SIZE_PRINTF=4096)
add_library(test_utility OBJECT ${GENERATED_LOW_LEVEL_SOURCE}
${SOURCE_DIR}/testcontrol.c
${TESTCONTROL_WEAK_DEFAULTS_SOURCE})
target_compile_definitions(test_utility PRIVATE CTEST BATCH_TEST
TEST_STACK_SIZE_PRINTF=4096)
target_link_libraries(test_utility PRIVATE azrtos::threadx)
foreach(test_case ${regression_test_cases})
get_filename_component(test_name ${test_case} NAME_WE)
add_executable(${test_name} ${test_case})
target_link_libraries(${test_name} PRIVATE test_utility)
if(test_name STREQUAL "threadx_initialize_kernel_setup_test")
add_executable(${test_name} ${test_case})
else()
add_executable(${test_name} ${test_case} $<TARGET_OBJECTS:test_utility>)
target_compile_definitions(${test_name} PRIVATE CTEST BATCH_TEST
TEST_STACK_SIZE_PRINTF=4096)
endif()
target_link_libraries(${test_name} PRIVATE azrtos::threadx)
add_test(${CMAKE_BUILD_TYPE}::${test_name} ${test_name})
endforeach()
@@ -0,0 +1,42 @@
if(NOT DEFINED SOURCE_FILE)
message(FATAL_ERROR "SOURCE_FILE is required")
endif()
if(NOT DEFINED OUTPUT_FILE)
message(FATAL_ERROR "OUTPUT_FILE is required")
endif()
file(STRINGS "${SOURCE_FILE}" FILE_LINES)
set(UPDATED_FILE_CONTENTS "")
set(DISPATCH_DECLARATION "VOID test_interrupt_dispatch(VOID);")
set(DISPATCH_CALL "test_interrupt_dispatch();")
set(DECLARATION_INSERTED FALSE)
set(CALL_INSERTED FALSE)
foreach(FILE_LINE IN LISTS FILE_LINES)
if((NOT DECLARATION_INSERTED) AND
((FILE_LINE MATCHES "^void[ \t]+\\*_tx_linux_timer_interrupt\\(void \\*p\\);[ \t]*$")
OR
(FILE_LINE MATCHES "^VOID CALLBACK[ \t]+_tx_win32_timer_interrupt\\(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2\\);[ \t]*$")))
string(APPEND UPDATED_FILE_CONTENTS "${FILE_LINE}\n${DISPATCH_DECLARATION}\n")
set(DECLARATION_INSERTED TRUE)
elseif((NOT CALL_INSERTED) AND (FILE_LINE MATCHES "^([ \t]*)_tx_timer_interrupt\\(\\);[ \t]*$"))
string(APPEND UPDATED_FILE_CONTENTS "${CMAKE_MATCH_1}${DISPATCH_CALL}\n${FILE_LINE}\n")
set(CALL_INSERTED TRUE)
else()
string(APPEND UPDATED_FILE_CONTENTS "${FILE_LINE}\n")
endif()
endforeach()
if(NOT CALL_INSERTED)
message(FATAL_ERROR "Unable to insert test interrupt dispatcher call into ${SOURCE_FILE}")
endif()
if(NOT DECLARATION_INSERTED)
message(FATAL_ERROR "Unable to insert test interrupt dispatcher declaration into ${SOURCE_FILE}")
endif()
get_filename_component(OUTPUT_DIRECTORY "${OUTPUT_FILE}" DIRECTORY)
file(MAKE_DIRECTORY "${OUTPUT_DIRECTORY}")
file(WRITE "${OUTPUT_FILE}" "${UPDATED_FILE_CONTENTS}")
+4 -14
View File
@@ -1,4 +1,5 @@
/* This is the test control routine of the ThreadX kernel. All tests are dispatched from this routine. */
// Some portions generated by Codex (gpt 5.4).
#include "tx_api.h"
#include <stdio.h>
@@ -122,7 +123,6 @@ typedef struct TEST_ENTRY_STRUCT
VOID (*test_entry)(void *);
} TEST_ENTRY;
/* Define the prototypes for the test entry points. */
void threadx_block_memory_basic_application_define(void *);
@@ -483,7 +483,6 @@ UINT i, j;
TX_THREAD *thread_ptr;
#endif
/* Initialize the test error/success counters. */
test_control_successful_tests = 0;
test_control_failed_tests = 0;
@@ -565,6 +564,7 @@ TX_THREAD *thread_ptr;
/* Clear the ISR dispatch. */
test_isr_dispatch = TX_NULL;
/* Ensure that _tx_thread_time_slice can handle NULL thread, note that current thread pointer is NULL at this point. */
_tx_thread_time_slice();
@@ -586,7 +586,7 @@ TX_THREAD *thread_ptr;
init_test_thread.tx_thread_ready_previous = &init_test_thread;
_tx_thread_time_slice();
_tx_thread_current_ptr = TX_NULL;
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Test to make sure _tx_thread_shell_entry can handle a NULL mutex release function pointer. */
temp_mutex_release = _tx_thread_mutex_release;
temp_thread = _tx_thread_execute_ptr;
@@ -605,6 +605,7 @@ TX_THREAD *thread_ptr;
_tx_thread_current_ptr = TX_NULL;
_tx_thread_execute_ptr = temp_thread;
_tx_thread_mutex_release = temp_mutex_release; /* Recover Mutex release pointer. */
#endif
/* Test _tx_thread_system_suspend when not current, preemption is needed but disabled. */
temp_thread = _tx_thread_execute_ptr;
@@ -1413,14 +1414,3 @@ void test_exit_notify(TX_THREAD *thread_ptr, UINT type)
}
__attribute__((weak)) void abort_all_threads_suspended_on_mutex(void)
{
}
__attribute__((weak)) void suspend_lowest_priority(void)
{
}
__attribute__((weak)) void abort_and_resume_byte_allocating_thread(void)
{
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
typedef struct BLOCK_MEMORY_TEST_STRUCT
{
@@ -86,7 +87,7 @@ CHAR *pointer;
/* Attempt to create a block pool from a timer. */
pointer = (CHAR *) 0x30000;
status = tx_block_pool_create(&pool_3, "pool 3", 100, pointer, 320);
status = tx_block_pool_create(&pool_3, "pool 3", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -146,7 +147,7 @@ UINT status;
}
/* Attempt to create a block pool from an ISR. */
status = tx_block_pool_create(&pool_3, "pool 3", 100, (void *) 0x100000, 320);
status = tx_block_pool_create(&pool_3, "pool 3", 100, (void *) 0x100000, TX_TEST_BLOCK_POOL_BYTES(100, 3));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -217,8 +218,8 @@ CHAR *pointer;
}
/* Create block pools 0 and 1. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -228,8 +229,8 @@ CHAR *pointer;
test_control_return(1);
}
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -265,7 +266,7 @@ CHAR *pointer_2;
CHAR *pointer_3;
CHAR *pointer_4;
INT i;
unsigned long fake_block[20];
TX_TEST_POINTER_WORD fake_block[20];
/* Inform user. */
@@ -316,7 +317,7 @@ unsigned long fake_block[20];
/* Try to release a block that points to a non-pool. */
fake_block[0] = 0;
fake_block[1] = (unsigned long) &fake_block[0];
TX_TEST_STORE_POINTER(fake_block[1], &fake_block[0]);
status = tx_block_release(&fake_block[2]);
/* Check status. */
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -49,18 +50,18 @@ INT status;
pointer = pointer + TEST_STACK_SIZE_PRINTF;
/* Create block pool 0. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
#ifndef TX_DISABLE_ERROR_CHECKING /* skip this test and pretend it passed */
/* Create block pool again to get pool_ptr error. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 320);
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_POOL_ERROR)
return;
/* Create block pool with NULL pointer. */
status = tx_block_pool_create(TX_NULL, "pool 0", 100, pointer, 320);
status = tx_block_pool_create(TX_NULL, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_POOL_ERROR)
{
@@ -69,7 +70,7 @@ INT status;
}
/* Create block pool pointer if NULL start. */
status = tx_block_pool_create(&pool_1, "pool 0", 100, NULL, 320);
status = tx_block_pool_create(&pool_1, "pool 0", 100, NULL, TX_TEST_BLOCK_POOL_BYTES(100, 3));
if (status != TX_PTR_ERROR)
{
@@ -128,11 +129,11 @@ INT i;
#ifndef TX_DISABLE_ERROR_CHECKING /* skip this test and pretend it passed */
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_1, "pool 1", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Attempt to create a pool with an invalid size. */
status = _txe_block_pool_create(&pool_2, "pool 2", 100, pointer, 320, 777777);
status = _txe_block_pool_create(&pool_2, "pool 2", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3), 777777);
if (status != TX_POOL_ERROR)
{
@@ -384,4 +385,3 @@ INT i;
printf("SUCCESS!\n");
test_control_return(0);
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -83,8 +84,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -308,4 +309,3 @@ CHAR *pointer_1;
}
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -84,8 +85,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -209,4 +210,3 @@ CHAR *pointer_1;
thread_2_counter++;
}
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -69,8 +70,8 @@ CHAR *pointer;
}
/* Create block pool. */
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, 340);
pointer = pointer + 340;
status = tx_block_pool_create(&pool_0, "pool 0", 100, pointer, TX_TEST_BLOCK_POOL_BYTES(100, 3));
pointer = pointer + TX_TEST_BLOCK_POOL_BYTES(100, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -182,4 +183,3 @@ CHAR *pointer_1;
thread_1_counter++;
}
}
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
/* Per-allocation overhead in byte pools: next pointer + ALIGN_TYPE alignment marker. */
#define BYTE_POOL_OVERHEAD (sizeof(UCHAR *) + sizeof(ALIGN_TYPE))
@@ -100,7 +101,7 @@ CHAR *pointer;
/* Attempt to create a byte pool from a timer. */
pointer = (CHAR *) 0x30000;
status = tx_byte_pool_create(&pool_2, "pool 2", pointer, 108);
status = tx_byte_pool_create(&pool_2, "pool 2", pointer, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -112,7 +113,7 @@ CHAR *pointer;
/* Attempt to create a byte pool with an invalid size. */
status = _txe_byte_pool_create(&pool_3, "pool 3", pointer,
108, (sizeof(TX_BYTE_POOL)+1));
TX_TEST_BYTE_POOL_BYTES(108), (sizeof(TX_BYTE_POOL)+1));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -195,7 +196,7 @@ UINT status;
/* Attempt to create a byte pool from an ISR. */
status = tx_byte_pool_create(&pool_2, "pool 0", (void *) 0x100000, 108);
status = tx_byte_pool_create(&pool_2, "pool 0", (void *) 0x100000, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_CALLER_ERROR)
@@ -265,8 +266,8 @@ CHAR *pointer;
}
/* Create byte pools 0 and 1. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, POOL_0_SIZE);
pointer = pointer + POOL_0_SIZE;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_CAPACITY_BYTES(24, 3));
pointer = pointer + TX_TEST_BYTE_POOL_CAPACITY_BYTES(24, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -276,8 +277,8 @@ CHAR *pointer;
test_control_return(1);
}
status = tx_byte_pool_create(&pool_1, "pool 1", pointer, 200);
pointer = pointer + 200;
status = tx_byte_pool_create(&pool_1, "pool 1", pointer, TX_TEST_BYTE_POOL_BYTES(200));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(200);
/* Check status. */
if (status != TX_SUCCESS)
@@ -288,9 +289,9 @@ CHAR *pointer;
}
/* Test for search pointer issue on wrapped seach with prior block to search pointer merged. */
status = tx_byte_pool_create(&pool_4, "pool 4", pointer, POOL_4_SIZE);
status = tx_byte_pool_create(&pool_4, "pool 4", pointer, TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3));
pool_4_memory = pointer;
pointer = pointer + POOL_4_SIZE;
pointer = pointer + TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3);
/* Check status. */
if (status != TX_SUCCESS)
@@ -362,7 +363,7 @@ CHAR *pointer_2;
CHAR *pointer_3;
CHAR *pointer_4;
INT i;
ULONG array[20];
TX_TEST_POINTER_WORD array[20];
UCHAR *save_search;
@@ -403,7 +404,7 @@ UCHAR *save_search;
/* Try to create a NULL pool. */
pointer_1 = (CHAR *) 0x30000;
status = tx_byte_pool_create(TX_NULL, "pool 0", pointer_1, 108);
status = tx_byte_pool_create(TX_NULL, "pool 0", pointer_1, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -415,7 +416,7 @@ UCHAR *save_search;
}
/* Try to create the same pool. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer_1, 108);
status = tx_byte_pool_create(&pool_0, "pool 0", pointer_1, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_POOL_ERROR)
@@ -427,7 +428,7 @@ UCHAR *save_search;
}
/* Try to create a pool with a NULL start address. */
status = tx_byte_pool_create(&pool_2, "pool 2", TX_NULL, 108);
status = tx_byte_pool_create(&pool_2, "pool 2", TX_NULL, TX_TEST_BYTE_POOL_BYTES(108));
/* Check status. */
if (status != TX_PTR_ERROR)
@@ -635,7 +636,7 @@ UCHAR *save_search;
/* Test another bad block release.... pool pointer is not a valid pool! */
array[0] = 0;
array[1] = (ULONG) &array[3];
TX_TEST_STORE_POINTER(array[1], &array[3]);
array[2] = 0;
array[3] = 0;
status = _tx_byte_release(&array[2]);
@@ -874,7 +875,7 @@ UCHAR *save_search;
}
/* Move the search pointer to the third block to exercise that code in the byte search algorithm. */
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - BYTE_POOL_OVERHEAD;
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - TX_TEST_BYTE_POOL_SEARCH_OFFSET;
/* Now allocate the block again. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer_2, 24, TX_NO_WAIT);
@@ -894,7 +895,7 @@ UCHAR *save_search;
status += tx_byte_release(pointer_1);
/* Move the search pointer to the third block to exercise that code in the byte search algorithm. */
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - BYTE_POOL_OVERHEAD;
pool_0.tx_byte_pool_search = (UCHAR *) pointer_3 - TX_TEST_BYTE_POOL_SEARCH_OFFSET;
/* Allocate a large block to force the search pointer update. */
status = tx_byte_allocate(&pool_0, (VOID **) &pointer_3, 88, TX_NO_WAIT);
@@ -970,7 +971,7 @@ UCHAR *save_search;
}
/* Create pool 4. */
status = tx_byte_pool_create(&pool_4, "pool 4", pool_4_memory, POOL_4_SIZE);
status = tx_byte_pool_create(&pool_4, "pool 4", pool_4_memory, TX_TEST_BYTE_POOL_CAPACITY_BYTES(84, 3));
/* Check status. */
if (status != TX_SUCCESS)
@@ -1070,4 +1071,3 @@ UCHAR *save_search;
printf("SUCCESS!\n");
test_control_return(0);
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
#include "tx_byte_pool.h"
@@ -193,7 +194,7 @@ CHAR *pointer;
}
/* Create the byte_pool with one byte. */
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, 100);
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(100));
pointer = pointer + 100;
/* Check for status. */
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
/* Define the ISR dispatch. */
@@ -197,7 +198,7 @@ CHAR *pointer;
}
/* Create the byte_pool with one byte. */
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, 100);
status = tx_byte_pool_create(&byte_pool_0, "byte_pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(100));
pointer = pointer + 100;
/* Check for status. */
@@ -495,4 +496,3 @@ VOID *pointer;
thread_6_counter++;
}
}
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -121,8 +122,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -85,8 +86,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -89,8 +90,8 @@ CHAR *pointer;
}
/* Create byte pool 0. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Save off the intial pool size. */
initial_pool_size = pool_0.tx_byte_pool_available;
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "tx_api.h"
#include "threadx_test_port.h"
static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;
@@ -68,8 +69,8 @@ CHAR *pointer;
}
/* Create byte pools 0 and 1. */
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, 108);
pointer = pointer + 108;
status = tx_byte_pool_create(&pool_0, "pool 0", pointer, TX_TEST_BYTE_POOL_BYTES(108));
pointer = pointer + TX_TEST_BYTE_POOL_BYTES(108);
/* Check status. */
if (status != TX_SUCCESS)
@@ -174,4 +175,3 @@ CHAR *pointer;
thread_1_counter++;
}
}
@@ -355,5 +355,3 @@ static void timer_0_entry(ULONG input)
{
timer_0_counter++;
}
@@ -181,9 +181,9 @@ UINT status;
/* Check the run counters. Depending on the starting time relative to
the tick boundary, thread 1 can run either 32 or 33 rounds and
thread 2 can run 13 or 14 rounds. This variance applies to any
platform with non-deterministic tick alignment (Linux, QEMU, etc.). */
if (((thread_1_counter != 32) && (thread_1_counter != 33)) ||
((thread_2_counter != 13) && (thread_2_counter != 14)))
platform with non-deterministic tick alignment (Linux, QEMU, Windows, etc.). */
if (((thread_1_counter < 32UL) || (thread_1_counter > 33UL)) ||
((thread_2_counter < 13UL) || (thread_2_counter > 14UL)))
{
/* Event flag error. */
@@ -1,6 +1,8 @@
/* This test is designed to test kernel setup functionality in ThreadX. */
// Some portions generated by Codex (gpt 5.4).
#include <stdio.h>
#include <stdlib.h>
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
@@ -30,20 +32,7 @@ UINT test_byte_pool_create_init;
UINT test_block_pool_create_init;
UINT test_timer_create_init;
__attribute__((weak)) void abort_all_threads_suspended_on_mutex(void)
{
}
__attribute__((weak)) void suspend_lowest_priority(void)
{
}
__attribute__((weak)) void abort_and_resume_byte_allocating_thread(void)
{
}
void main()
int main(void)
{
/* Setup the ThreadX kernel. */
@@ -59,6 +48,8 @@ void main()
printf("Running Initialize Kernel Setup Test................................ ERROR!\n");
exit(1);
}
return(0);
}
void test_application_define(void *first_unused_memory){}
@@ -78,4 +69,4 @@ void delete_timer_thread(void)
_tx_thread_delete(&_tx_timer_thread);
}
#endif
#endif
@@ -163,5 +163,3 @@ ULONG now;
test_control_return(0);
}
}

Some files were not shown because too many files have changed in this diff Show More