OSDN Git Service

Standardize header guards.
[pf3gnuchains/gcc-fork.git] / gcc / gthr-win32.h
1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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 GCC_GTHR_WIN32_H
31 #define GCC_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
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).
41
42       This memory leak may be significant for long-running applications
43       that make heavy use of C++ EH.
44
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
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).
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).
61   
62    The basic framework should work well enough. In the long term, GCC
63    needs to use Structured Exception Handling on Windows32.  */
64
65 #define __GTHREADS 1
66
67 #include <windows.h>
68 #include <errno.h>
69 #ifdef __MINGW32__
70 #include <_mingw.h>
71 #endif
72
73 #ifdef _LIBOBJC
74
75 /* Key structure for maintaining thread specific storage */
76 static DWORD    __gthread_objc_data_tls = (DWORD)-1;
77
78 /* Backend initialization functions */
79
80 /* Initialize the threads subsystem. */
81 int
82 __gthread_objc_init_thread_system(void)
83 {
84   /* Initialize the thread storage key */
85   if ((__gthread_objc_data_tls = TlsAlloc()) != (DWORD)-1)
86     return 0;
87   else
88     return -1;
89 }
90
91 /* Close the threads subsystem. */
92 int
93 __gthread_objc_close_thread_system(void)
94 {
95   if (__gthread_objc_data_tls != (DWORD)-1)
96     TlsFree(__gthread_objc_data_tls);
97   return 0;
98 }
99
100 /* Backend thread functions */
101
102 /* Create a new thread of execution. */
103 objc_thread_t
104 __gthread_objc_thread_detach(void (*func)(void *arg), void *arg)
105 {
106   DWORD thread_id = 0;
107   HANDLE win32_handle;
108
109   if (!(win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func,
110                                    arg, 0, &thread_id)))
111     thread_id = 0;
112   
113   return (objc_thread_t)thread_id;
114 }
115
116 /* Set the current thread's priority. */
117 int
118 __gthread_objc_thread_set_priority(int priority)
119 {
120   int sys_priority = 0;
121
122   switch (priority)
123     {
124     case OBJC_THREAD_INTERACTIVE_PRIORITY:
125       sys_priority = THREAD_PRIORITY_NORMAL;
126       break;
127     default:
128     case OBJC_THREAD_BACKGROUND_PRIORITY:
129       sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
130       break;
131     case OBJC_THREAD_LOW_PRIORITY:
132       sys_priority = THREAD_PRIORITY_LOWEST;
133       break;
134     }
135
136   /* Change priority */
137   if (SetThreadPriority(GetCurrentThread(), sys_priority))
138     return 0;
139   else
140     return -1;
141 }
142
143 /* Return the current thread's priority. */
144 int
145 __gthread_objc_thread_get_priority(void)
146 {
147   int sys_priority;
148
149   sys_priority = GetThreadPriority(GetCurrentThread());
150   
151   switch (sys_priority)
152     {
153     case THREAD_PRIORITY_HIGHEST:
154     case THREAD_PRIORITY_TIME_CRITICAL:
155     case THREAD_PRIORITY_ABOVE_NORMAL:
156     case THREAD_PRIORITY_NORMAL:
157       return OBJC_THREAD_INTERACTIVE_PRIORITY;
158
159     default:
160     case THREAD_PRIORITY_BELOW_NORMAL:
161       return OBJC_THREAD_BACKGROUND_PRIORITY;
162     
163     case THREAD_PRIORITY_IDLE:
164     case THREAD_PRIORITY_LOWEST:
165       return OBJC_THREAD_LOW_PRIORITY;
166     }
167
168   /* Couldn't get priority. */
169   return -1;
170 }
171
172 /* Yield our process time to another thread. */
173 void
174 __gthread_objc_thread_yield(void)
175 {
176   Sleep(0);
177 }
178
179 /* Terminate the current thread. */
180 int
181 __gthread_objc_thread_exit(void)
182 {
183   /* exit the thread */
184   ExitThread(__gthread_objc_thread_exit_status);
185
186   /* Failed if we reached here */
187   return -1;
188 }
189
190 /* Returns an integer value which uniquely describes a thread. */
191 objc_thread_t
192 __gthread_objc_thread_id(void)
193 {
194   return (objc_thread_t)GetCurrentThreadId();
195 }
196
197 /* Sets the thread's local storage pointer. */
198 int
199 __gthread_objc_thread_set_data(void *value)
200 {
201   if (TlsSetValue(__gthread_objc_data_tls, value))
202     return 0;
203   else
204     return -1;
205 }
206
207 /* Returns the thread's local storage pointer. */
208 void *
209 __gthread_objc_thread_get_data(void)
210 {
211   DWORD lasterror;
212   void *ptr;
213
214   lasterror = GetLastError();
215
216   ptr = TlsGetValue(__gthread_objc_data_tls);          /* Return thread data.      */
217
218   SetLastError( lasterror );
219
220   return ptr;
221 }
222
223 /* Backend mutex functions */
224
225 /* Allocate a mutex. */
226 int
227 __gthread_objc_mutex_allocate(objc_mutex_t mutex)
228 {
229   if ((mutex->backend = (void *)CreateMutex(NULL, 0, NULL)) == NULL)
230     return -1;
231   else
232     return 0;
233 }
234
235 /* Deallocate a mutex. */
236 int
237 __gthread_objc_mutex_deallocate(objc_mutex_t mutex)
238 {
239   CloseHandle((HANDLE)(mutex->backend));
240   return 0;
241 }
242
243 /* Grab a lock on a mutex. */
244 int
245 __gthread_objc_mutex_lock(objc_mutex_t mutex)
246 {
247   int status;
248
249   status = WaitForSingleObject((HANDLE)(mutex->backend), INFINITE);
250   if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
251     return -1;
252   else
253     return 0;
254 }
255
256 /* Try to grab a lock on a mutex. */
257 int
258 __gthread_objc_mutex_trylock(objc_mutex_t mutex)
259 {
260   int status;
261
262   status = WaitForSingleObject((HANDLE)(mutex->backend), 0);
263   if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
264     return -1;
265   else
266     return 0;
267 }
268
269 /* Unlock the mutex */
270 int
271 __gthread_objc_mutex_unlock(objc_mutex_t mutex)
272 {
273   if (ReleaseMutex((HANDLE)(mutex->backend)) == 0)
274     return -1;
275   else
276     return 0;
277 }
278
279 /* Backend condition mutex functions */
280
281 /* Allocate a condition. */
282 int
283 __gthread_objc_condition_allocate(objc_condition_t condition)
284 {
285   /* Unimplemented. */
286   return -1;
287 }
288
289 /* Deallocate a condition. */
290 int
291 __gthread_objc_condition_deallocate(objc_condition_t condition)
292 {
293   /* Unimplemented. */
294   return -1;
295 }
296
297 /* Wait on the condition */
298 int
299 __gthread_objc_condition_wait(objc_condition_t condition, objc_mutex_t mutex)
300 {
301   /* Unimplemented. */
302   return -1;
303 }
304
305 /* Wake up all threads waiting on this condition. */
306 int
307 __gthread_objc_condition_broadcast(objc_condition_t condition)
308 {
309   /* Unimplemented. */
310   return -1;
311 }
312
313 /* Wake up one thread waiting on this condition. */
314 int
315 __gthread_objc_condition_signal(objc_condition_t condition)
316 {
317   /* Unimplemented. */
318   return -1;
319 }
320
321 #else /* _LIBOBJC */
322
323 #ifdef __MINGW32__
324 #include <_mingw.h>
325 #endif
326
327 typedef DWORD __gthread_key_t;
328
329 typedef struct {
330   int done;
331   long started;
332 } __gthread_once_t;
333
334 typedef HANDLE __gthread_mutex_t;
335
336 #define __GTHREAD_ONCE_INIT {FALSE, -1}
337 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
338
339 #if __MINGW32_MAJOR_VERSION >= 1 || \
340   (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
341 #define MINGW32_SUPPORTS_MT_EH 1
342 extern int __mingwthr_key_dtor PARAMS ((DWORD, void (*) (void *)));
343 /* Mingw runtime >= v0.3 provides a magic variable that is set to non-zero
344    if -mthreads option was specified, or 0 otherwise. This is to get around 
345    the lack of weak symbols in PE-COFF.  */
346 extern int _CRT_MT;
347 #endif
348
349 static inline int
350 __gthread_active_p (void)
351 {
352 #ifdef MINGW32_SUPPORTS_MT_EH
353   return _CRT_MT;
354 #else
355   return 1;
356 #endif
357 }
358
359 static inline int
360 __gthread_once (__gthread_once_t *once, void (*func) (void))
361 {
362   if (! __gthread_active_p ())
363     return -1;
364   else if (once == NULL || func == NULL)
365     return EINVAL;
366
367   if (! once->done)
368     {
369       if (InterlockedIncrement (&(once->started)) == 0)
370         {
371           (*func) ();
372           once->done = TRUE;
373         }
374       else
375         {
376           /* Another thread is currently executing the code, so wait for it 
377              to finish; yield the CPU in the meantime.  If performance 
378              does become an issue, the solution is to use an Event that 
379              we wait on here (and set above), but that implies a place to 
380              create the event before this routine is called.  */ 
381           while (! once->done)
382             Sleep (0);
383         }
384     }
385   
386   return 0;
387 }
388
389 /* Windows32 thread local keys don't support destructors; this leads to
390    leaks, especially in threaded applications making extensive use of 
391    C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
392 static inline int
393 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
394 {
395   int status = 0;
396   DWORD tls_index = TlsAlloc ();
397   if (tls_index != 0xFFFFFFFF)
398     {
399       *key = tls_index;
400 #ifdef MINGW32_SUPPORTS_MT_EH
401       /* Mingw runtime will run the dtors in reverse order for each thread
402          when the thread exits.  */
403       status = __mingwthr_key_dtor (*key, dtor);
404 #endif
405     }
406   else
407     status = (int) GetLastError ();
408   return status;
409 }
410
411 /* Currently, this routine is called only for Mingw runtime, and if
412    -mthreads option is chosen to link in the thread support DLL.  */ 
413 static inline int
414 __gthread_key_dtor (__gthread_key_t key, void *ptr)
415 {
416   /* Nothing needed. */
417   return 0;
418 }
419
420 static inline int
421 __gthread_key_delete (__gthread_key_t key)
422 {
423   return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
424 }
425
426 static inline void *
427 __gthread_getspecific (__gthread_key_t key)
428 {
429   DWORD lasterror;
430   void *ptr;
431
432   lasterror = GetLastError();
433
434   ptr = TlsGetValue(key);
435
436   SetLastError( lasterror );
437
438   return ptr;
439 }
440
441 static inline int
442 __gthread_setspecific (__gthread_key_t key, const void *ptr)
443 {
444   return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
445 }
446
447 static inline void
448 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
449 {
450   /* Create unnamed mutex with default security attr and no initial owner.  */ 
451   *mutex = CreateMutex (NULL, 0, NULL);
452 }
453
454 static inline int
455 __gthread_mutex_lock (__gthread_mutex_t *mutex)
456 {
457   int status = 0;
458
459   if (__gthread_active_p ())
460     {
461       if (WaitForSingleObject (*mutex, INFINITE) == WAIT_OBJECT_0)
462         status = 0;
463       else
464         status = 1;
465     }
466   return status;
467 }
468
469 static inline int
470 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
471 {
472   int status = 0;
473
474   if (__gthread_active_p ())
475     {
476       if (WaitForSingleObject (*mutex, 0) == WAIT_OBJECT_0)
477         status = 0;
478       else
479         status = 1;
480     }
481   return status;
482 }
483
484 static inline int
485 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
486 {
487   if (__gthread_active_p ())
488     return (ReleaseMutex (*mutex) != 0) ? 0 : 1;
489   else
490     return 0;
491 }
492
493 #endif /* _LIBOBJC */
494
495 #endif /* ! GCC_GTHR_WIN32_H */
496