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