/*************************************************************************** * 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). #define TX_SOURCE_CODE #define TX_THREAD_SMP_SOURCE_CODE #include "tx_api.h" #include "tx_thread.h" #include "tx_timer.h" static VOID _tx_win32_thread_cleanup(TX_THREAD *thread_ptr); VOID _tx_thread_schedule(VOID) { UINT core; UINT pending_work; TX_THREAD *current_thread; TX_THREAD *execute_thread; UCHAR preempt_retry; DWORD wait_status; LONG start_sequence; preempt_retry = TX_FALSE; while (1) { _tx_win32_critical_section_obtain(&_tx_win32_critical_section); if (_tx_win32_global_int_disabled_flag != TX_FALSE) { _tx_win32_system_error++; } _tx_win32_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__); for (core = 0U; core < TX_THREAD_SMP_MAX_CORES; core++) { current_thread = _tx_thread_current_ptr[core]; if ((current_thread != TX_NULL) && (current_thread -> tx_thread_win32_deferred_preempt != TX_FALSE)) { if (_tx_thread_preempt_disable != 0U) { preempt_retry = TX_TRUE; continue; } if (current_thread -> tx_thread_win32_mutex_access != TX_FALSE) { preempt_retry = TX_TRUE; continue; } if (current_thread -> tx_thread_state != TX_TERMINATED) { _tx_win32_thread_suspend(current_thread -> tx_thread_win32_thread_handle); current_thread -> tx_thread_win32_deferred_preempt = TX_FALSE; current_thread -> tx_thread_win32_suspension_type = 1U; if (_tx_timer_time_slice[core] != 0U) { current_thread -> tx_thread_time_slice = _tx_timer_time_slice[core]; _tx_timer_time_slice[core] = 0U; } } _tx_thread_current_ptr[core] = TX_NULL; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_handle = NULL; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_id = 0U; current_thread -> tx_thread_smp_core_control = 1U; _tx_win32_debug_entry_insert("SCHEDULE-core_preempt_complete", __FILE__, __LINE__); } if (_tx_thread_current_ptr[core] == TX_NULL) { execute_thread = _tx_thread_execute_ptr[core]; if ((execute_thread != TX_NULL) && (execute_thread -> tx_thread_smp_core_control != 0U)) { _tx_thread_current_ptr[core] = execute_thread; execute_thread -> tx_thread_win32_virtual_core = core; execute_thread -> tx_thread_smp_core_mapped = core; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread = execute_thread; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_handle = execute_thread -> tx_thread_win32_thread_handle; _tx_win32_virtual_cores[core].tx_thread_smp_core_mapping_thread_id = execute_thread -> tx_thread_win32_thread_id; execute_thread -> tx_thread_smp_core_control = 0U; execute_thread -> tx_thread_run_count++; _tx_timer_time_slice[core] = execute_thread -> tx_thread_time_slice; MemoryBarrier(); if (execute_thread -> tx_thread_win32_suspension_type == 1U) { execute_thread -> tx_thread_win32_suspension_type = 0U; _tx_win32_debug_entry_insert("SCHEDULE-resume_thread", __FILE__, __LINE__); _tx_win32_thread_resume(execute_thread -> tx_thread_win32_thread_handle); } else if (execute_thread -> tx_thread_win32_suspension_type == 2U) { execute_thread -> tx_thread_win32_suspension_type = 0U; _tx_win32_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__); #ifdef TX_WIN32_PROFILE_ENABLE _tx_win32_profile_mark_run_signal(execute_thread); #endif #if (TX_WIN32_USE_ADDRESS_WAIT == 0) _tx_win32_semaphore_reset(execute_thread -> tx_thread_win32_thread_start_semaphore); _tx_win32_semaphore_reset(execute_thread -> tx_thread_win32_thread_run_semaphore); #endif start_sequence = _tx_win32_thread_start_sequence_get(execute_thread); _tx_win32_thread_run_signal(execute_thread); /* Wait for the execute_thread to signal start_ack before proceeding. * Holding the CS here means any thread that calls TX_DISABLE will * spin with mutex_access=TRUE and preempt_disable≠0, creating the * window the ISR needs to observe preempt_disable!=0 for resonance * tests such as wait_abort_and_isr. */ wait_status = _tx_win32_wait_for_thread_start_ack(execute_thread, start_sequence); if (wait_status != WAIT_OBJECT_0) { _tx_win32_system_error++; } } else { _tx_win32_system_error++; } } } } /* Signal context_restore's rendezvous wait now that all execute_threads have * been resumed and their start_ack received. */ if (_tx_win32_timer_waiting != 0U) { ReleaseSemaphore(_tx_win32_isr_semaphore, 1, NULL); } if (preempt_retry != TX_FALSE) { _tx_win32_critical_section_release_all(&_tx_win32_critical_section); _tx_win32_thread_yield(); preempt_retry = TX_FALSE; continue; } _tx_win32_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__); pending_work = TX_FALSE; for (core = 0U; core < TX_THREAD_SMP_MAX_CORES; core++) { current_thread = _tx_thread_current_ptr[core]; execute_thread = _tx_thread_execute_ptr[core]; if ((current_thread != TX_NULL) && (current_thread -> tx_thread_win32_deferred_preempt != TX_FALSE)) { pending_work = TX_TRUE; break; } if ((_tx_thread_current_ptr[core] == TX_NULL) && (execute_thread != TX_NULL) && (execute_thread -> tx_thread_smp_core_control != 0U)) { pending_work = TX_TRUE; break; } } _tx_win32_critical_section_release_all(&_tx_win32_critical_section); if (pending_work != TX_FALSE) { continue; } /* Coalesce stale wakeups so the scheduler yields to worker threads until there is a new ready-state transition to process. */ (void) _tx_win32_wait_for_scheduler_event(); } } static VOID _tx_win32_thread_cleanup(TX_THREAD *thread_ptr) { DWORD exit_code; ULONG wait_count; if (thread_ptr -> tx_thread_win32_thread_handle != NULL) { wait_count = 0U; do { if ((GetExitCodeThread(thread_ptr -> tx_thread_win32_thread_handle, &exit_code) != 0) && (exit_code != STILL_ACTIVE)) { break; } _tx_win32_thread_resume(thread_ptr -> tx_thread_win32_thread_handle); _tx_win32_thread_run_signal(thread_ptr); _tx_win32_thread_sleep(1U); wait_count++; } while (wait_count < 100U); if ((GetExitCodeThread(thread_ptr -> tx_thread_win32_thread_handle, &exit_code) != 0) && (exit_code == STILL_ACTIVE)) { (void) TerminateThread(thread_ptr -> tx_thread_win32_thread_handle, 0U); (void) WaitForSingleObject(thread_ptr -> tx_thread_win32_thread_handle, INFINITE); } CloseHandle(thread_ptr -> tx_thread_win32_thread_handle); thread_ptr -> tx_thread_win32_thread_handle = NULL; } if (thread_ptr -> tx_thread_win32_thread_run_semaphore != NULL) { CloseHandle(thread_ptr -> tx_thread_win32_thread_run_semaphore); thread_ptr -> tx_thread_win32_thread_run_semaphore = NULL; } if (thread_ptr -> tx_thread_win32_thread_start_semaphore != NULL) { CloseHandle(thread_ptr -> tx_thread_win32_thread_start_semaphore); thread_ptr -> tx_thread_win32_thread_start_semaphore = NULL; } } void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save) { _tx_thread_smp_unprotect(tx_interrupt_save); _tx_win32_thread_cleanup(thread_ptr); tx_interrupt_save = _tx_thread_smp_protect(); TX_PARAMETER_NOT_USED(tx_interrupt_save); } void _tx_thread_reset_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save) { _tx_thread_delete_port_completion(thread_ptr, tx_interrupt_save); }