ReactOS 0.4.16-dev-822-gbcedb53
thread.cpp
Go to the documentation of this file.
1//
2// thread.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// The _beginthread(), _beginthreadex(), _endthread(), and _endthreadex().
7//
8// There are several key differences in behavior between _beginthread() and
9// _beginthreadex():
10//
11// * _beginthreadex() takes three additional parameters, which are passed on to
12// CreateThread(): a security descriptor for the new thread, the initial
13// thread state (running or asleep), and an optional out parameter to which
14// the thread id of the newly created thread will be stored.
15//
16// * The procedure passed to _beginthread() must be __cdecl and has no return
17// code. The routine passed to _beginthreadex() must be __stdcall and must
18// return a return code, which will be used as the thread exit code.
19// Likewise, _endthread() takes no parameter and always returns a thread exit
20// code of 0 if the thread exits without error, whereas _endthreadex() takes
21// an exit code.
22//
23// * _endthread() calls CloseHandle() on the handle returned from CreateThread().
24// Note that this means that a caller should not use this handle, since it is
25// possible that the thread will have terminated and the handle will have been
26// closed by the time that _beginthread() returns.
27//
28// _endthreadex() does not call CloseHandle() to close the handle: the caller
29// of _beginthreadex() is required to close the handle.
30//
31// * _beginthread() returns -1 on failure. _beginthreadex() returns zero on
32// failure (just as CreateThread() does).
33//
34#include <corecrt_internal.h>
35#include <process.h>
36#include <roapi.h>
37
38// In some compilation models, the compiler is able to detect that the return
39// statement at the end of thread_start is unreachable. We cannot suppress the
40// warning locally because it is a backend warning.
41#pragma warning(disable: 4702) // unreachable code
42#pragma warning(disable: 4984) // 'if constexpr' is a C++17 language extension
43
44
45namespace
46{
48 {
49 void operator()(__acrt_thread_parameter* const parameter) throw()
50 {
51 if (!parameter)
52 {
53 return;
54 }
55
56 if (parameter->_thread_handle)
57 {
58 CloseHandle(parameter->_thread_handle);
59 }
60
61 if (parameter->_module_handle)
62 {
63 FreeLibrary(parameter->_module_handle);
64 }
65
66 _free_crt(parameter);
67 }
68 };
69
70 using unique_thread_parameter = __crt_unique_heap_ptr<
73}
74
75template <typename ThreadProcedure, bool Ex>
76static unsigned long WINAPI thread_start(void* const parameter) throw()
77{
78 if (!parameter)
79 {
81 }
82
83 __acrt_thread_parameter* const context = static_cast<__acrt_thread_parameter*>(parameter);
84
86
88 {
89 context->_initialized_apartment = __acrt_RoInitialize(RO_INIT_MULTITHREADED) == S_OK;
90 }
91
92 __try
93 {
94 ThreadProcedure const procedure = reinterpret_cast<ThreadProcedure>(context->_procedure);
95 if constexpr (Ex)
96 {
97 _endthreadex(procedure(context->_context));
98 }
99 else
100 {
101 procedure(context->_context);
102 _endthreadex(0);
103 }
104 }
106 {
107 // Execution should never reach here:
109 }
111
112 // This return statement will never be reached. All execution paths result
113 // in the thread or process exiting.
114 return 0;
115}
116
117
118
120 void* const procedure,
121 void* const context
122 ) throw()
123{
124 unique_thread_parameter parameter(_calloc_crt_t(__acrt_thread_parameter, 1).detach());
125 if (!parameter)
126 {
127 return nullptr;
128 }
129
130 parameter.get()->_procedure = reinterpret_cast<void*>(procedure);
131 parameter.get()->_context = context;
132
133 // Attempt to bump the reference count of the module in which the user's
134 // thread procedure is defined, to ensure that the module will stay loaded
135 // as long as the thread is executing. We will release this HMDOULE when
136 // the thread procedure returns or _endthreadex is called.
138 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
139 reinterpret_cast<LPCWSTR>(procedure),
140 &parameter.get()->_module_handle);
141
142 return parameter.detach();
143}
144
146 _beginthread_proc_type const procedure,
147 unsigned int const stack_size,
148 void* const context
149 )
150{
151 _VALIDATE_RETURN(procedure != nullptr, EINVAL, reinterpret_cast<uintptr_t>(INVALID_HANDLE_VALUE));
152
153 unique_thread_parameter parameter(create_thread_parameter(reinterpret_cast<void*>(procedure), context));
154 if (!parameter)
155 {
156 return reinterpret_cast<uintptr_t>(INVALID_HANDLE_VALUE);
157 }
158
159 // We create the new thread in a suspended state so that we can update
160 // the parameter structure with the thread handle. The newly created
161 // thread is responsible for closing this handle.
163 HANDLE const thread_handle = CreateThread(
164 nullptr,
165 stack_size,
166 thread_start<_beginthread_proc_type, false>,
167 parameter.get(),
169 &thread_id);
170
171 if (!thread_handle)
172 {
174 return reinterpret_cast<uintptr_t>(INVALID_HANDLE_VALUE);
175 }
176
177 parameter.get()->_thread_handle = thread_handle;
178
179 // Now we can start the thread...
180 if (ResumeThread(thread_handle) == static_cast<DWORD>(-1))
181 {
183 return reinterpret_cast<uintptr_t>(INVALID_HANDLE_VALUE);
184 }
185
186 // If we successfully created the thread, the thread now owns its parameter:
187 parameter.detach();
188
189 return reinterpret_cast<uintptr_t>(thread_handle);
190}
191
193 void* const security_descriptor,
194 unsigned int const stack_size,
195 _beginthreadex_proc_type const procedure,
196 void* const context,
197 unsigned int const creation_flags,
198 unsigned int* const thread_id_result
199 )
200{
201 _VALIDATE_RETURN(procedure != nullptr, EINVAL, 0);
202
203 unique_thread_parameter parameter(create_thread_parameter((void*)procedure, context));
204 if (!parameter)
205 {
206 return 0;
207 }
208
210 HANDLE const thread_handle = CreateThread(
211 reinterpret_cast<LPSECURITY_ATTRIBUTES>(security_descriptor),
212 stack_size,
213 thread_start<_beginthreadex_proc_type, true>,
214 parameter.get(),
215 creation_flags,
216 &thread_id);
217
218 if (!thread_handle)
219 {
221 return 0;
222 }
223
224 if (thread_id_result)
225 {
226 *thread_id_result = thread_id;
227 }
228
229 // If we successfully created the thread, the thread now owns its parameter:
230 parameter.detach();
231
232 return reinterpret_cast<uintptr_t>(thread_handle);
233}
234
235
236
237static void __cdecl common_end_thread(unsigned int const return_code) throw()
238{
240 if (!ptd)
241 {
242 ExitThread(return_code);
243 }
244
245 __acrt_thread_parameter* const parameter = ptd->_beginthread_context;
246 if (!parameter)
247 {
248 ExitThread(return_code);
249 }
250
251 if (parameter->_initialized_apartment)
252 {
254 }
255
256 if (parameter->_thread_handle != INVALID_HANDLE_VALUE && parameter->_thread_handle != nullptr)
257 {
258 CloseHandle(parameter->_thread_handle);
259 }
260
261 if (parameter->_module_handle != INVALID_HANDLE_VALUE && parameter->_module_handle != nullptr)
262 {
263 FreeLibraryAndExitThread(parameter->_module_handle, return_code);
264 }
265 else
266 {
267 ExitThread(return_code);
268 }
269}
270
271extern "C" void __cdecl _endthread()
272{
273 return common_end_thread(0);
274}
275
276extern "C" void __cdecl _endthreadex(unsigned int const return_code)
277{
278 return common_end_thread(return_code);
279}
void _exit(int exitcode)
Definition: _exit.c:25
#define EINVAL
Definition: acclib.h:90
#define __cdecl
Definition: accygwin.h:79
__acrt_ptd *__cdecl __acrt_getptd(void)
void WINAPI __acrt_RoUninitialize(void)
begin_thread_init_policy __cdecl __acrt_get_begin_thread_init_policy(void)
void __cdecl __acrt_errno_map_os_error(unsigned long)
Definition: errno.cpp:91
__acrt_ptd *__cdecl __acrt_getptd_noexit(void)
@ begin_thread_init_policy_ro_initialize
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
_ACRTIMP int __cdecl _seh_filter_exe(_In_ unsigned long _ExceptionNum, _In_ struct _EXCEPTION_POINTERS *_ExceptionPtr)
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define FreeLibrary(x)
Definition: compat.h:748
BOOL WINAPI GetModuleHandleExW(IN DWORD dwFlags, IN LPCWSTR lpwModuleName OPTIONAL, OUT HMODULE *phModule)
Definition: loader.c:866
VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule, DWORD dwExitCode)
Definition: loader.c:507
DWORD WINAPI ResumeThread(IN HANDLE hThread)
Definition: thread.c:567
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:365
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
unsigned long DWORD
Definition: ntddk_ex.h:95
#define _free_crt
#define S_OK
Definition: intsafe.h:52
unsigned int uintptr_t
Definition: intrin.h:47
static DWORD thread_id
Definition: protocol.c:159
__crt_unique_heap_ptr< __acrt_thread_parameter, thread_parameter_free_policy > unique_thread_parameter
Definition: thread.cpp:72
#define __try
Definition: pseh2_64.h:172
#define __except
Definition: pseh2_64.h:173
#define __endtry
Definition: pseh2_64.h:175
#define GetExceptionInformation()
Definition: exception.h:72
#define GetExceptionCode()
Definition: exception.h:68
@ RO_INIT_MULTITHREADED
Definition: roapi.h:26
unsigned(__stdcall * _beginthreadex_proc_type)(void *)
Definition: process.h:85
uintptr_t __cdecl _beginthread(_beginthread_proc_type const procedure, unsigned int const stack_size, void *const context)
Definition: thread.cpp:145
static __acrt_thread_parameter *__cdecl create_thread_parameter(void *const procedure, void *const context)
Definition: thread.cpp:119
void __cdecl _endthreadex(unsigned int const return_code)
Definition: thread.cpp:276
uintptr_t __cdecl _beginthreadex(void *const security_descriptor, unsigned int const stack_size, _beginthreadex_proc_type const procedure, void *const context, unsigned int const creation_flags, unsigned int *const thread_id_result)
Definition: thread.cpp:192
void __cdecl _endthread()
Definition: thread.cpp:271
static void __cdecl common_end_thread(unsigned int const return_code)
Definition: thread.cpp:237
static unsigned long WINAPI thread_start(void *const parameter)
Definition: thread.cpp:76
__acrt_thread_parameter * _beginthread_context
void operator()(__acrt_thread_parameter *const parameter)
Definition: thread.cpp:49
Definition: http.c:7252
HRESULT WINAPI __acrt_RoInitialize(RO_INIT_TYPE const init_type)
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CREATE_SUSPENDED
Definition: winbase.h:181
#define WINAPI
Definition: msvc.h:6
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185