1 1.1 mrg /* Implementation of threads compatibility routines for libgcc2. */ 2 1.1 mrg 3 1.1 mrg /* Copyright (C) 1999-2024 Free Software Foundation, Inc. 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 8 1.1 mrg the terms of the GNU General Public License as published by the Free 9 1.1 mrg Software Foundation; either version 3, or (at your option) any later 10 1.1 mrg version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 1.1 mrg for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* This module is separate from the rest of the implementation because only 27 1.1 mrg one copy of it ought to be linked. */ 28 1.1 mrg 29 1.1 mrg /* The implementation strategy for the c++0x thread support is as follows. 30 1.1 mrg 31 1.1 mrg A GNU thread is represented by a Win32 HANDLE that is obtained when the 32 1.1 mrg Win32 thread is created, except of course for the initial thread. This 33 1.1 mrg Win32 HANDLE is stored in a descriptor keyed from TLS memory for every 34 1.1 mrg thread, so the self routine can return it instead of having to duplicate 35 1.1 mrg the pseudo-handle returned by GetCurrentThread each time it is invoked. 36 1.1 mrg For the initial thread, this Win32 HANDLE is created during the first 37 1.1 mrg call to the self routine using the aforementioned technique. 38 1.1 mrg 39 1.1 mrg Note that the equal routine compares the identifier of threads instead 40 1.1 mrg of their Win32 HANDLE, which will give the correct positive answer even 41 1.1 mrg in the case where distinct Win32 HANDLEs have been created for the same 42 1.1 mrg thread by multiple instances of libgcc included in the link. */ 43 1.1 mrg 44 1.1 mrg #include "gthr-win32.h" 45 1.1 mrg 46 1.1 mrg /* The thread descriptor keyed from TLS memory. */ 47 1.1 mrg struct __gthr_win32_thr_desc 48 1.1 mrg { 49 1.1 mrg void *(*func) (void*); 50 1.1 mrg void *args; 51 1.1 mrg HANDLE h; 52 1.1 mrg }; 53 1.1 mrg 54 1.1 mrg /* The TLS key used by one instance of the library. */ 55 1.1 mrg static __gthread_key_t __gthr_win32_tls = TLS_OUT_OF_INDEXES; 56 1.1 mrg 57 1.1 mrg /* The initialization device for the TLS key. */ 58 1.1 mrg static __gthread_once_t __gthr_win32_tls_once = __GTHREAD_ONCE_INIT; 59 1.1 mrg 60 1.1 mrg /* Initialize the TLS key. */ 61 1.1 mrg 62 1.1 mrg static void 63 1.1 mrg __gthr_win32_tls_init (void) 64 1.1 mrg { 65 1.1 mrg if (__gthread_key_create (&__gthr_win32_tls, free)) 66 1.1 mrg abort (); 67 1.1 mrg } 68 1.1 mrg 69 1.1 mrg /* Wrapper routine around thread functions. */ 70 1.1 mrg 71 1.1 mrg static DWORD 72 1.1 mrg __gthr_win32_thread_wrapper (void *args) 73 1.1 mrg { 74 1.1 mrg struct __gthr_win32_thr_desc *td = (struct __gthr_win32_thr_desc *) args; 75 1.1 mrg 76 1.1 mrg __gthread_setspecific (__gthr_win32_tls, td); 77 1.1 mrg 78 1.1 mrg DWORD exit_code = (DWORD) (ULONG_PTR) (*td->func) (td->args); 79 1.1 mrg 80 1.1 mrg ExitThread (exit_code); 81 1.1 mrg return exit_code; 82 1.1 mrg } 83 1.1 mrg 84 1.1 mrg /* Implement the __gthread_create routine. */ 85 1.1 mrg 86 1.1 mrg int 87 1.1 mrg __gthr_win32_create (__gthread_t *thr, void *(*func) (void*), void *args) 88 1.1 mrg { 89 1.1 mrg struct __gthr_win32_thr_desc *td; 90 1.1 mrg 91 1.1 mrg __gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init); 92 1.1 mrg 93 1.1 mrg td = malloc (sizeof (struct __gthr_win32_thr_desc)); 94 1.1 mrg td->func = func; 95 1.1 mrg td->args = args; 96 1.1 mrg td->h = CreateThread (NULL, 0, 97 1.1 mrg (LPTHREAD_START_ROUTINE) __gthr_win32_thread_wrapper, 98 1.1 mrg (LPVOID) td, CREATE_SUSPENDED, NULL); 99 1.1 mrg if (td->h) 100 1.1 mrg { 101 1.1 mrg ResumeThread (td->h); 102 1.1 mrg *thr = (__gthread_t) td->h; 103 1.1 mrg return 0; 104 1.1 mrg } 105 1.1 mrg else 106 1.1 mrg { 107 1.1 mrg free (td); 108 1.1 mrg return (int) GetLastError (); 109 1.1 mrg } 110 1.1 mrg } 111 1.1 mrg 112 1.1 mrg /* Implement the __gthread_join routine. */ 113 1.1 mrg 114 1.1 mrg int 115 1.1 mrg __gthr_win32_join (__gthread_t thr, void **value_ptr) 116 1.1 mrg { 117 1.1 mrg int status = 0; 118 1.1 mrg 119 1.1 mrg if (GetThreadId ((HANDLE) thr) == GetCurrentThreadId ()) 120 1.1 mrg return 1; 121 1.1 mrg 122 1.1 mrg if (WaitForSingleObject ((HANDLE) thr, INFINITE) == WAIT_OBJECT_0) 123 1.1 mrg { 124 1.1 mrg if (value_ptr) 125 1.1 mrg { 126 1.1 mrg DWORD exit_code; 127 1.1 mrg if (GetExitCodeThread ((HANDLE) thr, &exit_code)) 128 1.1 mrg *value_ptr = (void *) (ULONG_PTR) exit_code; 129 1.1 mrg else 130 1.1 mrg status = (int) GetLastError (); 131 1.1 mrg } 132 1.1 mrg } 133 1.1 mrg else 134 1.1 mrg status = (int) GetLastError (); 135 1.1 mrg 136 1.1 mrg CloseHandle ((HANDLE) thr); 137 1.1 mrg return status; 138 1.1 mrg } 139 1.1 mrg 140 1.1 mrg /* Implement the __gthread_self routine. */ 141 1.1 mrg 142 1.1 mrg __gthread_t 143 1.1 mrg __gthr_win32_self (void) 144 1.1 mrg { 145 1.1 mrg struct __gthr_win32_thr_desc *td; 146 1.1 mrg 147 1.1 mrg __gthread_once (&__gthr_win32_tls_once, __gthr_win32_tls_init); 148 1.1 mrg 149 1.1 mrg if (!(td = __gthread_getspecific (__gthr_win32_tls))) 150 1.1 mrg { 151 1.1 mrg HANDLE proc = GetCurrentProcess (); 152 1.1 mrg td = malloc (sizeof (struct __gthr_win32_thr_desc)); 153 1.1 mrg td->func = NULL; 154 1.1 mrg td->args = NULL; 155 1.1 mrg if (!DuplicateHandle (proc, GetCurrentThread(), proc, &td->h, 0, FALSE, 156 1.1 mrg DUPLICATE_SAME_ACCESS)) 157 1.1 mrg abort (); 158 1.1 mrg __gthread_setspecific (__gthr_win32_tls, td); 159 1.1 mrg } 160 1.1 mrg 161 1.1 mrg return td->h; 162 1.1 mrg } 163