diff options
| author | Frédéric Desbiens <[email protected]> | 2026-06-08 10:01:32 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-06-08 10:01:32 +0200 |
| commit | 87ab09cce305eb9cd4aacac4e8c62af72f665bff (patch) | |
| tree | dd062ebbea5235d1921c64b396bf7e4ce79e9e15 /ports/win64/vs_2022/src | |
| parent | 9ab0cf9683f832cdb48e2099533a5b06a3afcd64 (diff) | |
| parent | 730b61874bc5cf40768987605ae5187fde0fa1e2 (diff) | |
Merge pull request #544 from eclipse-threadx/devv6.5.1.202602_rel
Merging changes for the v.6.5.1.202602 release
Diffstat (limited to 'ports/win64/vs_2022/src')
| -rw-r--r-- | ports/win64/vs_2022/src/tx_initialize_low_level.c | 417 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_context_restore.c | 180 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_context_save.c | 111 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_interrupt_control.c | 211 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_schedule.c | 331 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_stack_build.c | 211 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_thread_system_return.c | 216 | ||||
| -rw-r--r-- | ports/win64/vs_2022/src/tx_timer_interrupt.c | 151 |
8 files changed, 1828 insertions, 0 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 new file mode 100644 index 00000000..b7e96575 --- /dev/null +++ b/ports/win64/vs_2022/src/tx_initialize_low_level.c @@ -0,0 +1,417 @@ +/*************************************************************************** + * 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 */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include <stdio.h> +#include <stdlib.h> +#include <windows.h> +#pragma comment (lib, "Winmm.lib") + +/* Define various Win32 objects used by the ThreadX port. */ + +TX_WIN32_CRITICAL_SECTION _tx_win32_critical_section; +HANDLE _tx_win32_scheduler_semaphore; +HANDLE _tx_win32_scheduler_wake_event; +DWORD _tx_win32_scheduler_id; +ULONG _tx_win32_global_int_disabled_flag; +LARGE_INTEGER _tx_win32_time_stamp; +ULONG _tx_win32_system_error; +HANDLE _tx_win32_timer_handle; +HANDLE _tx_win32_timer_thread_handle; +HANDLE _tx_win32_isr_semaphore; +UINT _tx_win32_timer_waiting; +extern TX_THREAD *_tx_thread_current_ptr; + + +/* 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 + example. */ + +UINT _tx_win32_timer_id; +VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); +static VOID _tx_win32_timer_start(VOID); +static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input); + + +#ifdef TX_WIN32_DEBUG_ENABLE + +extern ULONG _tx_thread_system_state; +extern UINT _tx_thread_preempt_disable; +extern TX_THREAD *_tx_thread_current_ptr; +extern TX_THREAD *_tx_thread_execute_ptr; + + +/* Define the maximum size of the Win32 debug array. */ + +#ifndef TX_WIN32_DEBUG_EVENT_SIZE +#define TX_WIN32_DEBUG_EVENT_SIZE 400 +#endif + + +/* Define debug log in order to debug Win32 issues with this port. */ + +typedef struct TX_WIN32_DEBUG_ENTRY_STRUCT +{ + char *tx_win32_debug_entry_action; + LARGE_INTEGER tx_win32_debug_entry_timestamp; + char *tx_win32_debug_entry_file; + unsigned long tx_win32_debug_entry_line; + TX_WIN32_CRITICAL_SECTION tx_win32_debug_entry_critical_section; + unsigned long tx_win32_debug_entry_int_disabled_flag; + ULONG tx_win32_debug_entry_system_state; + UINT tx_win32_debug_entry_preempt_disable; + TX_THREAD *tx_win32_debug_entry_current_thread; + DWORD tx_win32_debug_entry_current_thread_id; + TX_THREAD *tx_win32_debug_entry_execute_thread; + DWORD tx_win32_debug_entry_execute_thread_id; + DWORD tx_win32_debug_entry_running_id; +} TX_WIN32_DEBUG_ENTRY; + + +/* Define the circular array of Win32 debug entries. */ + +TX_WIN32_DEBUG_ENTRY _tx_win32_debug_entry_array[TX_WIN32_DEBUG_EVENT_SIZE]; + + +/* Define the Win32 debug index. */ + +unsigned long _tx_win32_debug_entry_index = 0; + + +/* Now define the debug entry function. */ +void _tx_win32_debug_entry_insert(char *action, char *file, unsigned long line) +{ + + + /* Get the time stamp. */ + QueryPerformanceCounter((LARGE_INTEGER *)&_tx_win32_time_stamp); + + /* Setup the debug entry. */ + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_action = action; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_timestamp = _tx_win32_time_stamp; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_file = file; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_line = line; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_critical_section = _tx_win32_critical_section; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_int_disabled_flag = _tx_win32_global_int_disabled_flag; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_system_state = _tx_thread_system_state; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_preempt_disable = _tx_thread_preempt_disable; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread = _tx_thread_current_ptr; + if (_tx_thread_current_ptr) + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id = _tx_thread_current_ptr -> tx_thread_win32_thread_id; + else + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_current_thread_id = 0; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread = _tx_thread_execute_ptr; + if (_tx_thread_execute_ptr) + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id = _tx_thread_execute_ptr -> tx_thread_win32_thread_id; + else + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_execute_thread_id = 0; + _tx_win32_debug_entry_array[_tx_win32_debug_entry_index].tx_win32_debug_entry_running_id = GetCurrentThreadId(); + + /* Now move to the next entry. */ + _tx_win32_debug_entry_index++; + + /* Determine if we need to wrap the list. */ + if (_tx_win32_debug_entry_index >= TX_WIN32_DEBUG_EVENT_SIZE) + { + + /* Yes, wrap the list! */ + _tx_win32_debug_entry_index = 0; + } +} + +#endif + + +/* Define the ThreadX timer interrupt handler. */ + +void _tx_timer_interrupt(void); + + +/* Define other external function references. */ + +VOID _tx_initialize_low_level(VOID); +VOID _tx_thread_context_save(VOID); +VOID _tx_thread_context_restore(VOID); +VOID _tx_win32_scheduler_wake(VOID); + + +/* Define other external variable references. */ + +extern VOID *_tx_initialize_unused_memory; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Win64/MSVC */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* CreateMutex Win32 create mutex */ +/* CreateThread Win32 create thread */ +/* CreateSemaphore Win32 create semaphore */ +/* GetCurrentThreadId Win32 get current thread ID */ +/* SetProcessAffinityMask Win32 process affinity set */ +/* SetThreadPriority Win32 set thread priority */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/**************************************************************************/ +VOID _tx_initialize_low_level(VOID) +{ + +/* Deprecate TX_WIN32_MULTI_CORE build option and default to restricting + execution to one core. */ + +#ifndef TX_WIN32_BYPASS_AFFINITY_SETUP + + /* Limit this ThreadX simulation on Win64 to a single core. */ + if (SetProcessAffinityMask(GetCurrentProcess(), ((DWORD_PTR) 1)) == 0) + { + + /* Error restricting the process to one core. */ + printf("ThreadX Win64 error restricting the process to one core!\n"); + while(1) + { + } + } +#endif + + /* Pickup the first available memory address. */ + + /* Save the first available memory address. */ + _tx_initialize_unused_memory = malloc(TX_WIN32_MEMORY_SIZE); + + /* 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, + analogous to an interrupt lockout on an embedded target. */ + _tx_win32_critical_section.tx_win32_critical_section_mutex_handle = CreateMutex(NULL, FALSE, NULL); + _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); + _tx_win32_isr_semaphore = CreateSemaphore(NULL, 0, 1, NULL); + if ((_tx_win32_scheduler_semaphore == NULL) || (_tx_win32_isr_semaphore == NULL)) + { + printf("ThreadX Win64 error creating semaphores!\n"); + while(1) + { + } + } + + /* Create the event that wakes the scheduler whenever the ready state changes. */ + _tx_win32_scheduler_wake_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (_tx_win32_scheduler_wake_event == NULL) + { + printf("ThreadX Win64 error creating scheduler wake event!\n"); + while(1) + { + } + } + + /* Initialize the global interrupt disabled flag. */ + _tx_win32_global_int_disabled_flag = TX_FALSE; + _tx_win32_timer_waiting = TX_FALSE; + + /* Done, return to caller. */ +} + + +/* This routine is called after initialization is complete in order to start + all interrupt threads. Interrupt threads in addition to the timer may + be added to this routine as well. */ + +void _tx_initialize_start_interrupts(void) +{ + TIMECAPS tc; + UINT wTimerRes; + + /* Queries the timer device to determine its resolution. */ + if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) + { + /* Error; application can't continue. */ + printf("Query timer device error."); + while (1) + { + } + } + + wTimerRes = min(max(tc.wPeriodMin, TX_TIMER_PERIODIC), tc.wPeriodMax); + + /* Request the best available timer resolution for the simulation. */ + if (timeBeginPeriod(wTimerRes) != TIMERR_NOERROR) + { + printf("ThreadX Win64 error configuring timer resolution!\n"); + while (1) + { + } + } + + /* Create the periodic waitable timer used to drive simulated interrupts. */ +#if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0) + _tx_win32_timer_handle = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + if (_tx_win32_timer_handle == NULL) +#endif + { + _tx_win32_timer_handle = CreateWaitableTimer(NULL, FALSE, NULL); + } + + if (_tx_win32_timer_handle == NULL) + { + printf("ThreadX Win64 error creating timer handle!\n"); + while (1) + { + } + } + + /* Create the timer thread so interrupts are serialized through one execution context. */ + _tx_win32_timer_thread_handle = CreateThread(NULL, 0, _tx_win32_timer_thread_entry, NULL, 0, NULL); + if (_tx_win32_timer_thread_handle == NULL) + { + printf("ThreadX Win64 error creating timer thread!\n"); + while (1) + { + } + } + + SetThreadPriority(_tx_win32_timer_thread_handle, THREAD_PRIORITY_HIGHEST); + + _tx_win32_timer_id = 1; + + /* Start the first simulated tick. */ + _tx_win32_timer_start(); +} + +/* Define the ThreadX system timer interrupt. Other interrupts may be simulated + in a similar way. */ + +VOID CALLBACK _tx_win32_timer_interrupt(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +{ + TX_PARAMETER_NOT_USED(wTimerID); + TX_PARAMETER_NOT_USED(msg); + TX_PARAMETER_NOT_USED(dwUser); + TX_PARAMETER_NOT_USED(dw1); + TX_PARAMETER_NOT_USED(dw2); + + /* Call ThreadX context save for interrupt preparation. */ + _tx_thread_context_save(); + + /* Call the ThreadX system timer interrupt processing. */ + _tx_timer_interrupt(); + + /* Call ThreadX context restore for interrupt completion. */ + _tx_thread_context_restore(); + + /* Wake the scheduler so it can promptly observe timer-driven work. */ + _tx_win32_scheduler_wake(); +} + + +static DWORD WINAPI _tx_win32_timer_thread_entry(LPVOID thread_input) +{ + TX_PARAMETER_NOT_USED(thread_input); + + /* Drive periodic simulated interrupts from a single thread. */ + while (1) + { + WaitForSingleObject(_tx_win32_timer_handle, INFINITE); + _tx_win32_timer_interrupt(0, 0, 0, 0, 0); + _tx_win32_timer_start(); + } +} + + +VOID _tx_win32_scheduler_wake(VOID) +{ + + /* Wake the scheduler if it is waiting for a state change. */ + if (_tx_win32_scheduler_wake_event != NULL) + { + SetEvent(_tx_win32_scheduler_wake_event); + } +} + + +static VOID _tx_win32_timer_start(VOID) +{ + +LARGE_INTEGER due_time; + + + /* Rearm the host timer relative to "now" to avoid burst catch-up ticks. */ + due_time.QuadPart = -(((LONGLONG) TX_TIMER_PERIODIC) * 10000LL); +#if (TX_WIN32_USE_HIGH_RESOLUTION_TIMER != 0) + if (SetWaitableTimerEx(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, NULL, 0) == 0) +#else + if (SetWaitableTimer(_tx_win32_timer_handle, &due_time, 0, NULL, NULL, FALSE) == 0) +#endif + { + printf("ThreadX Win64 error starting timer!\n"); + while (1) + { + } + } +} + diff --git a/ports/win64/vs_2022/src/tx_thread_context_restore.c b/ports/win64/vs_2022/src/tx_thread_context_restore.c new file mode 100644 index 00000000..9786e7cb --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_context_restore.c @@ -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); +} + + diff --git a/ports/win64/vs_2022/src/tx_thread_context_save.c b/ports/win64/vs_2022/src/tx_thread_context_save.c new file mode 100644 index 00000000..84f2d290 --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_context_save.c @@ -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); +} + + diff --git a/ports/win64/vs_2022/src/tx_thread_interrupt_control.c b/ports/win64/vs_2022/src/tx_thread_interrupt_control.c new file mode 100644 index 00000000..ab50a3c9 --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_interrupt_control.c @@ -0,0 +1,211 @@ +/*************************************************************************** + * 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 <winbase.h> + +/* Define small routines used for the TX_DISABLE/TX_RESTORE macros. */ + +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); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Win64/MSVC */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* ExitThread Win32 thread exit */ +/* GetCurrentThread Win32 get current thread */ +/* GetCurrentThreadId Win32 get current thread ID */ +/* GetThreadPriority Win32 get thread priority */ +/* _tx_win32_critical_section_obtain Obtain critical section */ +/* _tx_win32_critical_section_release Release critical section */ +/* _tx_win32_critical_section_release_all */ +/* Release critical section */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/**************************************************************************/ +UINT _tx_thread_interrupt_control(UINT new_posture) +{ + +UINT old_posture; +HANDLE threadhandle; +int threadpriority; +DWORD threadid; +TX_THREAD *thread_ptr; + + + /* Enter Win32 critical section. */ + _tx_win32_critical_section_obtain(&_tx_win32_critical_section); + +#ifdef TX_WIN32_DEBUG_ENABLE + + /* Determine if this is a disable or enable request. */ + if (new_posture == TX_INT_ENABLE) + { + /* Enable. */ + _tx_win32_debug_entry_insert("RESTORE", __FILE__, __LINE__); + } + else + { + /* Disable. */ + _tx_win32_debug_entry_insert("DISABLE", __FILE__, __LINE__); + } +#endif + + /* 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))) + { + + /* This indicates the Win32 thread was actually terminated by ThreadX is only + being allowed to run in order to cleanup its resources. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + + /* Exit this thread. */ + ExitThread(0); + } + + /* Determine the current interrupt lockout condition. */ + if (_tx_win32_critical_section.tx_win32_critical_section_nested_count == 1) + { + + /* First pass through, interrupts are enabled. */ + old_posture = TX_INT_ENABLE; + } + else + { + + /* Interrupts are disabled. */ + old_posture = TX_INT_DISABLE; + } + + /* First, determine if this call is from a non-thread. */ + if (_tx_thread_system_state) + { + + /* Determine how to apply the new posture. */ + if (new_posture == TX_INT_ENABLE) + { + + /* Clear the disabled flag. */ + _tx_win32_global_int_disabled_flag = TX_FALSE; + + /* Determine if the critical section is locked. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + } + else if (new_posture == TX_INT_DISABLE) + { + + /* Set the disabled flag. */ + _tx_win32_global_int_disabled_flag = TX_TRUE; + } + } + else if (thread_ptr) + { + + /* Determine how to apply the new posture. */ + if (new_posture == TX_INT_ENABLE) + { + + /* Clear the disabled flag. */ + _tx_thread_current_ptr -> tx_thread_win32_int_disabled_flag = TX_FALSE; + + /* Determine if the critical section is locked. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + } + else if (new_posture == TX_INT_DISABLE) + { + + /* Set the disabled flag. */ + _tx_thread_current_ptr -> tx_thread_win32_int_disabled_flag = TX_TRUE; + } + } + + /* Return the previous interrupt disable posture. */ + 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 new file mode 100644 index 00000000..d08305ee --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_schedule.c @@ -0,0 +1,331 @@ +/*************************************************************************** + * 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" + + +static VOID _tx_win32_semaphore_reset(HANDLE semaphore_handle); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Win64/MSVC */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* ReleaseSemaphore Win32 release semaphore */ +/* ResumeThread Win32 resume thread */ +/* _tx_win32_scheduler_wake Wake scheduler waiters */ +/* WaitForSingleObject Win32 wait on a semaphore */ +/* _tx_win32_critical_section_obtain Obtain critical section */ +/* _tx_win32_critical_section_release Release critical section */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/**************************************************************************/ +VOID _tx_thread_schedule(VOID) +{ +DWORD wait_status; + + + /* Loop forever. */ + while(1) + { + + /* Wait for a thread to execute and all ISRs to complete. */ + while(1) + { + + + /* Enter Win32 critical section. */ + _tx_win32_critical_section_obtain(&_tx_win32_critical_section); + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__); + + /* Determine if there is a thread ready to execute AND all ISRs + are complete. */ + if ((_tx_thread_execute_ptr != TX_NULL) && (_tx_thread_system_state == 0)) + { + + /* Get out of this loop and schedule the thread! */ + break; + } + else + { + + /* 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); + } + } + + /* Yes! We have a thread to execute. Note that the critical section is already + active from the scheduling loop above. */ + + /* Setup the current thread pointer. */ + _tx_thread_current_ptr = _tx_thread_execute_ptr; + + /* Increment the run count for this thread. */ + _tx_thread_current_ptr -> tx_thread_run_count++; + + /* Setup time-slice, if present. */ + _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; + + /* Determine how the thread was suspended. */ + if (_tx_thread_current_ptr -> tx_thread_win32_suspension_type) + { + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SCHEDULE-resume_thread", __FILE__, __LINE__); + + /* Pseudo interrupt suspension. The thread is not waiting on + its run semaphore. */ + ResumeThread(_tx_thread_current_ptr -> tx_thread_win32_thread_handle); + } + else + { + + /* 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. */ + 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. */ + _tx_win32_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__); + + /* 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); + } +} + + +static VOID _tx_win32_semaphore_reset(HANDLE semaphore_handle) +{ + + /* 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()) + { + + /* Simply increment the nested counter. */ + critical_section -> tx_win32_critical_section_nested_count++; + } + else + { + + /* 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) + { + } + } + + /* At this point we have the mutex. */ + + /* Increment the nesting counter. */ + critical_section -> tx_win32_critical_section_nested_count = 1; + + /* Remember the owner. */ + critical_section -> tx_win32_critical_section_owner = GetCurrentThreadId(); + } +} + + +void _tx_win32_critical_section_release(TX_WIN32_CRITICAL_SECTION *critical_section) +{ + + + /* Ensure the caller is the mutex owner. */ + if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId()) + { + + /* Determine if there is protection. */ + if (critical_section -> tx_win32_critical_section_nested_count) + { + + /* Decrement the nesting counter. */ + critical_section -> tx_win32_critical_section_nested_count--; + + /* Determine if the critical section is now being released. */ + if (critical_section -> tx_win32_critical_section_nested_count == 0) + { + + /* 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++; + } + } + } + } + else + { + + /* Increment the system error counter. */ + _tx_win32_system_error++; + } +} + + +void _tx_win32_critical_section_release_all(TX_WIN32_CRITICAL_SECTION *critical_section) +{ + + /* Ensure the caller is the mutex owner. */ + if (critical_section -> tx_win32_critical_section_owner == GetCurrentThreadId()) + { + + /* Determine if there is protection. */ + if (critical_section -> tx_win32_critical_section_nested_count) + { + + /* Clear the nesting counter. */ + critical_section -> tx_win32_critical_section_nested_count = 0; + + /* 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++; + } + } + } + else + { + + /* Increment the system error counter. */ + _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 new file mode 100644 index 00000000..c50f7754 --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_stack_build.c @@ -0,0 +1,211 @@ +/*************************************************************************** + * 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 <stdio.h> + + +/* Prototype for new thread entry function. */ + +DWORD WINAPI _tx_win32_thread_entry(LPVOID p); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Win64/MSVC */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* CreateThread Win32 create thread */ +/* ResumeThread Win32 resume thread */ +/* SetThreadPriority Win32 set thread priority */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* _tx_thread_reset Reset thread service */ +/* */ +/**************************************************************************/ +VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +{ + + /* Create a Win32 thread for the application thread. */ + thread_ptr -> tx_thread_win32_thread_handle = + CreateThread(NULL, 0, _tx_win32_thread_entry, (LPVOID) thread_ptr, CREATE_SUSPENDED, + &(thread_ptr -> tx_thread_win32_thread_id)); + + /* Check for a good thread create. */ + if (!thread_ptr -> tx_thread_win32_thread_handle) + { + + /* Display an error message. */ + printf("ThreadX Win32 error creating thread!\n"); + while(1) + { + } + } + + /* Otherwise, we have a good thread create. Now set the priority to + a lower level. */ + SetThreadPriority(thread_ptr -> tx_thread_win32_thread_handle, THREAD_PRIORITY_LOWEST); + + /* Create the run semaphore for the thread. This will allow the scheduler + control over when the thread actually runs. */ + thread_ptr -> tx_thread_win32_thread_run_semaphore = CreateSemaphore(NULL, 0, 1, NULL); + + /* Determine if the run semaphore was created successfully. */ + if (!thread_ptr -> tx_thread_win32_thread_run_semaphore) + { + + /* Display an error message. */ + printf("ThreadX Win32 error creating thread running semaphore!\n"); + while(1) + { + } + } + + /* Create the scheduler acknowledgement semaphore for this thread. */ + thread_ptr -> tx_thread_win32_thread_start_semaphore = CreateSemaphore(NULL, 0, 1, NULL); + + /* Determine if the start semaphore was created successfully. */ + if (!thread_ptr -> tx_thread_win32_thread_start_semaphore) + { + + /* Display an error message. */ + printf("ThreadX Win32 error creating thread start semaphore!\n"); + while(1) + { + } + } + + /* Setup the thread suspension type to solicited thread suspension. + Pseudo interrupt handlers will suspend with this field set to 1. */ + thread_ptr -> tx_thread_win32_suspension_type = 0; + + /* Clear the disabled count that will keep track of the + 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); + + /* Clear the first word of the stack. */ + *(((ULONG *) thread_ptr -> tx_thread_stack_ptr) - 1) = 0; + + /* Make the thread initially ready so it will run to the initial wait on + its run semaphore. */ + ResumeThread(thread_ptr -> tx_thread_win32_thread_handle); + + /* Wait until the host thread is parked at the controlled handoff point + before ThreadX can schedule it. */ + if (WaitForSingleObject(thread_ptr -> tx_thread_win32_thread_start_semaphore, INFINITE) != WAIT_OBJECT_0) + { + + /* Display an error message. */ + printf("ThreadX Win32 error synchronizing thread startup!\n"); + while(1) + { + } + } +} + + +DWORD WINAPI _tx_win32_thread_entry(LPVOID ptr) +{ + +TX_THREAD *thread_ptr; +TX_THREAD *current_thread_ptr; +HANDLE threadhandle; +int threadpriority; +DWORD threadid; + + /* Pickup the current thread pointer. */ + thread_ptr = (TX_THREAD *) ptr; + + /* Tell the creator that this host thread has reached the controlled + 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); + + /* Acknowledge that the host thread is now able to execute ThreadX code. */ + ReleaseSemaphore(thread_ptr -> tx_thread_win32_thread_start_semaphore, 1, NULL); + + /* A deleted host thread can be released only to let it exit. In notify-enabled + builds, the first TX_DISABLE in _tx_thread_shell_entry catches this path. + When callbacks are disabled, perform the same check before the shell calls + the stale ThreadX entry function. */ + _tx_win32_critical_section_obtain(&_tx_win32_critical_section); + threadhandle = GetCurrentThread(); + threadpriority = GetThreadPriority(threadhandle); + threadid = GetCurrentThreadId(); + current_thread_ptr = _tx_thread_current_ptr; + if ((threadpriority == THREAD_PRIORITY_LOWEST) && + ((current_thread_ptr == TX_NULL) || (current_thread_ptr -> tx_thread_win32_thread_id != threadid))) + { + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + ExitThread(0); + } + _tx_win32_critical_section_release(&_tx_win32_critical_section); + + /* Call ThreadX thread entry point. */ + _tx_thread_shell_entry(); + + 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 new file mode 100644 index 00000000..7a8fc89c --- /dev/null +++ b/ports/win64/vs_2022/src/tx_thread_system_return.c @@ -0,0 +1,216 @@ +/*************************************************************************** + * 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" +#include <stdio.h> + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Win64/MSVC */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the system. Only a minimal context */ +/* is saved since the compiler assumes temp registers are going to get */ +/* slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_win32_critical_section_obtain Obtain critical section */ +/* _tx_win32_critical_section_release Release critical section */ +/* _tx_win32_critical_section_release_all */ +/* Release critical section */ +/* ExitThread Win32 thread exit */ +/* GetCurrentThread Win32 get current thread */ +/* GetCurrentThreadId Win32 get current thread ID */ +/* GetThreadPriority Win32 get thread priority */ +/* ReleaseSemaphore Win32 release semaphore */ +/* WaitForSingleObject Win32 wait on semaphore */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/**************************************************************************/ +VOID _tx_thread_system_return(VOID) +{ + +TX_THREAD *temp_thread_ptr; +HANDLE temp_run_semaphore; +UINT temp_thread_state; +HANDLE threadhandle; +int threadpriority; +DWORD threadid; + + + /* Enter Win32 critical section. */ + _tx_win32_critical_section_obtain(&_tx_win32_critical_section); + + /* Pickup the handle of the current thread. */ + threadhandle = GetCurrentThread(); + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SYSTEM_RETURN", __FILE__, __LINE__); + + /* First, determine if the thread was terminated. */ + + /* Pickup the priority of the current thread. */ + threadpriority = GetThreadPriority(threadhandle); + + /* Pickup the ID of the current thread. */ + threadid = GetCurrentThreadId(); + + /* Pickup the current thread pointer. */ + temp_thread_ptr = _tx_thread_current_ptr; + + /* Determine if this is a thread (THREAD_PRIORITY_LOWEST) and it does not + match the current thread pointer. */ + if ((threadpriority == THREAD_PRIORITY_LOWEST) && + ((!temp_thread_ptr) || (temp_thread_ptr -> tx_thread_win32_thread_id != threadid))) + { + + /* This indicates the Win32 thread was actually terminated by ThreadX and is only + being allowed to run in order to cleanup its resources. */ + + /* Release critical section. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + + /* Exit thread. */ + ExitThread(0); + } + + /* Determine if the time-slice is active. */ + if (_tx_timer_time_slice) + { + + /* Preserve current remaining time-slice for the thread and clear the current time-slice. */ + temp_thread_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + _tx_timer_time_slice = 0; + } + + /* Save the run semaphore into a temporary variable as well. */ + temp_run_semaphore = temp_thread_ptr -> tx_thread_win32_thread_run_semaphore; + + /* Pickup the current thread state. */ + temp_thread_state = temp_thread_ptr -> tx_thread_state; + + /* Setup the suspension type for this thread. */ + temp_thread_ptr -> tx_thread_win32_suspension_type = 0; + + /* Set the current thread pointer to NULL. */ + _tx_thread_current_ptr = TX_NULL; + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SYSTEM_RETURN-release_sem", __FILE__, __LINE__); + + /* Release the semaphore that the main scheduling thread is waiting + on. Note that the main scheduling algorithm will take care of + setting the current thread pointer to NULL. */ + ReleaseSemaphore(_tx_win32_scheduler_semaphore, 1, NULL); + _tx_win32_scheduler_wake(); + + /* Leave Win32 critical section. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + + /* Determine if the thread was self-terminating. */ + if (temp_thread_state == TX_TERMINATED) + { + + /* Exit the thread instead of waiting on the semaphore! */ + 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); + + /* Acknowledge that the thread is once again executing ThreadX code. */ + ReleaseSemaphore(temp_thread_ptr -> tx_thread_win32_thread_start_semaphore, 1, NULL); + + /* Enter Win32 critical section. */ + _tx_win32_critical_section_obtain(&_tx_win32_critical_section); + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SYSTEM_RETURN-wake_up", __FILE__, __LINE__); + + /* Determine if the thread was terminated. */ + + /* Pickup the current thread pointer. */ + temp_thread_ptr = _tx_thread_current_ptr; + + /* Determine if this is a thread (THREAD_PRIORITY_LOWEST) and it does not + match the current thread pointer. */ + if ((threadpriority == THREAD_PRIORITY_LOWEST) && + ((!temp_thread_ptr) || (temp_thread_ptr -> tx_thread_win32_thread_id != threadid))) + { + + /* Leave Win32 critical section. */ + _tx_win32_critical_section_release_all(&_tx_win32_critical_section); + + /* This indicates the Win32 thread was actually terminated by ThreadX and is only + being allowed to run in order to cleanup its resources. */ + ExitThread(0); + } + + /* Now determine if the application thread last had interrupts disabled. */ + + /* Debug entry. */ + _tx_win32_debug_entry_insert("SYSTEM_RETURN-finish", __FILE__, __LINE__); + + /* Determine if this thread had interrupts disabled. */ + if (!_tx_thread_current_ptr -> tx_thread_win32_int_disabled_flag) + { + + /* Leave Win32 critical section. */ + _tx_win32_critical_section_release(&_tx_win32_critical_section); + } +} + + diff --git a/ports/win64/vs_2022/src/tx_timer_interrupt.c b/ports/win64/vs_2022/src/tx_timer_interrupt.c new file mode 100644 index 00000000..6814334b --- /dev/null +++ b/ports/win64/vs_2022/src/tx_timer_interrupt.c @@ -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); +} + + |
