OSDN Git Service

Revert:
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / gthr-win32.c
1 /* Implementation of W32-specific threads compatibility routines for
2    libgcc2.  */
3
4 /* Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
5    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
6    Modified and moved to separate file by Danny Smith
7    <dannysmith@users.sourceforge.net>.
8
9 This file is part of GCC.
10
11 GCC is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 2, or (at your option) any later
14 version.
15
16 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with GCC; see the file COPYING.  If not, write to the Free
23 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301, USA.  */
25
26 /* As a special exception, if you link this library with other files,
27    some of which are compiled with GCC, to produce an executable,
28    this library does not by itself cause the resulting executable
29    to be covered by the GNU General Public License.
30    This exception does not however invalidate any other reasons why
31    the executable file might be covered by the GNU General Public License.  */
32
33
34 #include <windows.h>
35 #ifndef __GTHREAD_HIDE_WIN32API
36 # define __GTHREAD_HIDE_WIN32API 1
37 #endif
38 #undef  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
39 #define __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
40 #include <gthr-win32.h>
41
42 /* Windows32 threads specific definitions. The windows32 threading model
43    does not map well into pthread-inspired gcc's threading model, and so 
44    there are caveats one needs to be aware of.
45
46    1. The destructor supplied to __gthread_key_create is ignored for
47       generic x86-win32 ports. This will certainly cause memory leaks 
48       due to unreclaimed eh contexts (sizeof (eh_context) is at least 
49       24 bytes for x86 currently).
50
51       This memory leak may be significant for long-running applications
52       that make heavy use of C++ EH.
53
54       However, Mingw runtime (version 0.3 or newer) provides a mechanism
55       to emulate pthreads key dtors; the runtime provides a special DLL,
56       linked in if -mthreads option is specified, that runs the dtors in
57       the reverse order of registration when each thread exits. If
58       -mthreads option is not given, a stub is linked in instead of the
59       DLL, which results in memory leak. Other x86-win32 ports can use 
60       the same technique of course to avoid the leak.
61
62    2. The error codes returned are non-POSIX like, and cast into ints.
63       This may cause incorrect error return due to truncation values on 
64       hw where sizeof (DWORD) > sizeof (int).
65    
66    3. We are currently using a special mutex instead of the Critical
67       Sections, since Win9x does not support TryEnterCriticalSection
68       (while NT does).
69   
70    The basic framework should work well enough. In the long term, GCC
71    needs to use Structured Exception Handling on Windows32.  */
72
73 int
74 __gthr_win32_once (__gthread_once_t *once, void (*func) (void))
75 {
76   if (once == NULL || func == NULL)
77     return EINVAL;
78
79   if (! once->done)
80     {
81       if (InterlockedIncrement (&(once->started)) == 0)
82         {
83           (*func) ();
84           once->done = TRUE;
85         }
86       else
87         {
88           /* Another thread is currently executing the code, so wait for it 
89              to finish; yield the CPU in the meantime.  If performance 
90              does become an issue, the solution is to use an Event that 
91              we wait on here (and set above), but that implies a place to 
92              create the event before this routine is called.  */ 
93           while (! once->done)
94             Sleep (0);
95         }
96     }
97   return 0;
98 }
99
100 /* Windows32 thread local keys don't support destructors; this leads to
101    leaks, especially in threaded applications making extensive use of 
102    C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
103
104 int
105 __gthr_win32_key_create (__gthread_key_t *key,
106                          void (*dtor) (void *) __attribute__((unused)))
107 {
108   int status = 0;
109   DWORD tls_index = TlsAlloc ();
110   if (tls_index != 0xFFFFFFFF)
111     {
112       *key = tls_index;
113 #ifdef MINGW32_SUPPORTS_MT_EH
114       /* Mingw runtime will run the dtors in reverse order for each thread
115          when the thread exits.  */
116       status = __mingwthr_key_dtor (*key, dtor);
117 #endif
118     }
119   else
120     status = (int) GetLastError ();
121   return status;
122 }
123
124 int
125 __gthr_win32_key_delete (__gthread_key_t key)
126 {
127   return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
128 }
129
130 void *
131 __gthr_win32_getspecific (__gthread_key_t key)
132 {
133   DWORD lasterror;
134   void *ptr;
135   lasterror = GetLastError();
136   ptr = TlsGetValue(key);
137   SetLastError( lasterror );
138   return ptr;
139 }
140
141 int
142 __gthr_win32_setspecific (__gthread_key_t key, const void *ptr)
143 {
144   return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
145 }
146
147 void
148 __gthr_win32_mutex_init_function (__gthread_mutex_t *mutex)
149 {
150   mutex->counter = -1;
151   mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
152 }
153
154 int
155 __gthr_win32_mutex_lock (__gthread_mutex_t *mutex)
156 {
157   if (InterlockedIncrement (&mutex->counter) == 0 ||
158       WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
159     return 0;
160   else
161     {
162       /* WaitForSingleObject returns WAIT_FAILED, and we can only do
163          some best-effort cleanup here.  */
164       InterlockedDecrement (&mutex->counter);
165       return 1;
166     }
167 }
168
169 int
170 __gthr_win32_mutex_trylock (__gthread_mutex_t *mutex)
171 {
172   if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
173     return 0;
174   else
175     return 1;
176 }
177
178 int
179 __gthr_win32_mutex_unlock (__gthread_mutex_t *mutex)
180 {
181   if (InterlockedDecrement (&mutex->counter) >= 0)
182     return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
183   else
184     return 0;
185 }
186
187 void
188 __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
189 {
190   mutex->counter = -1;
191   mutex->depth = 0;
192   mutex->owner = 0;
193   mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
194 }
195
196 int
197 __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
198 {
199   DWORD me = GetCurrentThreadId();
200   if (InterlockedIncrement (&mutex->counter) == 0)
201     {
202       mutex->depth = 1;
203       mutex->owner = me;
204     }
205   else if (mutex->owner == me)
206     {
207       InterlockedDecrement (&mutex->counter);
208       ++(mutex->depth);
209     }
210   else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
211     {
212       mutex->depth = 1;
213       mutex->owner = me;
214     }
215   else
216     {
217       /* WaitForSingleObject returns WAIT_FAILED, and we can only do
218          some best-effort cleanup here.  */
219       InterlockedDecrement (&mutex->counter);
220       return 1;
221     }
222   return 0;
223 }
224
225 int
226 __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
227 {
228   DWORD me = GetCurrentThreadId();
229   if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
230     {
231       mutex->depth = 1;
232       mutex->owner = me;
233     }
234   else if (mutex->owner == me)
235     ++(mutex->depth);
236   else
237     return 1;
238
239   return 0;
240 }
241
242 int
243 __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
244 {
245   --(mutex->depth);
246   if (mutex->depth == 0)
247     {
248       mutex->owner = 0;
249
250       if (InterlockedDecrement (&mutex->counter) >= 0)
251         return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
252     }
253
254   return 0;
255 }