Function _beginthreadex() is implemented as wrapper around the CRT
_beginthread() function and _endthreadex() as wrapper around the WinAPI
ExitThread() function.
---
mingw-w64-crt/Makefile.am | 13 +-
mingw-w64-crt/misc/_beginthreadex.c | 181 ++++++++++++++++++++++++++++
mingw-w64-crt/misc/_endthreadex.c | 20 +++
3 files changed, 213 insertions(+), 1 deletion(-)
create mode 100644 mingw-w64-crt/misc/_beginthreadex.c
create mode 100644 mingw-w64-crt/misc/_endthreadex.c
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 33a5290409b4..e6a255d4995c 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -916,6 +916,8 @@ src_pre_msvcrt20=\
misc/__p__winver.c \
misc/__timezone.c \
misc/__tzname.c \
+ misc/_beginthreadex.c \
+ misc/_endthreadex.c \
stdio/_wfindfirst32.c \
stdio/_wfindnext32.c \
stdio/_wstat32.c \
@@ -1043,10 +1045,12 @@ src_pre_msvcr90=\
src_pre_msvcr100=\
misc/i386__XcptFilter.c \
misc/i386__beginthread.c \
- misc/i386__beginthreadex.c \
misc/_invalid_parameter_noinfo_noreturn.c \
misc/imaxdiv.c
+src_pre_msvcr100_post_msvcrt10=\
+ misc/i386__beginthreadex.c
+
src_pre_msvcr110=\
stdio/msvcr110pre_fstat32.c \
stdio/msvcr110pre_fstat64i32.c \
@@ -1130,6 +1134,7 @@ src_msvcrt20=\
$(src_pre_msvcr80) \
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
misc/msvcrt20__getmainargs.c \
@@ -1142,6 +1147,7 @@ src_msvcrt40=\
$(src_pre_msvcr80) \
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
misc/msvcrt__getmainargs.c \
@@ -1153,6 +1159,7 @@ src_msvcrtd=\
$(src_pre_msvcr80) \
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
locale/___lc_codepage_func.c \
@@ -1165,6 +1172,7 @@ src_msvcr70=\
$(src_pre_msvcr80) \
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
misc/__p__osplatform.c
@@ -1173,6 +1181,7 @@ src_msvcr71=\
$(src_pre_msvcr80) \
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
misc/__p__osplatform.c
@@ -1180,6 +1189,7 @@ src_msvcr71=\
src_msvcr80=\
$(src_pre_msvcr90) \
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
$(src_pre_msvcr120_post_msvcr71) \
@@ -1187,6 +1197,7 @@ src_msvcr80=\
src_msvcr90=\
$(src_pre_msvcr100) \
+ $(src_pre_msvcr100_post_msvcrt10) \
$(src_pre_msvcr110) \
$(src_pre_msvcr120) \
$(src_pre_msvcr120_post_msvcr71) \
diff --git a/mingw-w64-crt/misc/_beginthreadex.c
b/mingw-w64-crt/misc/_beginthreadex.c
new file mode 100644
index 000000000000..dad6eccf97ff
--- /dev/null
+++ b/mingw-w64-crt/misc/_beginthreadex.c
@@ -0,0 +1,181 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <errno.h>
+#include <process.h>
+#include <windows.h>
+
+#if defined(__i386__)
+#include "i386_sse_float_exception_handler.h"
+uintptr_t __cdecl __msvcrt_beginthread(_beginthread_proc_type start_address,
unsigned stack_size, void *arglist);
+#define _beginthread __msvcrt_beginthread
+#endif
+
+#if defined(__i386__)
+/* We need to make sure that we align the stack to 16 bytes for the sake of
SSE */
+__attribute__((force_align_arg_pointer))
+#endif
+__MINGW_ATTRIB_NORETURN
+static void __cdecl thread_func(void *data)
+{
+ unsigned ret;
+ void **thread_args = data;
+ _beginthreadex_proc_type start_address = thread_args[0];
+ void *arglist = thread_args[1];
+ unsigned *thread_id_ptr = thread_args[2];
+ HANDLE child_initialized = thread_args[3];
+ HANDLE child_can_run = thread_args[4];
+
+ /* Store our spawned thread id if the caller asked for it. */
+ if (thread_id_ptr)
+ *thread_id_ptr = GetCurrentThreadId();
+
+ /* Inform the parent thread that we (child) have stopped using the
+ * thread_args[] array (which is stored on the parent thread stack).
+ * After this step the parent thread can deallocate the thread_args[]
+ * array and destroy events which owns.
+ */
+ _ReadWriteBarrier();
+ SetEvent(child_initialized);
+
+ /* Wait until the _beginthreadex() parent finish its initialization.
+ * This prevents executing of the application's start_address which
+ * could close the thread handle and break our _beginthreadex().
+ * This also prevents executing of the application's start_address
+ * if our thread should be in the CREATE_SUSPENDED state.
+ */
+ WaitForSingleObject(child_can_run, INFINITE);
+ CloseHandle(child_can_run);
+
+ /* Call the application supplied thread function. */
+#if defined(__i386__)
+ EXCEPTION_REGISTRATION_RECORD exception_record = {
+ .Next = (EXCEPTION_REGISTRATION_RECORD *)__readfsdword(0),
+ .Handler = (PEXCEPTION_ROUTINE)(INT_PTR)sse_float_exception_handler,
+ };
+ __writefsdword(0, (DWORD)&exception_record);
+#endif
+ ret = start_address(arglist);
+#if defined(__i386__)
+ __writefsdword(0, (DWORD)exception_record.Next);
+#endif
+
+ /* Ensure that our thread function never returns back to the caller as
+ * our caller (which is _beginthread) automatically closes the thread handle.
+ * Thread spawned by the _beginthreadex() must not close the thread handle.
+ */
+ ExitThread(ret);
+}
+
+/* mingw-w64 _beginthreadex() implementation is wrapper around the CRT
_beginthread() function. */
+uintptr_t __cdecl _beginthreadex(void *security, unsigned stack_size,
_beginthreadex_proc_type start_address, void *arglist, unsigned initflag,
unsigned *thread_id_ptr)
+{
+ void *thread_args[5];
+ uintptr_t thread_handle;
+ SECURITY_ATTRIBUTES *sec_attrs;
+ HANDLE child_initialized;
+ HANDLE child_can_run;
+ BOOL create_suspended = FALSE;
+ BOOL inherit_handle = FALSE;
+ SECURITY_DESCRIPTOR *dacl_descriptor = NULL;
+
+ if (initflag) {
+ if (initflag & ~(CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION)) {
+ /* Invalid initflag was passed. */
+ errno = EINVAL;
+ return 0;
+ }
+ if (initflag & CREATE_SUSPENDED)
+ create_suspended = TRUE;
+ /* STACK_SIZE_PARAM_IS_A_RESERVATION is ignored, new thread would have
just larger preallocated stack. */
+ }
+
+ if (security) {
+ sec_attrs = security;
+ if (sec_attrs->nLength != sizeof(*sec_attrs)) {
+ /* Invalid SECURITY_ATTRIBUTES structure was passed. */
+ errno = EINVAL;
+ return 0;
+ }
+ inherit_handle = sec_attrs->bInheritHandle;
+ dacl_descriptor = sec_attrs->lpSecurityDescriptor;
+ }
+
+ child_initialized = CreateEventA(NULL, TRUE, FALSE, NULL);
+ if (!child_initialized) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ child_can_run = CreateEventA(NULL, TRUE, FALSE, NULL);
+ if (!child_can_run) {
+ CloseHandle(child_initialized);
+ errno = ENOMEM;
+ return 0;
+ }
+
+ thread_args[0] = (void *)start_address;
+ thread_args[1] = arglist;
+ thread_args[2] = thread_id_ptr;
+ thread_args[3] = child_initialized;
+ thread_args[4] = child_can_run;
+ thread_handle = _beginthread(thread_func, stack_size, thread_args);
+
+ if (thread_handle != (uintptr_t)-1) {
+ /* Set HANDLE_FLAG_INHERIT and DACL_SECURITY_INFORMATION as soon as
possible. */
+ if (inherit_handle)
+ SetHandleInformation((HANDLE)thread_handle, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT);
+ if (dacl_descriptor)
+ SetKernelObjectSecurity((HANDLE)thread_handle,
DACL_SECURITY_INFORMATION, dacl_descriptor);
+
+ /* Wait until the child thread_func started, filled the thread_id_ptr,
+ * stopped using our stack variables, including the automatic array of
+ * arguments OR the newly spawned child thread crashed/finished.
+ */
+ if (WaitForMultipleObjects(2, (HANDLE[]){(HANDLE)thread_handle,
child_initialized}, FALSE, INFINITE) == WAIT_OBJECT_0) {
+ /* If the newly spawned thread crashed/finished (returns WAIT_OBJECT_0)
+ * before signaling the successful startup (returns WAIT_OBJECT_1)
+ * then treat it as an _beginthread() error.
+ */
+ CloseHandle((HANDLE)thread_handle);
+ thread_handle = (uintptr_t)-1;
+ errno = EINVAL;
+ }
+ _ReadWriteBarrier();
+ }
+
+ CloseHandle(child_initialized);
+
+ /* _beginthread() returned -1 on error but _beginthreadex() has to return 0
on error.
+ * _beginthread() already set errno if error happened and above code called
+ * only WinAPI functions which do not modify CRT errno at all.
+ */
+ if (thread_handle == (uintptr_t)-1) {
+ CloseHandle(child_can_run);
+ return 0;
+ }
+
+ /* If the CREATE_SUSPENDED flag was passed then now suspend the child thread.
+ * SuspendThread() is asynchronous function and it returns before the thread
+ * is suspended. To wait until the thread is suspended, it is needed to call
+ * some synchronous operation which forces the suspend request to be
processed.
+ * GetThreadContext() is one of such function. See:
+ * https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
+ */
+ if (create_suspended) {
+ SuspendThread((HANDLE)thread_handle);
+ GetThreadContext((HANDLE)thread_handle, &(CONTEXT){.ContextFlags =
CONTEXT_CONTROL});
+ }
+
+ /* Now tell the child thread that it can execute the application's
start_address.
+ * If the child thread is suspended then it will start execution after is
resumed.
+ * Child thread will also closes the child_can_run handle.
+ */
+ SetEvent(child_can_run);
+
+ return thread_handle;
+}
+uintptr_t (__cdecl *__MINGW_IMP_SYMBOL(_beginthreadex))(void *, unsigned,
_beginthreadex_proc_type, void *, unsigned, unsigned *) = _beginthreadex;
diff --git a/mingw-w64-crt/misc/_endthreadex.c
b/mingw-w64-crt/misc/_endthreadex.c
new file mode 100644
index 000000000000..31243abb7fdf
--- /dev/null
+++ b/mingw-w64-crt/misc/_endthreadex.c
@@ -0,0 +1,20 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <process.h>
+#include <windows.h>
+
+__MINGW_ATTRIB_NORETURN
+void __cdecl _endthreadex(unsigned retval)
+{
+ /* Do not call _endthread() as it automatically closes the thread handle.
+ * Function _endthreadex() must not close the thread handle.
+ * CRT DLL library always correctly release thread resources via its DLL
entrypoint callback.
+ * So calling just the WinAPI ExitThread() is enough, no memory leak is
possible.
+ */
+ ExitThread(retval);
+}
+void (__cdecl *__MINGW_IMP_SYMBOL(_endthreadex))(unsigned) = _endthreadex;
--
2.20.1
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public