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