/***************************************************************************
 * 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);
}
