OSDN Git Service

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