summaryrefslogtreecommitdiff
path: root/libgcc/config/i386/gthr-win32-thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgcc/config/i386/gthr-win32-thread.c')
-rw-r--r--libgcc/config/i386/gthr-win32-thread.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/libgcc/config/i386/gthr-win32-thread.c b/libgcc/config/i386/gthr-win32-thread.c
new file mode 100644
index 00000000000..81e6fd094c7
--- /dev/null
+++ b/libgcc/config/i386/gthr-win32-thread.c
@@ -0,0 +1,162 @@
+/* Implementation of threads compatibility routines for libgcc2. */
+
+/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/* This module is separate from the rest of the implementation because only
+ one copy of it ought to be linked. */
+
+/* The implementation strategy for the c++0x thread support is as follows.
+
+ A GNU thread is represented by a Win32 HANDLE that is obtained when the
+ Win32 thread is created, except of course for the initial thread. This
+ Win32 HANDLE is stored in a descriptor keyed from TLS memory for every
+ thread, so the self routine can return it instead of having to duplicate
+ the pseudo-handle returned by GetCurrentThread each time it is invoked.
+ For the initial thread, this Win32 HANDLE is created during the first
+ call to the self routine using the aforementioned technique.
+
+ Note that the equal routine compares the identifier of threads instead
+ of their Win32 HANDLE, which will give the correct positive answer even
+ in the case where distinct Win32 HANDLEs have been created for the same
+ thread by multiple instances of libgcc included in the link. */
+
+#include "gthr-win32.h"
+
+/* The thread descriptor keyed from TLS memory. */
+struct __gthr_win32_thr_desc
+{
+ void *(*func) (void*);
+ void *args;
+ HANDLE h;
+};
+
+/* The TLS key used by one instance of the library. */
+static __gthread_key_t __gthr_win32_tls = TLS_OUT_OF_INDEXES;
+
+/* The initialization device for the TLS key. */
+static __gthread_once_t __gthr_win32_tls_once = __GTHREAD_ONCE_INIT;
+
+/* Initialize the TLS key. */
+
+static void
+__gthr_win32_tls_init (void)
+{
+ if (__gthread_key_create (&__gthr_win32_tls, free))
+ abort ();
+}
+
+/* Wrapper routine around thread functions. */
+
+static DWORD
+__gthr_win32_thread_wrapper (void *args)
+{
+ struct __gthr_win32_thr_desc *td = (struct __gthr_win32_thr_desc *) args;
+
+ __gthread_setspecific (__gthr_win32_tls, td);
+
+ DWORD exit_code = (DWORD) (ULONG_PTR) (*td->func) (td->args);
+
+ ExitThread (exit_code);
+ return exit_code;
+}
+
+/* Implement the __gthread_create routine. */
+
+int
+__gthr_win32_create (__gthread_t *thr, void *(*func) (void*), void *args)
+{
+ struct __gthr_win32_thr_desc *td;
+
+ __gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init);
+
+ td = malloc (sizeof (struct __gthr_win32_thr_desc));
+ td->func = func;
+ td->args = args;
+ td->h = CreateThread (NULL, 0,
+ (LPTHREAD_START_ROUTINE) __gthr_win32_thread_wrapper,
+ (LPVOID) td, CREATE_SUSPENDED, NULL);
+ if (td->h)
+ {
+ ResumeThread (td->h);
+ *thr = (__gthread_t) td->h;
+ return 0;
+ }
+ else
+ {
+ free (td);
+ return (int) GetLastError ();
+ }
+}
+
+/* Implement the __gthread_join routine. */
+
+int
+__gthr_win32_join (__gthread_t thr, void **value_ptr)
+{
+ int status = 0;
+
+ if (GetThreadId ((HANDLE) thr) == GetCurrentThreadId ())
+ return 1;
+
+ if (WaitForSingleObject ((HANDLE) thr, INFINITE) == WAIT_OBJECT_0)
+ {
+ if (value_ptr)
+ {
+ DWORD exit_code;
+ if (GetExitCodeThread ((HANDLE) thr, &exit_code))
+ *value_ptr = (void *) (ULONG_PTR) exit_code;
+ else
+ status = (int) GetLastError ();
+ }
+ }
+ else
+ status = (int) GetLastError ();
+
+ CloseHandle ((HANDLE) thr);
+ return status;
+}
+
+/* Implement the __gthread_self routine. */
+
+__gthread_t
+__gthr_win32_self (void)
+{
+ struct __gthr_win32_thr_desc *td;
+
+ __gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init);
+
+ if (!(td = __gthread_getspecific (__gthr_win32_tls)))
+ {
+ HANDLE proc = GetCurrentProcess ();
+ td = malloc (sizeof (struct __gthr_win32_thr_desc));
+ td->func = NULL;
+ td->args = NULL;
+ if (!DuplicateHandle (proc, GetCurrentThread(), proc, &td->h, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ abort ();
+ __gthread_setspecific (__gthr_win32_tls, td);
+ }
+
+ return td->h;
+}