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