diff options
Diffstat (limited to 'ports/win64/vs_2022/src')
| -rw-r--r-- | ports/win64/vs_2022/src/tx_initialize_low_level.c | 68 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_context_restore.c | 15 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_interrupt_control.c | 15 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_schedule.c | 85 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_stack_build.c | 21 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_system_return.c | 11 |
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; } } - |
