summaryrefslogtreecommitdiff
path: root/ports/win64/vs_2022/src
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-10-02 10:42:44 -0400
committerGitHub <[email protected]>2026-10-02 10:42:44 -0400
commit93387b0a60382a29579bbad5045c68328e3751df (patch)
tree42be790d602cb76f55090e5a7c418df7ea2b3428 /ports/win64/vs_2022/src
parent44d7c95c582d415c4ad84527180b29c93c3bf664 (diff)
parent28281cd5647d4671236ca08d19bd18ed15b2265a (diff)
Merge pull request #783 from eclipse-threadx/devv6.5.2.202603_rel
Merged changes ahead of the v6.5.2.202603 release
Diffstat (limited to 'ports/win64/vs_2022/src')
-rw-r--r--ports/win64/vs_2022/src/tx_initialize_low_level.c68
-rw-r--r--ports/win64/vs_2022/src/tx_thread_context_restore.c15
-rw-r--r--ports/win64/vs_2022/src/tx_thread_interrupt_control.c15
-rw-r--r--ports/win64/vs_2022/src/tx_thread_schedule.c85
-rw-r--r--ports/win64/vs_2022/src/tx_thread_stack_build.c21
-rw-r--r--ports/win64/vs_2022/src/tx_thread_system_return.c11
6 files changed, 123 insertions, 92 deletions
diff --git a/ports/win64/vs_2022/src/tx_initialize_low_level.c b/ports/win64/vs_2022/src/tx_initialize_low_level.c
index b7e96575..0bb1f3e3 100644
--- a/ports/win64/vs_2022/src/tx_initialize_low_level.c
+++ b/ports/win64/vs_2022/src/tx_initialize_low_level.c
@@ -13,7 +13,7 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
-// Some portions generated by Codex (gpt 5.4).
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
/** */
@@ -51,6 +51,15 @@ HANDLE _tx_win32_isr_semaphore;
UINT _tx_win32_timer_waiting;
extern TX_THREAD *_tx_thread_current_ptr;
+#ifdef TX_WIN32_NO_IDLE_ENABLE
+/* Auto-reset event used by the scheduler to kick the timer thread so that the
+ simulated clock advances immediately when no thread is ready to run, instead
+ of waiting for the wall-clock periodic timer. This makes the simulation
+ CPU-bound rather than wall-clock-bound during idle periods, mirroring the
+ Linux port's TX_LINUX_NO_IDLE_ENABLE behavior. */
+HANDLE _tx_win32_timer_kick_event;
+#endif
+
/* Define simulated timer interrupt. This is done inside a thread, which is
how other interrupts may be defined as well. See code below for an
@@ -197,7 +206,7 @@ extern VOID *_tx_initialize_unused_memory;
/* */
/* CALLS */
/* */
-/* CreateMutex Win32 create mutex */
+/* InitializeCriticalSection Win32 initialize lock */
/* CreateThread Win32 create thread */
/* CreateSemaphore Win32 create semaphore */
/* GetCurrentThreadId Win32 get current thread ID */
@@ -237,18 +246,11 @@ VOID _tx_initialize_low_level(VOID)
/* Pickup the unique Id of the current thread, which will also be the Id of the scheduler. */
_tx_win32_scheduler_id = GetCurrentThreadId();
- /* Create the system critical section mutex. This is used by the system to block all other access,
+ /* Initialize the system critical section. This is used by the system to block all other access,
analogous to an interrupt lockout on an embedded target. */
- _tx_win32_critical_section.tx_win32_critical_section_mutex_handle = CreateMutex(NULL, FALSE, NULL);
+ InitializeCriticalSection(&_tx_win32_critical_section.tx_win32_critical_section_lock);
_tx_win32_critical_section.tx_win32_critical_section_nested_count = 0;
_tx_win32_critical_section.tx_win32_critical_section_owner = 0;
- if (_tx_win32_critical_section.tx_win32_critical_section_mutex_handle == NULL)
- {
- printf("ThreadX Win64 error creating critical section mutex!\n");
- while(1)
- {
- }
- }
/* Create the semaphore that regulates when the scheduler executes. */
_tx_win32_scheduler_semaphore = CreateSemaphore(NULL, 0, 1, NULL);
@@ -271,6 +273,20 @@ VOID _tx_initialize_low_level(VOID)
}
}
+#ifdef TX_WIN32_NO_IDLE_ENABLE
+
+ /* Create the auto-reset event used to kick the timer thread when the
+ scheduler detects an idle system (see _tx_thread_schedule). */
+ _tx_win32_timer_kick_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (_tx_win32_timer_kick_event == NULL)
+ {
+ printf("ThreadX Win64 error creating timer kick event!\n");
+ while(1)
+ {
+ }
+ }
+#endif
+
/* Initialize the global interrupt disabled flag. */
_tx_win32_global_int_disabled_flag = TX_FALSE;
_tx_win32_timer_waiting = TX_FALSE;
@@ -358,8 +374,20 @@ VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUse
/* Call ThreadX context save for interrupt preparation. */
_tx_thread_context_save();
- /* Call the ThreadX system timer interrupt processing. */
- _tx_timer_interrupt();
+ /* Fire TX_WIN32_TICKS_PER_INTERRUPT ticks inside a single interrupt
+ context. The SuspendThread/ResumeThread overhead is amortized across
+ all N ticks, and all timer-based delays shrink by factor N. The
+ relative ordering of thread wakeups is preserved because each call to
+ _tx_timer_interrupt() advances the tick counter by exactly one step and
+ processes the timers that expire at that step. */
+#ifndef TX_WIN32_TICKS_PER_INTERRUPT
+#define TX_WIN32_TICKS_PER_INTERRUPT 5
+#endif
+ {
+ UINT _tick_i;
+ for (_tick_i = 0; _tick_i < TX_WIN32_TICKS_PER_INTERRUPT; _tick_i++)
+ _tx_timer_interrupt();
+ }
/* Call ThreadX context restore for interrupt completion. */
_tx_thread_context_restore();
@@ -376,13 +404,26 @@ static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input)
/* Drive periodic simulated interrupts from a single thread. */
while (1)
{
+#ifdef TX_WIN32_NO_IDLE_ENABLE
+
+ /* Wake either on the periodic wall-clock timer or on a scheduler kick
+ (issued when the system is idle). Firing on the kick advances the
+ simulated clock immediately, without waiting for the wall clock. */
+ HANDLE _wait_handles[2];
+
+ _wait_handles[0] = _tx_win32_timer_handle;
+ _wait_handles[1] = _tx_win32_timer_kick_event;
+ WaitForMultipleObjects(2, _wait_handles, FALSE, INFINITE);
+#else
WaitForSingleObject(_tx_win32_timer_handle, INFINITE);
+#endif
_tx_win32_timer_interrupt(0, 0, 0, 0, 0);
_tx_win32_timer_start();
}
}
+
VOID _tx_win32_scheduler_wake(VOID)
{
@@ -414,4 +455,3 @@ LARGE_INTEGER due_time;
}
}
}
-
diff --git a/ports/win64/vs_2022/src/tx_thread_context_restore.c b/ports/win64/vs_2022/src/tx_thread_context_restore.c
index 9786e7cb..ae265da1 100644
--- a/ports/win64/vs_2022/src/tx_thread_context_restore.c
+++ b/ports/win64/vs_2022/src/tx_thread_context_restore.c
@@ -13,7 +13,7 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
-// Some portions generated by Codex (gpt 5.4).
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
@@ -131,9 +131,11 @@ TX_THREAD *execute_thread;
(execute_thread -> tx_thread_win32_suspension_type == 0))
{
- /* Release the critical section while the scheduler runs. */
+ /* Spin-poll for the scheduler to complete the solicited wakeup
+ before the timer ISR proceeds. */
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
- WaitForSingleObject(_tx_win32_isr_semaphore, INFINITE);
+ while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) != WAIT_OBJECT_0)
+ SwitchToThread();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) == WAIT_OBJECT_0)
{
@@ -161,9 +163,11 @@ TX_THREAD *execute_thread;
if (execute_thread -> tx_thread_win32_suspension_type == 0)
{
- /* Release the critical section while the scheduler runs. */
+ /* Spin-poll for the scheduler to hand off to the next thread and
+ acknowledge via the ISR semaphore. Keeps timer-path latency low. */
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
- WaitForSingleObject(_tx_win32_isr_semaphore, INFINITE);
+ while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) != WAIT_OBJECT_0)
+ SwitchToThread();
_tx_win32_critical_section_obtain(&_tx_win32_critical_section);
while (WaitForSingleObject(_tx_win32_isr_semaphore, 0) == WAIT_OBJECT_0)
{
@@ -177,4 +181,3 @@ TX_THREAD *execute_thread;
_tx_win32_critical_section_release_all(&_tx_win32_critical_section);
}
-
diff --git a/ports/win64/vs_2022/src/tx_thread_interrupt_control.c b/ports/win64/vs_2022/src/tx_thread_interrupt_control.c
index ab50a3c9..ff6329d6 100644
--- a/ports/win64/vs_2022/src/tx_thread_interrupt_control.c
+++ b/ports/win64/vs_2022/src/tx_thread_interrupt_control.c
@@ -13,6 +13,8 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
/** */
@@ -96,8 +98,6 @@ UINT _tx_thread_interrupt_control(UINT new_posture)
{
UINT old_posture;
-HANDLE threadhandle;
-int threadpriority;
DWORD threadid;
TX_THREAD *thread_ptr;
@@ -122,22 +122,16 @@ TX_THREAD *thread_ptr;
/* Determine if the thread was terminated. */
- /* Pickup the handle of the current thread. */
- threadhandle = GetCurrentThread();
-
/* Pickup the current thread pointer. */
thread_ptr = _tx_thread_current_ptr;
- /* Pickup the priority of the current thread. */
- threadpriority = GetThreadPriority(threadhandle);
-
/* Pickup the ID of the current thread. */
threadid = GetCurrentThreadId();
/* Determine if this is a thread (THREAD_PRIORITY_LOWEST) and it does not
match the current thread pointer. */
- if ((threadpriority == THREAD_PRIORITY_LOWEST) &&
- ((!thread_ptr) || (thread_ptr -> tx_thread_win32_thread_id != threadid)))
+ if (((!thread_ptr) || (thread_ptr -> tx_thread_win32_thread_id != threadid)) &&
+ (GetThreadPriority(GetCurrentThread()) == THREAD_PRIORITY_LOWEST))
{
/* This indicates the Win32 thread was actually terminated by ThreadX is only
@@ -208,4 +202,3 @@ TX_THREAD *thread_ptr;
return(old_posture);
}
-
diff --git a/ports/win64/vs_2022/src/tx_thread_schedule.c b/ports/win64/vs_2022/src/tx_thread_schedule.c
index d08305ee..204a1e90 100644
--- a/ports/win64/vs_2022/src/tx_thread_schedule.c
+++ b/ports/win64/vs_2022/src/tx_thread_schedule.c
@@ -13,7 +13,7 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
-// Some portions generated by Codex (gpt 5.4).
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
@@ -111,8 +111,27 @@ DWORD wait_status;
/* Leave the critical section. */
_tx_win32_critical_section_release(&_tx_win32_critical_section);
- /* Wait for the next scheduling state change. */
- WaitForSingleObject(_tx_win32_scheduler_wake_event, INFINITE);
+#ifdef TX_WIN32_NO_IDLE_ENABLE
+
+ /* No thread is ready to run: advance the simulated clock now
+ instead of waiting for the wall-clock periodic timer. Kick
+ the timer thread so it fires the next tick(s) immediately,
+ then wait for it to signal progress via the wake event. A
+ short bounded timeout guards against a missed wake. This
+ makes idle periods CPU-bound rather than wall-clock-bound,
+ mirroring the Linux port's TX_LINUX_NO_IDLE_ENABLE path. */
+ SetEvent(_tx_win32_timer_kick_event);
+ WaitForSingleObject(_tx_win32_scheduler_wake_event, 2);
+#else
+
+ /* Yield to other threads (timer, application threads) instead of
+ blocking indefinitely. This spin-poll eliminates the ~0.5 ms
+ kernel-wake latency of WaitForSingleObject(INFINITE) and reduces
+ context-switch overhead by >10x at the cost of higher CPU usage
+ during test runs. Drain any pending wake event to keep it clean. */
+ WaitForSingleObject(_tx_win32_scheduler_wake_event, 0);
+ SwitchToThread();
+#endif
}
}
@@ -185,12 +204,16 @@ DWORD wait_status;
/* Exit Win32 critical section. */
_tx_win32_critical_section_release(&_tx_win32_critical_section);
- /* Now suspend the main thread so the application thread can run. */
- WaitForSingleObject(_tx_win32_scheduler_semaphore, INFINITE);
+ /* Spin-poll for the application thread to return control. Using
+ SwitchToThread() between polls yields the CPU without blocking,
+ matching the low-latency approach used in the idle loop above. */
+ while (WaitForSingleObject(_tx_win32_scheduler_semaphore, 0) != WAIT_OBJECT_0)
+ SwitchToThread();
}
}
+
static VOID _tx_win32_semaphore_reset(HANDLE semaphore_handle)
{
@@ -216,17 +239,9 @@ void _tx_win32_critical_section_obtain(TX_WIN32_CRITICAL_SECTION *critical_se
{
/* Get the Win32 critical section. */
- if (WaitForSingleObject(critical_section -> tx_win32_critical_section_mutex_handle, INFINITE) != WAIT_OBJECT_0)
- {
-
- /* Increment the system error counter and stop when the mutex cannot be acquired. */
- _tx_win32_system_error++;
- while(1)
- {
- }
- }
+ EnterCriticalSection(&critical_section -> tx_win32_critical_section_lock);
- /* At this point we have the mutex. */
+ /* At this point we have the critical section. */
/* Increment the nesting counter. */
critical_section -> tx_win32_critical_section_nested_count = 1;
@@ -241,7 +256,7 @@ void _tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION *critical_s
{
- /* Ensure the caller is the mutex owner. */
+ /* Ensure the caller is the critical section owner. */
if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
{
@@ -259,21 +274,8 @@ void _tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION *critical_s
/* Yes, it is being released clear the owner. */
critical_section -> tx_win32_critical_section_owner = 0;
- /* Finally, release the mutex. */
- if (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) != TX_TRUE)
- {
-
- /* Increment the system error counter. */
- _tx_win32_system_error++;
- }
-
- /* Just in case, make sure there the mutex is not owned. */
- while (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) == TX_TRUE)
- {
-
- /* Increment the system error counter. */
- _tx_win32_system_error++;
- }
+ /* Finally, release the critical section. */
+ LeaveCriticalSection(&critical_section -> tx_win32_critical_section_lock);
}
}
}
@@ -289,7 +291,7 @@ void _tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION *critical_s
void _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION *critical_section)
{
- /* Ensure the caller is the mutex owner. */
+ /* Ensure the caller is the critical section owner. */
if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
{
@@ -303,21 +305,8 @@ void _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION *cri
/* Yes, it is being release clear the owner. */
critical_section -> tx_win32_critical_section_owner = 0;
- /* Finally, release the mutex. */
- if (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) != TX_TRUE)
- {
-
- /* Increment the system error counter. */
- _tx_win32_system_error++;
- }
-
- /* Just in case, make sure there the mutex is not owned. */
- while (ReleaseMutex(critical_section -> tx_win32_critical_section_mutex_handle) == TX_TRUE)
- {
-
- /* Increment the system error counter. */
- _tx_win32_system_error++;
- }
+ /* Finally, release the critical section. */
+ LeaveCriticalSection(&critical_section -> tx_win32_critical_section_lock);
}
}
else
@@ -327,5 +316,3 @@ void _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION *cri
_tx_win32_system_error++;
}
}
-
-
diff --git a/ports/win64/vs_2022/src/tx_thread_stack_build.c b/ports/win64/vs_2022/src/tx_thread_stack_build.c
index c50f7754..c4f3f6ea 100644
--- a/ports/win64/vs_2022/src/tx_thread_stack_build.c
+++ b/ports/win64/vs_2022/src/tx_thread_stack_build.c
@@ -13,7 +13,8 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
-// Some portions generated by Codex (gpt 5.4).
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -80,6 +81,7 @@ DWORD WINAPI _tx_win32_thread_entry(LPVOID p);
/**************************************************************************/
VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{
+ALIGN_TYPE fake_stack_ptr;
/* Create a Win32 thread for the application thread. */
thread_ptr -> tx_thread_win32_thread_handle =
@@ -138,8 +140,13 @@ VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
tx_interrupt_control nesting. */
thread_ptr -> tx_thread_win32_int_disabled_flag = 0;
- /* Setup a fake thread stack pointer. */
- thread_ptr -> tx_thread_stack_ptr = (VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8);
+ /* Setup a fake thread stack pointer. The stack end points at the last byte of the
+ thread's stack area and is therefore not necessarily aligned, so round the result
+ down to a ULONG boundary. This pointer is dereferenced as a ULONG below and is
+ also the starting value of the stack checking logic's highest used pointer. */
+ fake_stack_ptr = (ALIGN_TYPE) ((VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8));
+ fake_stack_ptr = fake_stack_ptr & (~((ALIGN_TYPE) (sizeof(ULONG) - 1)));
+ thread_ptr -> tx_thread_stack_ptr = (VOID *) ((ALIGN_TYPE) fake_stack_ptr);
/* Clear the first word of the stack. */
*(((ULONG *) thread_ptr -> tx_thread_stack_ptr) - 1) = 0;
@@ -178,9 +185,10 @@ DWORD threadid;
handoff point and is ready to be scheduled. */
ReleaseSemaphore(thread_ptr -> tx_thread_win32_thread_start_semaphore, 1, NULL);
- /* Now suspend the thread initially. If the thread has already
- been scheduled, this will return immediately. */
- WaitForSingleObject(thread_ptr -> tx_thread_win32_thread_run_semaphore, INFINITE);
+ /* Spin-poll for the scheduler to release this thread to run.
+ Matches the spin-poll pattern used in _tx_thread_system_return. */
+ while (WaitForSingleObject(thread_ptr -> tx_thread_win32_thread_run_semaphore, 0) != WAIT_OBJECT_0)
+ SwitchToThread();
/* Acknowledge that the host thread is now able to execute ThreadX code. */
ReleaseSemaphore(thread_ptr -> tx_thread_win32_thread_start_semaphore, 1, NULL);
@@ -208,4 +216,3 @@ DWORD threadid;
return EXIT_SUCCESS;
}
-
diff --git a/ports/win64/vs_2022/src/tx_thread_system_return.c b/ports/win64/vs_2022/src/tx_thread_system_return.c
index 7a8fc89c..47249d0e 100644
--- a/ports/win64/vs_2022/src/tx_thread_system_return.c
+++ b/ports/win64/vs_2022/src/tx_thread_system_return.c
@@ -13,7 +13,7 @@
* SPDX-License-Identifier: MIT and CC0-1.0
**************************************************************************/
-// Some portions generated by Codex (gpt 5.4).
+// Portions of this file were generated with AI assistance.
/**************************************************************************/
/**************************************************************************/
@@ -167,9 +167,11 @@ DWORD threadid;
ExitThread(0);
}
- /* Wait on the run semaphore for this thread. This won't get set again
- until the thread is scheduled. */
- WaitForSingleObject(temp_run_semaphore, INFINITE);
+ /* Spin-poll for the scheduler to grant this thread a new time-slice.
+ SwitchToThread() between polls keeps the CPU available to the scheduler
+ and timer without paying the full kernel-wake cost of INFINITE. */
+ while (WaitForSingleObject(temp_run_semaphore, 0) != WAIT_OBJECT_0)
+ SwitchToThread();
/* Acknowledge that the thread is once again executing ThreadX code. */
ReleaseSemaphore(temp_thread_ptr -> tx_thread_win32_thread_start_semaphore, 1, NULL);
@@ -213,4 +215,3 @@ DWORD threadid;
}
}
-