]>
Commit | Line | Data |
---|---|---|
899905f6 | 1 | /* Threads compatibility routines for libgcc2. */ |
62dafdeb | 2 | /* Compile this one with gcc. */ |
f22a97d2 | 3 | /* Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
62dafdeb MK |
4 | Contributed by Mumit Khan <khan@xraylith.wisc.edu>. |
5 | ||
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU CC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GNU CC; see the file COPYING. If not, write to | |
20 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
21 | Boston, MA 02111-1307, USA. */ | |
22 | ||
23 | /* As a special exception, if you link this library with other files, | |
24 | some of which are compiled with GCC, to produce an executable, | |
25 | this library does not by itself cause the resulting executable | |
26 | to be covered by the GNU General Public License. | |
27 | This exception does not however invalidate any other reasons why | |
28 | the executable file might be covered by the GNU General Public License. */ | |
29 | ||
30 | #ifndef __gthr_win32_h | |
31 | #define __gthr_win32_h | |
32 | ||
33 | /* Windows32 threads specific definitions. The windows32 threading model | |
34 | does not map well into pthread-inspired gcc's threading model, and so | |
35 | there are caveats one needs to be aware of. | |
36 | ||
f22a97d2 MK |
37 | 1. The destructor supplied to __gthread_key_create is ignored for |
38 | generic x86-win32 ports. This will certainly cause memory leaks | |
39 | due to unreclaimed eh contexts (sizeof (eh_context) is at least | |
40 | 24 bytes for x86 currently). | |
62dafdeb MK |
41 | |
42 | This memory leak may be significant for long-running applications | |
43 | that make heavy use of C++ EH. | |
44 | ||
f22a97d2 MK |
45 | However, Mingw runtime (version 0.3 or newer) provides a mechanism |
46 | to emulate pthreads key dtors; the runtime provides a special DLL, | |
47 | linked in if -mthreads option is specified, that runs the dtors in | |
48 | the reverse order of registration when each thread exits. If | |
49 | -mthreads option is not given, a stub is linked in instead of the | |
50 | DLL, which results in memory leak. Other x86-win32 ports can use | |
51 | the same technique of course to avoid the leak. | |
52 | ||
62dafdeb MK |
53 | 2. The error codes returned are non-POSIX like, and cast into ints. |
54 | This may cause incorrect error return due to truncation values on | |
55 | hw where sizeof (DWORD) > sizeof (int). | |
f22a97d2 MK |
56 | |
57 | 3. We might consider using Critical Sections instead of Windows32 | |
58 | mutexes for better performance, but emulating __gthread_mutex_trylock | |
59 | interface becomes more complicated (Win9x does not support | |
60 | TryEnterCriticalSectioni, while NT does). | |
62dafdeb | 61 | |
f22a97d2 MK |
62 | The basic framework should work well enough. In the long term, GCC |
63 | needs to use Structured Exception Handling on Windows32. */ | |
62dafdeb MK |
64 | |
65 | #define __GTHREADS 1 | |
66 | ||
67 | #include <windows.h> | |
68 | #include <errno.h> | |
f22a97d2 MK |
69 | #ifdef __MINGW32__ |
70 | #include <_mingw.h> | |
71 | #endif | |
62dafdeb MK |
72 | |
73 | typedef DWORD __gthread_key_t; | |
74 | ||
75 | typedef struct { | |
76 | int done; | |
77 | long started; | |
78 | } __gthread_once_t; | |
79 | ||
80 | typedef HANDLE __gthread_mutex_t; | |
81 | ||
82 | #define __GTHREAD_ONCE_INIT {FALSE, -1} | |
83 | #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function | |
84 | ||
f22a97d2 MK |
85 | #if __MINGW32_MAJOR_VERSION >= 1 || \ |
86 | (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2) | |
87 | #define MINGW32_SUPPORTS_MT_EH 1 | |
3fe41456 | 88 | extern int __mingwthr_key_dtor PARAMS ((DWORD, void (*) (void *))); |
f22a97d2 MK |
89 | /* Mingw runtime >= v0.3 provides a magic variable that is set to non-zero |
90 | if -mthreads option was specified, or 0 otherwise. This is to get around | |
91 | the lack of weak symbols in PE-COFF. */ | |
92 | extern int _CRT_MT; | |
93 | #endif | |
94 | ||
62dafdeb | 95 | static inline int |
d1e51320 | 96 | __gthread_active_p (void) |
62dafdeb | 97 | { |
f22a97d2 MK |
98 | #ifdef MINGW32_SUPPORTS_MT_EH |
99 | return _CRT_MT; | |
100 | #else | |
62dafdeb | 101 | return 1; |
f22a97d2 | 102 | #endif |
62dafdeb MK |
103 | } |
104 | ||
105 | static inline int | |
d1e51320 | 106 | __gthread_once (__gthread_once_t *once, void (*func) (void)) |
62dafdeb MK |
107 | { |
108 | if (! __gthread_active_p ()) | |
109 | return -1; | |
110 | else if (once == NULL || func == NULL) | |
111 | return EINVAL; | |
112 | ||
113 | if (! once->done) | |
114 | { | |
115 | if (InterlockedIncrement (&(once->started)) == 0) | |
116 | { | |
117 | (*func) (); | |
118 | once->done = TRUE; | |
119 | } | |
f22a97d2 MK |
120 | else |
121 | { | |
122 | /* Another thread is currently executing the code, so wait for it | |
123 | to finish; yield the CPU in the meantime. If performance | |
124 | does become an issue, the solution is to use an Event that | |
125 | we wait on here (and set above), but that implies a place to | |
126 | create the event before this routine is called. */ | |
127 | while (! once->done) | |
128 | Sleep (0); | |
129 | } | |
62dafdeb MK |
130 | } |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
f22a97d2 MK |
135 | /* Windows32 thread local keys don't support destructors; this leads to |
136 | leaks, especially in threaded applications making extensive use of | |
137 | C++ EH. Mingw uses a thread-support DLL to work-around this problem. */ | |
62dafdeb | 138 | static inline int |
f22a97d2 | 139 | __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) |
62dafdeb MK |
140 | { |
141 | int status = 0; | |
142 | DWORD tls_index = TlsAlloc (); | |
143 | if (tls_index != 0xFFFFFFFF) | |
f22a97d2 MK |
144 | { |
145 | *key = tls_index; | |
146 | #ifdef MINGW32_SUPPORTS_MT_EH | |
147 | /* Mingw runtime will run the dtors in reverse order for each thread | |
148 | when the thread exits. */ | |
149 | status = __mingwthr_key_dtor (*key, dtor); | |
150 | #endif | |
151 | } | |
62dafdeb MK |
152 | else |
153 | status = (int) GetLastError (); | |
154 | return status; | |
155 | } | |
156 | ||
f22a97d2 MK |
157 | /* Currently, this routine is called only for Mingw runtime, and if |
158 | -mthreads option is chosen to link in the thread support DLL. */ | |
62dafdeb MK |
159 | static inline int |
160 | __gthread_key_dtor (__gthread_key_t key, void *ptr) | |
161 | { | |
f22a97d2 MK |
162 | /* Nothing needed. */ |
163 | return 0; | |
62dafdeb MK |
164 | } |
165 | ||
62dafdeb MK |
166 | static inline int |
167 | __gthread_key_delete (__gthread_key_t key) | |
168 | { | |
169 | return (TlsFree (key) != 0) ? 0 : (int) GetLastError (); | |
170 | } | |
171 | ||
172 | static inline void * | |
173 | __gthread_getspecific (__gthread_key_t key) | |
174 | { | |
175 | return TlsGetValue (key); | |
176 | } | |
177 | ||
178 | static inline int | |
179 | __gthread_setspecific (__gthread_key_t key, const void *ptr) | |
180 | { | |
f22a97d2 | 181 | return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError (); |
62dafdeb MK |
182 | } |
183 | ||
184 | static inline void | |
185 | __gthread_mutex_init_function (__gthread_mutex_t *mutex) | |
186 | { | |
187 | /* Create unnamed mutex with default security attr and no initial owner. */ | |
188 | *mutex = CreateMutex (NULL, 0, NULL); | |
189 | } | |
190 | ||
191 | static inline int | |
192 | __gthread_mutex_lock (__gthread_mutex_t *mutex) | |
193 | { | |
194 | int status = 0; | |
195 | ||
196 | if (__gthread_active_p ()) | |
197 | { | |
198 | if (WaitForSingleObject (*mutex, INFINITE) == WAIT_OBJECT_0) | |
199 | status = 0; | |
200 | else | |
201 | status = 1; | |
202 | } | |
203 | return status; | |
204 | } | |
205 | ||
206 | static inline int | |
207 | __gthread_mutex_trylock (__gthread_mutex_t *mutex) | |
208 | { | |
209 | int status = 0; | |
210 | ||
211 | if (__gthread_active_p ()) | |
212 | { | |
213 | if (WaitForSingleObject (*mutex, 0) == WAIT_OBJECT_0) | |
214 | status = 0; | |
215 | else | |
216 | status = 1; | |
217 | } | |
218 | return status; | |
219 | } | |
220 | ||
221 | static inline int | |
222 | __gthread_mutex_unlock (__gthread_mutex_t *mutex) | |
223 | { | |
224 | if (__gthread_active_p ()) | |
225 | return (ReleaseMutex (*mutex) != 0) ? 0 : 1; | |
226 | else | |
227 | return 0; | |
228 | } | |
229 | ||
230 | #endif /* not __gthr_win32_h */ | |
231 |