gthr-win32-thread.c revision 1.1 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