/*************************************************************************** * Copyright (C) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * AI Disclosure: This file was largely AI-generated by Codex (gpt 5.4). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ // Some portions generated by Codex (gpt 5.5). // Some portions generated by GitHub Copilot (claude-sonnet-4.6). #define TX_SOURCE_CODE #define TX_THREAD_SMP_SOURCE_CODE #include "tx_api.h" #include "tx_thread.h" #include "tx_timer.h" VOID _tx_thread_context_restore(VOID) { TX_THREAD *current_thread; TX_THREAD *execute_thread; _tx_win32_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__); _tx_thread_system_state[0]--; current_thread = _tx_thread_current_ptr[0]; execute_thread = _tx_thread_execute_ptr[0]; if (_tx_thread_system_state[0] == 0UL) { if (current_thread != TX_NULL) { if ((_tx_thread_preempt_disable == 0U) && (current_thread != execute_thread)) { /* If context_save skipped SuspendThread because the thread was spinning * on the Win32 CS (suspension_type == 4), suspend it now. The ISR still * holds the CS so the spinning thread cannot make forward progress, making * SuspendThread safe to call here. mutex_access remains TRUE; the thread * will clear it naturally when it acquires the CS after being resumed. */ if (current_thread -> tx_thread_win32_suspension_type == 4U) { _tx_win32_thread_suspend(current_thread -> tx_thread_win32_thread_handle); } current_thread -> tx_thread_win32_suspension_type = 1U; if (_tx_timer_time_slice[0] != 0U) { current_thread -> tx_thread_time_slice = _tx_timer_time_slice[0]; _tx_timer_time_slice[0] = 0U; } _tx_thread_current_ptr[0] = TX_NULL; _tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_handle = NULL; _tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread_id = 0U; _tx_win32_virtual_cores[0].tx_thread_smp_core_mapping_thread = TX_NULL; current_thread -> tx_thread_smp_core_control = 1U; /* Signal the scheduler to assign the next execute_thread. Wait for the * scheduler to signal isr_semaphore before returning: the scheduler holds * the CS while waiting for start_ack from the execute_thread, which forces * any thread calling TX_DISABLE to spin with mutex_access=TRUE while * preempt_disable may be non-zero — exactly the window needed to satisfy * the condition in tests such as wait_abort_and_isr. */ _tx_win32_timer_waiting = 1U; MemoryBarrier(); if (SetEvent(_tx_win32_scheduler_event) == 0) { _tx_win32_system_error++; } if ((execute_thread != TX_NULL) && (execute_thread -> tx_thread_win32_suspension_type == 2U)) { _tx_win32_critical_section_release_all(&_tx_win32_critical_section); _tx_win32_wait_for_isr_rendezvous(); _tx_win32_critical_section_obtain(&_tx_win32_critical_section); _tx_win32_semaphore_reset(_tx_win32_isr_semaphore); } _tx_win32_timer_waiting = 0U; } else { if ((current_thread -> tx_thread_win32_suspension_type == 3U) || (current_thread -> tx_thread_win32_suspension_type == 4U)) { /* context_save did not call SuspendThread (type 3: preempt_disable≠0; * type 4: thread was spinning on Win32 CS). Clear the flag; do not * issue a matching ResumeThread. The thread will continue * automatically once the ISR releases the Win32 critical section. */ current_thread -> tx_thread_win32_suspension_type = 0U; } else { /* suspension_type 0: context_save called SuspendThread. Always issue * the matching ResumeThread here, regardless of mutex_access. * * Do NOT gate this on mutex_access: a thread on a different virtual core * that happens to share the same stale TLS slot can momentarily stamp * mutex_access = TRUE on this thread's struct while it is OS-suspended, * which would otherwise cause context_restore to skip ResumeThread and * leave the thread permanently suspended (deadlock). */ _tx_win32_thread_resume(current_thread -> tx_thread_win32_thread_handle); } } } else if (execute_thread != TX_NULL) { _tx_win32_timer_waiting = 1U; MemoryBarrier(); if (SetEvent(_tx_win32_scheduler_event) == 0) { _tx_win32_system_error++; } if (execute_thread -> tx_thread_win32_suspension_type == 2U) { _tx_win32_critical_section_release_all(&_tx_win32_critical_section); _tx_win32_wait_for_isr_rendezvous(); _tx_win32_critical_section_obtain(&_tx_win32_critical_section); _tx_win32_semaphore_reset(_tx_win32_isr_semaphore); } _tx_win32_timer_waiting = 0U; } } _tx_thread_smp_unprotect(TX_INT_ENABLE); }