OSDN Git Service

2008-02-10 Danny Smith <dannysmith@users.sourceforge.net>
[pf3gnuchains/gcc-fork.git] / gcc / gthr-win32.h
1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3
4 /* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
5    Free Software Foundation, Inc.
6    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
7
8 This file is part of GCC.
9
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING.  If not, write to the Free
22 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301, USA.  */
24
25 /* As a special exception, if you link this library with other files,
26    some of which are compiled with GCC, to produce an executable,
27    this library does not by itself cause the resulting executable
28    to be covered by the GNU General Public License.
29    This exception does not however invalidate any other reasons why
30    the executable file might be covered by the GNU General Public License.  */
31
32 #ifndef GCC_GTHR_WIN32_H
33 #define GCC_GTHR_WIN32_H
34
35 /* Windows32 threads specific definitions. The windows32 threading model
36    does not map well into pthread-inspired gcc's threading model, and so
37    there are caveats one needs to be aware of.
38
39    1. The destructor supplied to __gthread_key_create is ignored for
40       generic x86-win32 ports. This will certainly cause memory leaks
41       due to unreclaimed eh contexts (sizeof (eh_context) is at least
42       24 bytes for x86 currently).
43
44       This memory leak may be significant for long-running applications
45       that make heavy use of C++ EH.
46
47       However, Mingw runtime (version 0.3 or newer) provides a mechanism
48       to emulate pthreads key dtors; the runtime provides a special DLL,
49       linked in if -mthreads option is specified, that runs the dtors in
50       the reverse order of registration when each thread exits. If
51       -mthreads option is not given, a stub is linked in instead of the
52       DLL, which results in memory leak. Other x86-win32 ports can use
53       the same technique of course to avoid the leak.
54
55    2. The error codes returned are non-POSIX like, and cast into ints.
56       This may cause incorrect error return due to truncation values on
57       hw where sizeof (DWORD) > sizeof (int).
58
59    3. We are currently using a special mutex instead of the Critical
60       Sections, since Win9x does not support TryEnterCriticalSection
61       (while NT does).
62
63    The basic framework should work well enough. In the long term, GCC
64    needs to use Structured Exception Handling on Windows32.  */
65
66 #define __GTHREADS 1
67
68 #include <errno.h>
69 #ifdef __MINGW32__
70 #include <_mingw.h>
71 #endif
72
73 #ifdef _LIBOBJC
74
75 /* This is necessary to prevent windef.h (included from windows.h) from
76    defining its own BOOL as a typedef.  */
77 #ifndef __OBJC__
78 #define __OBJC__
79 #endif
80 #include <windows.h>
81 /* Now undef the windows BOOL.  */
82 #undef BOOL
83
84 /* Key structure for maintaining thread specific storage */
85 static DWORD    __gthread_objc_data_tls = (DWORD) -1;
86
87 /* Backend initialization functions */
88
89 /* Initialize the threads subsystem.  */
90 int
91 __gthread_objc_init_thread_system (void)
92 {
93   /* Initialize the thread storage key.  */
94   if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
95     return 0;
96   else
97     return -1;
98 }
99
100 /* Close the threads subsystem.  */
101 int
102 __gthread_objc_close_thread_system (void)
103 {
104   if (__gthread_objc_data_tls != (DWORD) -1)
105     TlsFree (__gthread_objc_data_tls);
106   return 0;
107 }
108
109 /* Backend thread functions */
110
111 /* Create a new thread of execution.  */
112 objc_thread_t
113 __gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
114 {
115   DWORD thread_id = 0;
116   HANDLE win32_handle;
117
118   if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
119                                      arg, 0, &thread_id)))
120     thread_id = 0;
121
122   return (objc_thread_t) thread_id;
123 }
124
125 /* Set the current thread's priority.  */
126 int
127 __gthread_objc_thread_set_priority (int priority)
128 {
129   int sys_priority = 0;
130
131   switch (priority)
132     {
133     case OBJC_THREAD_INTERACTIVE_PRIORITY:
134       sys_priority = THREAD_PRIORITY_NORMAL;
135       break;
136     default:
137     case OBJC_THREAD_BACKGROUND_PRIORITY:
138       sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
139       break;
140     case OBJC_THREAD_LOW_PRIORITY:
141       sys_priority = THREAD_PRIORITY_LOWEST;
142       break;
143     }
144
145   /* Change priority */
146   if (SetThreadPriority (GetCurrentThread (), sys_priority))
147     return 0;
148   else
149     return -1;
150 }
151
152 /* Return the current thread's priority.  */
153 int
154 __gthread_objc_thread_get_priority (void)
155 {
156   int sys_priority;
157
158   sys_priority = GetThreadPriority (GetCurrentThread ());
159
160   switch (sys_priority)
161     {
162     case THREAD_PRIORITY_HIGHEST:
163     case THREAD_PRIORITY_TIME_CRITICAL:
164     case THREAD_PRIORITY_ABOVE_NORMAL:
165     case THREAD_PRIORITY_NORMAL:
166       return OBJC_THREAD_INTERACTIVE_PRIORITY;
167
168     default:
169     case THREAD_PRIORITY_BELOW_NORMAL:
170       return OBJC_THREAD_BACKGROUND_PRIORITY;
171
172     case THREAD_PRIORITY_IDLE:
173     case THREAD_PRIORITY_LOWEST:
174       return OBJC_THREAD_LOW_PRIORITY;
175     }
176
177   /* Couldn't get priority.  */
178   return -1;
179 }
180
181 /* Yield our process time to another thread.  */
182 void
183 __gthread_objc_thread_yield (void)
184 {
185   Sleep (0);
186 }
187
188 /* Terminate the current thread.  */
189 int
190 __gthread_objc_thread_exit (void)
191 {
192   /* exit the thread */
193   ExitThread (__objc_thread_exit_status);
194
195   /* Failed if we reached here */
196   return -1;
197 }
198
199 /* Returns an integer value which uniquely describes a thread.  */
200 objc_thread_t
201 __gthread_objc_thread_id (void)
202 {
203   return (objc_thread_t) GetCurrentThreadId ();
204 }
205
206 /* Sets the thread's local storage pointer.  */
207 int
208 __gthread_objc_thread_set_data (void *value)
209 {
210   if (TlsSetValue (__gthread_objc_data_tls, value))
211     return 0;
212   else
213     return -1;
214 }
215
216 /* Returns the thread's local storage pointer.  */
217 void *
218 __gthread_objc_thread_get_data (void)
219 {
220   DWORD lasterror;
221   void *ptr;
222
223   lasterror = GetLastError ();
224
225   ptr = TlsGetValue (__gthread_objc_data_tls);          /* Return thread data.  */
226
227   SetLastError (lasterror);
228
229   return ptr;
230 }
231
232 /* Backend mutex functions */
233
234 /* Allocate a mutex.  */
235 int
236 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
237 {
238   if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
239     return -1;
240   else
241     return 0;
242 }
243
244 /* Deallocate a mutex.  */
245 int
246 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
247 {
248   CloseHandle ((HANDLE) (mutex->backend));
249   return 0;
250 }
251
252 /* Grab a lock on a mutex.  */
253 int
254 __gthread_objc_mutex_lock (objc_mutex_t mutex)
255 {
256   int status;
257
258   status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
259   if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
260     return -1;
261   else
262     return 0;
263 }
264
265 /* Try to grab a lock on a mutex.  */
266 int
267 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
268 {
269   int status;
270
271   status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
272   if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
273     return -1;
274   else
275     return 0;
276 }
277
278 /* Unlock the mutex */
279 int
280 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
281 {
282   if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
283     return -1;
284   else
285     return 0;
286 }
287
288 /* Backend condition mutex functions */
289
290 /* Allocate a condition.  */
291 int
292 __gthread_objc_condition_allocate (objc_condition_t condition)
293 {
294   /* Unimplemented.  */
295   return -1;
296 }
297
298 /* Deallocate a condition.  */
299 int
300 __gthread_objc_condition_deallocate (objc_condition_t condition)
301 {
302   /* Unimplemented.  */
303   return -1;
304 }
305
306 /* Wait on the condition */
307 int
308 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
309 {
310   /* Unimplemented.  */
311   return -1;
312 }
313
314 /* Wake up all threads waiting on this condition.  */
315 int
316 __gthread_objc_condition_broadcast (objc_condition_t condition)
317 {
318   /* Unimplemented.  */
319   return -1;
320 }
321
322 /* Wake up one thread waiting on this condition.  */
323 int
324 __gthread_objc_condition_signal (objc_condition_t condition)
325 {
326   /* Unimplemented.  */
327   return -1;
328 }
329
330 #else /* _LIBOBJC */
331
332 #ifdef __cplusplus
333 extern "C" {
334 #endif
335
336 typedef unsigned long __gthread_key_t;
337
338 typedef struct {
339   int done;
340   long started;
341 } __gthread_once_t;
342
343 typedef struct {
344   long counter;
345   void *sema;
346 } __gthread_mutex_t;
347
348 typedef struct {
349   long counter;
350   long depth;
351   unsigned long owner;
352   void *sema;
353 } __gthread_recursive_mutex_t;
354
355 #define __GTHREAD_ONCE_INIT {0, -1}
356 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
357 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
358 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
359   __gthread_recursive_mutex_init_function
360 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
361
362 #define __GTHREAD_MUTEX_DESTROY_FUNCTION \
363   __gthread_mutex_destroy_function
364
365 #if __MINGW32_MAJOR_VERSION >= 1 || \
366   (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
367 #define MINGW32_SUPPORTS_MT_EH 1
368 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
369    if -mthreads option was specified, or 0 otherwise. This is to get around
370    the lack of weak symbols in PE-COFF.  */
371 extern int _CRT_MT;
372 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
373 #endif /* __MINGW32__ version */
374
375 /* The Windows95 kernel does not export InterlockedCompareExchange.
376    This provides a substitute.   When building apps that reference
377    gthread_mutex_try_lock, the  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
378    macro  must be defined if Windows95 is a target.  Currently
379    gthread_mutex_try_lock is not referenced by libgcc or libstdc++.  */
380 #ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
381 static inline long
382 __gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
383 {
384   long result;
385   __asm__ __volatile__ ("\n\
386         lock\n\
387         cmpxchg{l} {%4, %1|%1, %4}\n"
388         : "=a" (result), "=m" (*dest)
389         : "0" (comperand), "m" (*dest), "r" (xchg)
390         : "cc");
391   return result;
392 }
393 #define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
394 #else  /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
395 #define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
396 #endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
397
398 static inline int
399 __gthread_active_p (void)
400 {
401 #ifdef MINGW32_SUPPORTS_MT_EH
402   return _CRT_MT;
403 #else
404   return 1;
405 #endif
406 }
407
408 #if __GTHREAD_HIDE_WIN32API
409
410 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
411    Only stubs are exposed to avoid polluting the C++ namespace with
412    windows api definitions.  */
413
414 extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
415 extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
416 extern int __gthr_win32_key_delete (__gthread_key_t);
417 extern void * __gthr_win32_getspecific (__gthread_key_t);
418 extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
419 extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
420 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
421 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
422 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
423 extern void
424   __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
425 extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
426 extern int
427   __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
428 extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
429
430 static inline int
431 __gthread_once (__gthread_once_t *once, void (*func) (void))
432 {
433   if (__gthread_active_p ())
434     return __gthr_win32_once (once, func);
435   else
436     return -1;
437 }
438
439 static inline int
440 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
441 {
442   return __gthr_win32_key_create (key, dtor);
443 }
444
445 static inline int
446 __gthread_key_delete (__gthread_key_t key)
447 {
448   return __gthr_win32_key_delete (key);
449 }
450
451 static inline void *
452 __gthread_getspecific (__gthread_key_t key)
453 {
454   return __gthr_win32_getspecific (key);
455 }
456
457 static inline int
458 __gthread_setspecific (__gthread_key_t key, const void *ptr)
459 {
460   return __gthr_win32_setspecific (key, ptr);
461 }
462
463 static inline void
464 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
465 {
466   __gthr_win32_mutex_init_function (mutex);
467 }
468
469 static inline int
470 __gthread_mutex_lock (__gthread_mutex_t *mutex)
471 {
472   if (__gthread_active_p ())
473     return __gthr_win32_mutex_lock (mutex);
474   else
475     return 0;
476 }
477
478 static inline int
479 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
480 {
481   if (__gthread_active_p ())
482     return __gthr_win32_mutex_trylock (mutex);
483   else
484     return 0;
485 }
486
487 static inline int
488 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
489 {
490   if (__gthread_active_p ())
491     return __gthr_win32_mutex_unlock (mutex);
492   else
493     return 0;
494 }
495
496 static inline void
497 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
498 {
499    __gthr_win32_recursive_mutex_init_function (mutex);
500 }
501
502 static inline int
503 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
504 {
505   if (__gthread_active_p ())
506     return __gthr_win32_recursive_mutex_lock (mutex);
507   else
508     return 0;
509 }
510
511 static inline int
512 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
513 {
514   if (__gthread_active_p ())
515     return __gthr_win32_recursive_mutex_trylock (mutex);
516   else
517     return 0;
518 }
519
520 static inline int
521 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
522 {
523   if (__gthread_active_p ())
524     return __gthr_win32_recursive_mutex_unlock (mutex);
525   else
526     return 0;
527 }
528
529 #else /* ! __GTHREAD_HIDE_WIN32API */
530
531 #include <windows.h>
532 #include <errno.h>
533
534 static inline int
535 __gthread_once (__gthread_once_t *once, void (*func) (void))
536 {
537   if (! __gthread_active_p ())
538     return -1;
539   else if (once == NULL || func == NULL)
540     return EINVAL;
541
542   if (! once->done)
543     {
544       if (InterlockedIncrement (&(once->started)) == 0)
545         {
546           (*func) ();
547           once->done = TRUE;
548         }
549       else
550         {
551           /* Another thread is currently executing the code, so wait for it
552              to finish; yield the CPU in the meantime.  If performance
553              does become an issue, the solution is to use an Event that
554              we wait on here (and set above), but that implies a place to
555              create the event before this routine is called.  */
556           while (! once->done)
557             Sleep (0);
558         }
559     }
560
561   return 0;
562 }
563
564 /* Windows32 thread local keys don't support destructors; this leads to
565    leaks, especially in threaded applications making extensive use of
566    C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
567 static inline int
568 __gthread_key_create (__gthread_key_t *key,
569                       void (*dtor) (void *) __attribute__((unused)))
570 {
571   int status = 0;
572   DWORD tls_index = TlsAlloc ();
573   if (tls_index != 0xFFFFFFFF)
574     {
575       *key = tls_index;
576 #ifdef MINGW32_SUPPORTS_MT_EH
577       /* Mingw runtime will run the dtors in reverse order for each thread
578          when the thread exits.  */
579       status = __mingwthr_key_dtor (*key, dtor);
580 #endif
581     }
582   else
583     status = (int) GetLastError ();
584   return status;
585 }
586
587 static inline int
588 __gthread_key_delete (__gthread_key_t key)
589 {
590   return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
591 }
592
593 static inline void *
594 __gthread_getspecific (__gthread_key_t key)
595 {
596   DWORD lasterror;
597   void *ptr;
598
599   lasterror = GetLastError ();
600
601   ptr = TlsGetValue (key);
602
603   SetLastError (lasterror);
604
605   return ptr;
606 }
607
608 static inline int
609 __gthread_setspecific (__gthread_key_t key, const void *ptr)
610 {
611   return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
612 }
613
614 static inline void
615 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
616 {
617   mutex->counter = -1;
618   mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
619 }
620
621 static inline void
622 __gthread_mutex_destroy_function (__gthread_mutex_t *mutex)
623 {
624   CloseHandle ((HANDLE) mutex->sema);
625 }
626
627 static inline int
628 __gthread_mutex_lock (__gthread_mutex_t *mutex)
629 {
630   int status = 0;
631
632   if (__gthread_active_p ())
633     {
634       if (InterlockedIncrement (&mutex->counter) == 0 ||
635           WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
636         status = 0;
637       else
638         {
639           /* WaitForSingleObject returns WAIT_FAILED, and we can only do
640              some best-effort cleanup here.  */
641           InterlockedDecrement (&mutex->counter);
642           status = 1;
643         }
644     }
645   return status;
646 }
647
648 static inline int
649 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
650 {
651   int status = 0;
652
653   if (__gthread_active_p ())
654     {
655       if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
656         status = 0;
657       else
658         status = 1;
659     }
660   return status;
661 }
662
663 static inline int
664 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
665 {
666   if (__gthread_active_p ())
667     {
668       if (InterlockedDecrement (&mutex->counter) >= 0)
669         return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
670     }
671   return 0;
672 }
673
674 static inline void
675 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
676 {
677   mutex->counter = -1;
678   mutex->depth = 0;
679   mutex->owner = 0;
680   mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
681 }
682
683 static inline int
684 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
685 {
686   if (__gthread_active_p ())
687     {
688       DWORD me = GetCurrentThreadId();
689       if (InterlockedIncrement (&mutex->counter) == 0)
690         {
691           mutex->depth = 1;
692           mutex->owner = me;
693         }
694       else if (mutex->owner == me)
695         {
696           InterlockedDecrement (&mutex->counter);
697           ++(mutex->depth);
698         }
699       else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
700         {
701           mutex->depth = 1;
702           mutex->owner = me;
703         }
704       else
705         {
706           /* WaitForSingleObject returns WAIT_FAILED, and we can only do
707              some best-effort cleanup here.  */
708           InterlockedDecrement (&mutex->counter);
709           return 1;
710         }
711     }
712   return 0;
713 }
714
715 static inline int
716 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
717 {
718   if (__gthread_active_p ())
719     {
720       DWORD me = GetCurrentThreadId();
721       if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
722         {
723           mutex->depth = 1;
724           mutex->owner = me;
725         }
726       else if (mutex->owner == me)
727         ++(mutex->depth);
728       else
729         return 1;
730     }
731   return 0;
732 }
733
734 static inline int
735 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
736 {
737   if (__gthread_active_p ())
738     {
739       --(mutex->depth);
740       if (mutex->depth == 0)
741         {
742           mutex->owner = 0;
743
744           if (InterlockedDecrement (&mutex->counter) >= 0)
745             return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
746         }
747     }
748   return 0;
749 }
750
751 #endif /*  __GTHREAD_HIDE_WIN32API */
752
753 #ifdef __cplusplus
754 }
755 #endif
756
757 #endif /* _LIBOBJC */
758
759 #endif /* ! GCC_GTHR_WIN32_H */