]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gthr-win32.h
Merge basic-improvements-branch to trunk
[thirdparty/gcc.git] / gcc / gthr-win32.h
CommitLineData
6319d58e 1/* Threads compatibility routines for libgcc2 and libobjc. */
471528fc 2/* Compile this one with gcc. */
04641143 3/* Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
471528fc 4 Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
5
f12b58b3 6This file is part of GCC.
471528fc 7
f12b58b3 8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
471528fc 12
f12b58b3 13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
471528fc 17
18You should have received a copy of the GNU General Public License
f12b58b3 19along with GCC; see the file COPYING. If not, write to the Free
20Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2102111-1307, USA. */
471528fc 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
2a281353 30#ifndef GCC_GTHR_WIN32_H
31#define GCC_GTHR_WIN32_H
471528fc 32
33/* Windows32 threads specific definitions. The windows32 threading model
3cfec666 34 does not map well into pthread-inspired gcc's threading model, and so
471528fc 35 there are caveats one needs to be aware of.
36
c13f265c 37 1. The destructor supplied to __gthread_key_create is ignored for
3cfec666 38 generic x86-win32 ports. This will certainly cause memory leaks
39 due to unreclaimed eh contexts (sizeof (eh_context) is at least
c13f265c 40 24 bytes for x86 currently).
471528fc 41
42 This memory leak may be significant for long-running applications
43 that make heavy use of C++ EH.
44
c13f265c 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
3cfec666 50 DLL, which results in memory leak. Other x86-win32 ports can use
c13f265c 51 the same technique of course to avoid the leak.
52
471528fc 53 2. The error codes returned are non-POSIX like, and cast into ints.
3cfec666 54 This may cause incorrect error return due to truncation values on
471528fc 55 hw where sizeof (DWORD) > sizeof (int).
3cfec666 56
57 3. We might consider using Critical Sections instead of Windows32
58 mutexes for better performance, but emulating __gthread_mutex_trylock
c13f265c 59 interface becomes more complicated (Win9x does not support
60 TryEnterCriticalSectioni, while NT does).
3cfec666 61
c13f265c 62 The basic framework should work well enough. In the long term, GCC
63 needs to use Structured Exception Handling on Windows32. */
471528fc 64
65#define __GTHREADS 1
66
81189303 67#include <errno.h>
68#ifdef __MINGW32__
69#include <_mingw.h>
70#endif
6319d58e 71
72#ifdef _LIBOBJC
73
61dcce9c 74/* This is necessary to prevent windef.h (included from windows.h) from
3cfec666 75 defining it's own BOOL as a typedef. */
61dcce9c 76#ifndef __OBJC__
77#define __OBJC__
78#endif
79#include <windows.h>
3cfec666 80/* Now undef the windows BOOL. */
61dcce9c 81#undef BOOL
82
6319d58e 83/* Key structure for maintaining thread specific storage */
0160b241 84static DWORD __gthread_objc_data_tls = (DWORD) -1;
6319d58e 85
86/* Backend initialization functions */
87
5a54c45e 88/* Initialize the threads subsystem. */
6319d58e 89int
0160b241 90__gthread_objc_init_thread_system (void)
6319d58e 91{
92 /* Initialize the thread storage key */
0160b241 93 if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
6319d58e 94 return 0;
95 else
96 return -1;
97}
98
5a54c45e 99/* Close the threads subsystem. */
6319d58e 100int
0160b241 101__gthread_objc_close_thread_system (void)
6319d58e 102{
0160b241 103 if (__gthread_objc_data_tls != (DWORD) -1)
104 TlsFree (__gthread_objc_data_tls);
6319d58e 105 return 0;
106}
107
108/* Backend thread functions */
109
5a54c45e 110/* Create a new thread of execution. */
6319d58e 111objc_thread_t
0160b241 112__gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
6319d58e 113{
114 DWORD thread_id = 0;
115 HANDLE win32_handle;
116
0160b241 117 if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
118 arg, 0, &thread_id)))
6319d58e 119 thread_id = 0;
3cfec666 120
0160b241 121 return (objc_thread_t) thread_id;
6319d58e 122}
123
5a54c45e 124/* Set the current thread's priority. */
6319d58e 125int
0160b241 126__gthread_objc_thread_set_priority (int priority)
6319d58e 127{
128 int sys_priority = 0;
129
130 switch (priority)
131 {
132 case OBJC_THREAD_INTERACTIVE_PRIORITY:
133 sys_priority = THREAD_PRIORITY_NORMAL;
134 break;
135 default:
136 case OBJC_THREAD_BACKGROUND_PRIORITY:
137 sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
138 break;
139 case OBJC_THREAD_LOW_PRIORITY:
140 sys_priority = THREAD_PRIORITY_LOWEST;
141 break;
142 }
143
144 /* Change priority */
0160b241 145 if (SetThreadPriority (GetCurrentThread (), sys_priority))
6319d58e 146 return 0;
147 else
148 return -1;
149}
150
5a54c45e 151/* Return the current thread's priority. */
6319d58e 152int
0160b241 153__gthread_objc_thread_get_priority (void)
6319d58e 154{
155 int sys_priority;
156
0160b241 157 sys_priority = GetThreadPriority (GetCurrentThread ());
3cfec666 158
6319d58e 159 switch (sys_priority)
160 {
161 case THREAD_PRIORITY_HIGHEST:
162 case THREAD_PRIORITY_TIME_CRITICAL:
163 case THREAD_PRIORITY_ABOVE_NORMAL:
164 case THREAD_PRIORITY_NORMAL:
165 return OBJC_THREAD_INTERACTIVE_PRIORITY;
166
167 default:
168 case THREAD_PRIORITY_BELOW_NORMAL:
169 return OBJC_THREAD_BACKGROUND_PRIORITY;
3cfec666 170
6319d58e 171 case THREAD_PRIORITY_IDLE:
172 case THREAD_PRIORITY_LOWEST:
173 return OBJC_THREAD_LOW_PRIORITY;
174 }
175
5a54c45e 176 /* Couldn't get priority. */
6319d58e 177 return -1;
178}
179
5a54c45e 180/* Yield our process time to another thread. */
6319d58e 181void
0160b241 182__gthread_objc_thread_yield (void)
6319d58e 183{
0160b241 184 Sleep (0);
6319d58e 185}
186
5a54c45e 187/* Terminate the current thread. */
6319d58e 188int
0160b241 189__gthread_objc_thread_exit (void)
6319d58e 190{
191 /* exit the thread */
0160b241 192 ExitThread (__objc_thread_exit_status);
6319d58e 193
194 /* Failed if we reached here */
195 return -1;
196}
197
5a54c45e 198/* Returns an integer value which uniquely describes a thread. */
6319d58e 199objc_thread_t
0160b241 200__gthread_objc_thread_id (void)
6319d58e 201{
0160b241 202 return (objc_thread_t) GetCurrentThreadId ();
6319d58e 203}
204
5a54c45e 205/* Sets the thread's local storage pointer. */
6319d58e 206int
0160b241 207__gthread_objc_thread_set_data (void *value)
6319d58e 208{
0160b241 209 if (TlsSetValue (__gthread_objc_data_tls, value))
6319d58e 210 return 0;
211 else
212 return -1;
213}
214
5a54c45e 215/* Returns the thread's local storage pointer. */
6319d58e 216void *
0160b241 217__gthread_objc_thread_get_data (void)
6319d58e 218{
bc7da7ad 219 DWORD lasterror;
220 void *ptr;
221
0160b241 222 lasterror = GetLastError ();
bc7da7ad 223
0160b241 224 ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */
bc7da7ad 225
0160b241 226 SetLastError (lasterror);
bc7da7ad 227
228 return ptr;
6319d58e 229}
230
231/* Backend mutex functions */
232
5a54c45e 233/* Allocate a mutex. */
6319d58e 234int
0160b241 235__gthread_objc_mutex_allocate (objc_mutex_t mutex)
6319d58e 236{
0160b241 237 if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
6319d58e 238 return -1;
239 else
240 return 0;
241}
242
5a54c45e 243/* Deallocate a mutex. */
6319d58e 244int
0160b241 245__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
6319d58e 246{
0160b241 247 CloseHandle ((HANDLE) (mutex->backend));
6319d58e 248 return 0;
249}
250
5a54c45e 251/* Grab a lock on a mutex. */
6319d58e 252int
0160b241 253__gthread_objc_mutex_lock (objc_mutex_t mutex)
6319d58e 254{
255 int status;
256
0160b241 257 status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
6319d58e 258 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
259 return -1;
260 else
261 return 0;
262}
263
5a54c45e 264/* Try to grab a lock on a mutex. */
6319d58e 265int
0160b241 266__gthread_objc_mutex_trylock (objc_mutex_t mutex)
6319d58e 267{
268 int status;
269
0160b241 270 status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
6319d58e 271 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
272 return -1;
273 else
274 return 0;
275}
276
277/* Unlock the mutex */
278int
0160b241 279__gthread_objc_mutex_unlock (objc_mutex_t mutex)
6319d58e 280{
0160b241 281 if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
6319d58e 282 return -1;
283 else
284 return 0;
285}
286
287/* Backend condition mutex functions */
288
5a54c45e 289/* Allocate a condition. */
6319d58e 290int
0160b241 291__gthread_objc_condition_allocate (objc_condition_t condition)
6319d58e 292{
5a54c45e 293 /* Unimplemented. */
6319d58e 294 return -1;
295}
296
5a54c45e 297/* Deallocate a condition. */
6319d58e 298int
0160b241 299__gthread_objc_condition_deallocate (objc_condition_t condition)
6319d58e 300{
5a54c45e 301 /* Unimplemented. */
6319d58e 302 return -1;
303}
304
305/* Wait on the condition */
306int
0160b241 307__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
6319d58e 308{
5a54c45e 309 /* Unimplemented. */
6319d58e 310 return -1;
311}
312
5a54c45e 313/* Wake up all threads waiting on this condition. */
6319d58e 314int
0160b241 315__gthread_objc_condition_broadcast (objc_condition_t condition)
6319d58e 316{
5a54c45e 317 /* Unimplemented. */
6319d58e 318 return -1;
319}
320
5a54c45e 321/* Wake up one thread waiting on this condition. */
6319d58e 322int
0160b241 323__gthread_objc_condition_signal (objc_condition_t condition)
6319d58e 324{
5a54c45e 325 /* Unimplemented. */
6319d58e 326 return -1;
327}
328
329#else /* _LIBOBJC */
330
29dcbe46 331#ifdef __cplusplus
332extern "C" {
333#endif
471528fc 334
29dcbe46 335typedef unsigned long __gthread_key_t;
471528fc 336
337typedef struct {
338 int done;
339 long started;
340} __gthread_once_t;
341
29dcbe46 342typedef void* __gthread_mutex_t;
471528fc 343
29dcbe46 344#define __GTHREAD_ONCE_INIT {0, -1}
471528fc 345#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
b8dd27f3 346#define __GTHREAD_MUTEX_INIT_DEFAULT 0
471528fc 347
c13f265c 348#if __MINGW32_MAJOR_VERSION >= 1 || \
349 (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
350#define MINGW32_SUPPORTS_MT_EH 1
6ef828f9 351/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
3cfec666 352 if -mthreads option was specified, or 0 otherwise. This is to get around
c13f265c 353 the lack of weak symbols in PE-COFF. */
354extern int _CRT_MT;
29dcbe46 355extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
356#endif /* __MINGW32__ version */
c13f265c 357
471528fc 358static inline int
205b5771 359__gthread_active_p (void)
471528fc 360{
c13f265c 361#ifdef MINGW32_SUPPORTS_MT_EH
362 return _CRT_MT;
363#else
471528fc 364 return 1;
c13f265c 365#endif
471528fc 366}
367
29dcbe46 368#ifdef __GTHREAD_HIDE_WIN32API
369
370/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
371 Only stubs are exposed to avoid polluting the C++ namespace with
372 windows api definitions. */
373
374extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
375extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
376extern int __gthr_win32_key_delete (__gthread_key_t);
377extern void * __gthr_win32_getspecific (__gthread_key_t);
378extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
379extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
380extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
381extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
382extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
383
384static inline int
385__gthread_once (__gthread_once_t *once, void (*func) (void))
386{
0160b241 387 if (__gthread_active_p ())
29dcbe46 388 return __gthr_win32_once (once, func);
389 else
0160b241 390 return -1;
29dcbe46 391}
392
393static inline int
394__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
395{
396 return __gthr_win32_key_create (key, dtor);
397}
398
0160b241 399static inline int
29dcbe46 400__gthread_key_delete (__gthread_key_t key)
401{
0160b241 402 return __gthr_win32_key_delete (key);
29dcbe46 403}
404
405static inline void *
406__gthread_getspecific (__gthread_key_t key)
407{
408 return __gthr_win32_getspecific (key);
409}
410
411static inline int
412__gthread_setspecific (__gthread_key_t key, const void *ptr)
413{
414 return __gthr_win32_setspecific (key, ptr);
415}
416
417static inline void
418__gthread_mutex_init_function (__gthread_mutex_t *mutex)
419{
420 __gthr_win32_mutex_init_function (mutex);
421}
422
423static inline int
424__gthread_mutex_lock (__gthread_mutex_t *mutex)
425{
426 if (__gthread_active_p ())
427 return __gthr_win32_mutex_lock (mutex);
428 else
429 return 0;
430}
431
432static inline int
433__gthread_mutex_trylock (__gthread_mutex_t *mutex)
434{
435 if (__gthread_active_p ())
436 return __gthr_win32_mutex_trylock (mutex);
437 else
0160b241 438 return 0;
29dcbe46 439}
440
441static inline int
442__gthread_mutex_unlock (__gthread_mutex_t *mutex)
443{
444 if (__gthread_active_p ())
445 return __gthr_win32_mutex_unlock (mutex);
446 else
0160b241 447 return 0;
29dcbe46 448}
449
450#else /* ! __GTHREAD_HIDE_WIN32API */
451
452#include <windows.h>
453#include <errno.h>
454
471528fc 455static inline int
205b5771 456__gthread_once (__gthread_once_t *once, void (*func) (void))
471528fc 457{
458 if (! __gthread_active_p ())
459 return -1;
460 else if (once == NULL || func == NULL)
461 return EINVAL;
462
463 if (! once->done)
464 {
465 if (InterlockedIncrement (&(once->started)) == 0)
3cfec666 466 {
471528fc 467 (*func) ();
468 once->done = TRUE;
469 }
c13f265c 470 else
471 {
3cfec666 472 /* Another thread is currently executing the code, so wait for it
473 to finish; yield the CPU in the meantime. If performance
474 does become an issue, the solution is to use an Event that
475 we wait on here (and set above), but that implies a place to
476 create the event before this routine is called. */
c13f265c 477 while (! once->done)
478 Sleep (0);
479 }
471528fc 480 }
3cfec666 481
471528fc 482 return 0;
483}
484
c13f265c 485/* Windows32 thread local keys don't support destructors; this leads to
3cfec666 486 leaks, especially in threaded applications making extensive use of
c13f265c 487 C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
471528fc 488static inline int
c13f265c 489__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
471528fc 490{
491 int status = 0;
492 DWORD tls_index = TlsAlloc ();
493 if (tls_index != 0xFFFFFFFF)
c13f265c 494 {
495 *key = tls_index;
496#ifdef MINGW32_SUPPORTS_MT_EH
497 /* Mingw runtime will run the dtors in reverse order for each thread
498 when the thread exits. */
499 status = __mingwthr_key_dtor (*key, dtor);
500#endif
501 }
471528fc 502 else
503 status = (int) GetLastError ();
504 return status;
505}
506
471528fc 507static inline int
508__gthread_key_delete (__gthread_key_t key)
509{
510 return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
511}
512
513static inline void *
514__gthread_getspecific (__gthread_key_t key)
515{
bc7da7ad 516 DWORD lasterror;
517 void *ptr;
518
0160b241 519 lasterror = GetLastError ();
bc7da7ad 520
0160b241 521 ptr = TlsGetValue (key);
bc7da7ad 522
0160b241 523 SetLastError (lasterror);
bc7da7ad 524
525 return ptr;
471528fc 526}
527
528static inline int
529__gthread_setspecific (__gthread_key_t key, const void *ptr)
530{
c13f265c 531 return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
471528fc 532}
533
534static inline void
535__gthread_mutex_init_function (__gthread_mutex_t *mutex)
536{
3cfec666 537 /* Create unnamed mutex with default security attr and no initial owner. */
471528fc 538 *mutex = CreateMutex (NULL, 0, NULL);
539}
540
541static inline int
542__gthread_mutex_lock (__gthread_mutex_t *mutex)
543{
544 int status = 0;
545
546 if (__gthread_active_p ())
547 {
548 if (WaitForSingleObject (*mutex, INFINITE) == WAIT_OBJECT_0)
549 status = 0;
550 else
551 status = 1;
552 }
553 return status;
554}
555
556static inline int
557__gthread_mutex_trylock (__gthread_mutex_t *mutex)
558{
559 int status = 0;
560
561 if (__gthread_active_p ())
562 {
563 if (WaitForSingleObject (*mutex, 0) == WAIT_OBJECT_0)
564 status = 0;
565 else
566 status = 1;
567 }
568 return status;
569}
570
571static inline int
572__gthread_mutex_unlock (__gthread_mutex_t *mutex)
573{
574 if (__gthread_active_p ())
575 return (ReleaseMutex (*mutex) != 0) ? 0 : 1;
576 else
577 return 0;
578}
579
29dcbe46 580#endif /* __GTHREAD_HIDE_WIN32API */
581
582#ifdef __cplusplus
583}
584#endif
585
6319d58e 586#endif /* _LIBOBJC */
587
2a281353 588#endif /* ! GCC_GTHR_WIN32_H */