summaryrefslogtreecommitdiff
path: root/ports/win32/vs_2019/src/tx_thread_schedule.c
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/win32/vs_2019/src/tx_thread_schedule.c
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/win32/vs_2019/src/tx_thread_schedule.c')
-rw-r--r--ports/win32/vs_2019/src/tx_thread_schedule.c139
1 files changed, 84 insertions, 55 deletions
diff --git a/ports/win32/vs_2019/src/tx_thread_schedule.c b/ports/win32/vs_2019/src/tx_thread_schedule.c
index d67efee8..e9dc43d7 100644
--- a/ports/win32/vs_2019/src/tx_thread_schedule.c
+++ b/ports/win32/vs_2019/src/tx_thread_schedule.c
@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
- * Copyright (c) 2026-present Eclipse ThreadX contributors
+ * 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
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -31,6 +33,9 @@
#include "tx_timer.h"
+static VOID _tx_win32_semaphore_reset(HANDLE semaphore_handle);
+
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
@@ -59,7 +64,6 @@
/* */
/* ReleaseSemaphore Win32 release semaphore */
/* ResumeThread Win32 resume thread */
-/* Sleep Win32 thread sleep */
/* WaitForSingleObject Win32 wait on a semaphore */
/* _tx_win32_critical_section_obtain Obtain critical section */
/* _tx_win32_critical_section_release Release critical section */
@@ -71,6 +75,8 @@
/**************************************************************************/
VOID _tx_thread_schedule(VOID)
{
+DWORD wait_status;
+
/* Loop forever. */
@@ -102,8 +108,27 @@ VOID _tx_thread_schedule(VOID)
/* Leave the critical section. */
_tx_win32_critical_section_release(&_tx_win32_critical_section);
- /* Now sleep so we don't block forever. */
- Sleep(2);
+#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
}
}
@@ -136,8 +161,38 @@ VOID _tx_thread_schedule(VOID)
/* Debug entry. */
_tx_win32_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__);
+ /* Clear any stale wakeup acknowledgements before this solicited resume. */
+ _tx_win32_semaphore_reset(_tx_thread_current_ptr -> tx_thread_win32_thread_start_semaphore);
+ _tx_win32_semaphore_reset(_tx_thread_current_ptr -> tx_thread_win32_thread_run_semaphore);
+
/* Let the thread run again by releasing its run semaphore. */
- ReleaseSemaphore(_tx_thread_current_ptr -> tx_thread_win32_thread_run_semaphore, 1, NULL);
+ if (ReleaseSemaphore(_tx_thread_current_ptr -> tx_thread_win32_thread_run_semaphore, 1, NULL) == 0)
+ {
+
+ /* Increment the system error counter. */
+ _tx_win32_system_error++;
+ }
+
+ /* Let the solicited wakeup reach ThreadX before the timer ISR advances again. */
+ if (_tx_win32_timer_waiting)
+ {
+
+ /* Wait for the thread to acknowledge the wakeup and then release the ISR. */
+ wait_status = WaitForSingleObject(_tx_thread_current_ptr -> tx_thread_win32_thread_start_semaphore, INFINITE);
+ if (ReleaseSemaphore(_tx_win32_isr_semaphore, 1, NULL) == 0)
+ {
+
+ /* Increment the system error counter. */
+ _tx_win32_system_error++;
+ }
+
+ if (wait_status != WAIT_OBJECT_0)
+ {
+
+ /* Increment the system error counter. */
+ _tx_win32_system_error++;
+ }
+ }
}
/* Debug entry. */
@@ -146,20 +201,29 @@ VOID _tx_thread_schedule(VOID)
/* 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();
}
}
-/* Define the ThreadX Win32 critical section get, release, and release all functions. */
-
-void _tx_win32_critical_section_obtain(TX_WIN32_CRITICAL_SECTION *critical_section)
+static VOID _tx_win32_semaphore_reset(HANDLE semaphore_handle)
{
-TX_THREAD *thread_ptr;
+ /* Drain any stale semaphore count from a previous host-side wakeup. */
+ while (WaitForSingleObject(semaphore_handle, 0) == WAIT_OBJECT_0)
+ {
+ }
+}
+/* Define the ThreadX Win32 critical section get, release, and release all functions. */
+
+void _tx_win32_critical_section_obtain(TX_WIN32_CRITICAL_SECTION *critical_section)
+{
/* Is the protection owned? */
if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId())
{
@@ -170,15 +234,10 @@ TX_THREAD *thread_ptr;
else
{
- /* Pickup the current thread pointer. */
- thread_ptr = _tx_thread_current_ptr;
-
/* Get the Win32 critical section. */
- while (WaitForSingleObject(critical_section -> tx_win32_critical_section_mutex_handle, 3) != WAIT_OBJECT_0)
- {
- }
+ 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;
@@ -193,7 +252,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())
{
@@ -211,25 +270,9 @@ 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++;
- }
-
- /* Sleep for 0, just to relinquish to other ready threads. */
- Sleep(0);
- }
+ /* Finally, release the critical section. */
+ LeaveCriticalSection(&critical_section -> tx_win32_critical_section_lock);
+ }
}
}
else
@@ -244,7 +287,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())
{
@@ -258,21 +301,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
@@ -282,4 +312,3 @@ void _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION *cri
_tx_win32_system_error++;
}
}
-