196263Sobrien/* Threads compatibility routines for libgcc2 and libobjc.  */
296263Sobrien/* Compile this one with gcc.  */
3169689Skan
4169689Skan/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
5169689Skan   Free Software Foundation, Inc.
696263Sobrien   Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
796263Sobrien
896263SobrienThis file is part of GCC.
996263Sobrien
1096263SobrienGCC is free software; you can redistribute it and/or modify it under
1196263Sobrienthe terms of the GNU General Public License as published by the Free
1296263SobrienSoftware Foundation; either version 2, or (at your option) any later
1396263Sobrienversion.
1496263Sobrien
1596263SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1696263SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1796263SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1896263Sobrienfor more details.
1996263Sobrien
2096263SobrienYou should have received a copy of the GNU General Public License
2196263Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
22169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23169689Skan02110-1301, USA.  */
2496263Sobrien
2596263Sobrien/* As a special exception, if you link this library with other files,
2696263Sobrien   some of which are compiled with GCC, to produce an executable,
2796263Sobrien   this library does not by itself cause the resulting executable
2896263Sobrien   to be covered by the GNU General Public License.
2996263Sobrien   This exception does not however invalidate any other reasons why
3096263Sobrien   the executable file might be covered by the GNU General Public License.  */
3196263Sobrien
3296263Sobrien#ifndef GCC_GTHR_WIN32_H
3396263Sobrien#define GCC_GTHR_WIN32_H
3496263Sobrien
3596263Sobrien/* Windows32 threads specific definitions. The windows32 threading model
36117395Skan   does not map well into pthread-inspired gcc's threading model, and so
3796263Sobrien   there are caveats one needs to be aware of.
3896263Sobrien
3996263Sobrien   1. The destructor supplied to __gthread_key_create is ignored for
40117395Skan      generic x86-win32 ports. This will certainly cause memory leaks
41117395Skan      due to unreclaimed eh contexts (sizeof (eh_context) is at least
4296263Sobrien      24 bytes for x86 currently).
4396263Sobrien
4496263Sobrien      This memory leak may be significant for long-running applications
4596263Sobrien      that make heavy use of C++ EH.
4696263Sobrien
4796263Sobrien      However, Mingw runtime (version 0.3 or newer) provides a mechanism
4896263Sobrien      to emulate pthreads key dtors; the runtime provides a special DLL,
4996263Sobrien      linked in if -mthreads option is specified, that runs the dtors in
5096263Sobrien      the reverse order of registration when each thread exits. If
5196263Sobrien      -mthreads option is not given, a stub is linked in instead of the
52117395Skan      DLL, which results in memory leak. Other x86-win32 ports can use
5396263Sobrien      the same technique of course to avoid the leak.
5496263Sobrien
5596263Sobrien   2. The error codes returned are non-POSIX like, and cast into ints.
56117395Skan      This may cause incorrect error return due to truncation values on
5796263Sobrien      hw where sizeof (DWORD) > sizeof (int).
58117395Skan
59146895Skan   3. We are currently using a special mutex instead of the Critical
60146895Skan      Sections, since Win9x does not support TryEnterCriticalSection
61146895Skan      (while NT does).
62117395Skan
6396263Sobrien   The basic framework should work well enough. In the long term, GCC
6496263Sobrien   needs to use Structured Exception Handling on Windows32.  */
6596263Sobrien
6696263Sobrien#define __GTHREADS 1
6796263Sobrien
6896263Sobrien#include <errno.h>
6996263Sobrien#ifdef __MINGW32__
7096263Sobrien#include <_mingw.h>
7196263Sobrien#endif
7296263Sobrien
7396263Sobrien#ifdef _LIBOBJC
7496263Sobrien
7596263Sobrien/* This is necessary to prevent windef.h (included from windows.h) from
76169689Skan   defining its own BOOL as a typedef.  */
7796263Sobrien#ifndef __OBJC__
7896263Sobrien#define __OBJC__
7996263Sobrien#endif
8096263Sobrien#include <windows.h>
81117395Skan/* Now undef the windows BOOL.  */
8296263Sobrien#undef BOOL
8396263Sobrien
8496263Sobrien/* Key structure for maintaining thread specific storage */
85117395Skanstatic DWORD	__gthread_objc_data_tls = (DWORD) -1;
8696263Sobrien
8796263Sobrien/* Backend initialization functions */
8896263Sobrien
8996263Sobrien/* Initialize the threads subsystem.  */
9096263Sobrienint
91117395Skan__gthread_objc_init_thread_system (void)
9296263Sobrien{
93169689Skan  /* Initialize the thread storage key.  */
94117395Skan  if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
9596263Sobrien    return 0;
9696263Sobrien  else
9796263Sobrien    return -1;
9896263Sobrien}
9996263Sobrien
10096263Sobrien/* Close the threads subsystem.  */
10196263Sobrienint
102117395Skan__gthread_objc_close_thread_system (void)
10396263Sobrien{
104117395Skan  if (__gthread_objc_data_tls != (DWORD) -1)
105117395Skan    TlsFree (__gthread_objc_data_tls);
10696263Sobrien  return 0;
10796263Sobrien}
10896263Sobrien
10996263Sobrien/* Backend thread functions */
11096263Sobrien
11196263Sobrien/* Create a new thread of execution.  */
11296263Sobrienobjc_thread_t
113117395Skan__gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
11496263Sobrien{
11596263Sobrien  DWORD	thread_id = 0;
11696263Sobrien  HANDLE win32_handle;
11796263Sobrien
118117395Skan  if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
119117395Skan				     arg, 0, &thread_id)))
12096263Sobrien    thread_id = 0;
121117395Skan
122117395Skan  return (objc_thread_t) thread_id;
12396263Sobrien}
12496263Sobrien
12596263Sobrien/* Set the current thread's priority.  */
12696263Sobrienint
127117395Skan__gthread_objc_thread_set_priority (int priority)
12896263Sobrien{
12996263Sobrien  int sys_priority = 0;
13096263Sobrien
13196263Sobrien  switch (priority)
13296263Sobrien    {
13396263Sobrien    case OBJC_THREAD_INTERACTIVE_PRIORITY:
13496263Sobrien      sys_priority = THREAD_PRIORITY_NORMAL;
13596263Sobrien      break;
13696263Sobrien    default:
13796263Sobrien    case OBJC_THREAD_BACKGROUND_PRIORITY:
13896263Sobrien      sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
13996263Sobrien      break;
14096263Sobrien    case OBJC_THREAD_LOW_PRIORITY:
14196263Sobrien      sys_priority = THREAD_PRIORITY_LOWEST;
14296263Sobrien      break;
14396263Sobrien    }
14496263Sobrien
14596263Sobrien  /* Change priority */
146117395Skan  if (SetThreadPriority (GetCurrentThread (), sys_priority))
14796263Sobrien    return 0;
14896263Sobrien  else
14996263Sobrien    return -1;
15096263Sobrien}
15196263Sobrien
15296263Sobrien/* Return the current thread's priority.  */
15396263Sobrienint
154117395Skan__gthread_objc_thread_get_priority (void)
15596263Sobrien{
15696263Sobrien  int sys_priority;
15796263Sobrien
158117395Skan  sys_priority = GetThreadPriority (GetCurrentThread ());
159117395Skan
16096263Sobrien  switch (sys_priority)
16196263Sobrien    {
16296263Sobrien    case THREAD_PRIORITY_HIGHEST:
16396263Sobrien    case THREAD_PRIORITY_TIME_CRITICAL:
16496263Sobrien    case THREAD_PRIORITY_ABOVE_NORMAL:
16596263Sobrien    case THREAD_PRIORITY_NORMAL:
16696263Sobrien      return OBJC_THREAD_INTERACTIVE_PRIORITY;
16796263Sobrien
16896263Sobrien    default:
16996263Sobrien    case THREAD_PRIORITY_BELOW_NORMAL:
17096263Sobrien      return OBJC_THREAD_BACKGROUND_PRIORITY;
171117395Skan
17296263Sobrien    case THREAD_PRIORITY_IDLE:
17396263Sobrien    case THREAD_PRIORITY_LOWEST:
17496263Sobrien      return OBJC_THREAD_LOW_PRIORITY;
17596263Sobrien    }
17696263Sobrien
17796263Sobrien  /* Couldn't get priority.  */
17896263Sobrien  return -1;
17996263Sobrien}
18096263Sobrien
18196263Sobrien/* Yield our process time to another thread.  */
18296263Sobrienvoid
183117395Skan__gthread_objc_thread_yield (void)
18496263Sobrien{
185117395Skan  Sleep (0);
18696263Sobrien}
18796263Sobrien
18896263Sobrien/* Terminate the current thread.  */
18996263Sobrienint
190117395Skan__gthread_objc_thread_exit (void)
19196263Sobrien{
19296263Sobrien  /* exit the thread */
193117395Skan  ExitThread (__objc_thread_exit_status);
19496263Sobrien
19596263Sobrien  /* Failed if we reached here */
19696263Sobrien  return -1;
19796263Sobrien}
19896263Sobrien
19996263Sobrien/* Returns an integer value which uniquely describes a thread.  */
20096263Sobrienobjc_thread_t
201117395Skan__gthread_objc_thread_id (void)
20296263Sobrien{
203117395Skan  return (objc_thread_t) GetCurrentThreadId ();
20496263Sobrien}
20596263Sobrien
20696263Sobrien/* Sets the thread's local storage pointer.  */
20796263Sobrienint
208117395Skan__gthread_objc_thread_set_data (void *value)
20996263Sobrien{
210117395Skan  if (TlsSetValue (__gthread_objc_data_tls, value))
21196263Sobrien    return 0;
21296263Sobrien  else
21396263Sobrien    return -1;
21496263Sobrien}
21596263Sobrien
21696263Sobrien/* Returns the thread's local storage pointer.  */
21796263Sobrienvoid *
218117395Skan__gthread_objc_thread_get_data (void)
21996263Sobrien{
22096263Sobrien  DWORD lasterror;
22196263Sobrien  void *ptr;
22296263Sobrien
223117395Skan  lasterror = GetLastError ();
22496263Sobrien
225117395Skan  ptr = TlsGetValue (__gthread_objc_data_tls);          /* Return thread data.  */
22696263Sobrien
227117395Skan  SetLastError (lasterror);
22896263Sobrien
22996263Sobrien  return ptr;
23096263Sobrien}
23196263Sobrien
23296263Sobrien/* Backend mutex functions */
23396263Sobrien
23496263Sobrien/* Allocate a mutex.  */
23596263Sobrienint
236117395Skan__gthread_objc_mutex_allocate (objc_mutex_t mutex)
23796263Sobrien{
238117395Skan  if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
23996263Sobrien    return -1;
24096263Sobrien  else
24196263Sobrien    return 0;
24296263Sobrien}
24396263Sobrien
24496263Sobrien/* Deallocate a mutex.  */
24596263Sobrienint
246117395Skan__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
24796263Sobrien{
248117395Skan  CloseHandle ((HANDLE) (mutex->backend));
24996263Sobrien  return 0;
25096263Sobrien}
25196263Sobrien
25296263Sobrien/* Grab a lock on a mutex.  */
25396263Sobrienint
254117395Skan__gthread_objc_mutex_lock (objc_mutex_t mutex)
25596263Sobrien{
25696263Sobrien  int status;
25796263Sobrien
258117395Skan  status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
25996263Sobrien  if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
26096263Sobrien    return -1;
26196263Sobrien  else
26296263Sobrien    return 0;
26396263Sobrien}
26496263Sobrien
26596263Sobrien/* Try to grab a lock on a mutex.  */
26696263Sobrienint
267117395Skan__gthread_objc_mutex_trylock (objc_mutex_t mutex)
26896263Sobrien{
26996263Sobrien  int status;
27096263Sobrien
271117395Skan  status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
27296263Sobrien  if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
27396263Sobrien    return -1;
27496263Sobrien  else
27596263Sobrien    return 0;
27696263Sobrien}
27796263Sobrien
27896263Sobrien/* Unlock the mutex */
27996263Sobrienint
280117395Skan__gthread_objc_mutex_unlock (objc_mutex_t mutex)
28196263Sobrien{
282117395Skan  if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
28396263Sobrien    return -1;
28496263Sobrien  else
28596263Sobrien    return 0;
28696263Sobrien}
28796263Sobrien
28896263Sobrien/* Backend condition mutex functions */
28996263Sobrien
29096263Sobrien/* Allocate a condition.  */
29196263Sobrienint
292117395Skan__gthread_objc_condition_allocate (objc_condition_t condition)
29396263Sobrien{
29496263Sobrien  /* Unimplemented.  */
29596263Sobrien  return -1;
29696263Sobrien}
29796263Sobrien
29896263Sobrien/* Deallocate a condition.  */
29996263Sobrienint
300117395Skan__gthread_objc_condition_deallocate (objc_condition_t condition)
30196263Sobrien{
30296263Sobrien  /* Unimplemented.  */
30396263Sobrien  return -1;
30496263Sobrien}
30596263Sobrien
30696263Sobrien/* Wait on the condition */
30796263Sobrienint
308117395Skan__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
30996263Sobrien{
31096263Sobrien  /* Unimplemented.  */
31196263Sobrien  return -1;
31296263Sobrien}
31396263Sobrien
31496263Sobrien/* Wake up all threads waiting on this condition.  */
31596263Sobrienint
316117395Skan__gthread_objc_condition_broadcast (objc_condition_t condition)
31796263Sobrien{
31896263Sobrien  /* Unimplemented.  */
31996263Sobrien  return -1;
32096263Sobrien}
32196263Sobrien
32296263Sobrien/* Wake up one thread waiting on this condition.  */
32396263Sobrienint
324117395Skan__gthread_objc_condition_signal (objc_condition_t condition)
32596263Sobrien{
32696263Sobrien  /* Unimplemented.  */
32796263Sobrien  return -1;
32896263Sobrien}
32996263Sobrien
33096263Sobrien#else /* _LIBOBJC */
33196263Sobrien
332117395Skan#ifdef __cplusplus
333117395Skanextern "C" {
334117395Skan#endif
33596263Sobrien
336117395Skantypedef unsigned long __gthread_key_t;
33796263Sobrien
33896263Sobrientypedef struct {
33996263Sobrien  int done;
34096263Sobrien  long started;
34196263Sobrien} __gthread_once_t;
34296263Sobrien
343146895Skantypedef struct {
344146895Skan  long counter;
345146895Skan  void *sema;
346146895Skan} __gthread_mutex_t;
34796263Sobrien
348169689Skantypedef struct {
349169689Skan  long counter;
350169689Skan  long depth;
351169689Skan  unsigned long owner;
352169689Skan  void *sema;
353169689Skan} __gthread_recursive_mutex_t;
354169689Skan
355117395Skan#define __GTHREAD_ONCE_INIT {0, -1}
35696263Sobrien#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
357146895Skan#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
358169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
359169689Skan  __gthread_recursive_mutex_init_function
360169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
36196263Sobrien
36296263Sobrien#if __MINGW32_MAJOR_VERSION >= 1 || \
36396263Sobrien  (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
36496263Sobrien#define MINGW32_SUPPORTS_MT_EH 1
365117395Skan/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
366117395Skan   if -mthreads option was specified, or 0 otherwise. This is to get around
36796263Sobrien   the lack of weak symbols in PE-COFF.  */
36896263Sobrienextern int _CRT_MT;
369117395Skanextern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
370117395Skan#endif /* __MINGW32__ version */
37196263Sobrien
372169689Skan/* The Windows95 kernel does not export InterlockedCompareExchange.
373169689Skan   This provides a substitute.   When building apps that reference
374169689Skan   gthread_mutex_try_lock, the  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
375169689Skan   macro  must be defined if Windows95 is a target.  Currently
376169689Skan   gthread_mutex_try_lock is not referenced by libgcc or libstdc++.  */
377146895Skan#ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
378146895Skanstatic inline long
379146895Skan__gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
380146895Skan{
381146895Skan  long result;
382146895Skan  __asm__ __volatile__ ("\n\
383146895Skan	lock\n\
384146895Skan	cmpxchg{l} {%4, %1|%1, %4}\n"
385146895Skan	: "=a" (result), "=m" (*dest)
386146895Skan	: "0" (comperand), "m" (*dest), "r" (xchg)
387146895Skan	: "cc");
388146895Skan  return result;
389146895Skan}
390146895Skan#define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
391146895Skan#else  /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
392146895Skan#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
393146895Skan#endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
394146895Skan
39596263Sobrienstatic inline int
39696263Sobrien__gthread_active_p (void)
39796263Sobrien{
39896263Sobrien#ifdef MINGW32_SUPPORTS_MT_EH
39996263Sobrien  return _CRT_MT;
40096263Sobrien#else
40196263Sobrien  return 1;
40296263Sobrien#endif
40396263Sobrien}
40496263Sobrien
405132718Skan#if __GTHREAD_HIDE_WIN32API
406117395Skan
407117395Skan/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
408117395Skan   Only stubs are exposed to avoid polluting the C++ namespace with
409117395Skan   windows api definitions.  */
410117395Skan
411117395Skanextern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
412117395Skanextern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
413117395Skanextern int __gthr_win32_key_delete (__gthread_key_t);
414117395Skanextern void * __gthr_win32_getspecific (__gthread_key_t);
415117395Skanextern int __gthr_win32_setspecific (__gthread_key_t, const void *);
416117395Skanextern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
417117395Skanextern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
418117395Skanextern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
419117395Skanextern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
420169689Skanextern void
421169689Skan  __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
422169689Skanextern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
423169689Skanextern int
424169689Skan  __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
425169689Skanextern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
426117395Skan
42796263Sobrienstatic inline int
42896263Sobrien__gthread_once (__gthread_once_t *once, void (*func) (void))
42996263Sobrien{
430117395Skan  if (__gthread_active_p ())
431117395Skan    return __gthr_win32_once (once, func);
432117395Skan  else
433117395Skan    return -1;
434117395Skan}
435117395Skan
436117395Skanstatic inline int
437117395Skan__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
438117395Skan{
439117395Skan  return __gthr_win32_key_create (key, dtor);
440117395Skan}
441117395Skan
442117395Skanstatic inline int
443117395Skan__gthread_key_delete (__gthread_key_t key)
444117395Skan{
445117395Skan  return __gthr_win32_key_delete (key);
446117395Skan}
447117395Skan
448117395Skanstatic inline void *
449117395Skan__gthread_getspecific (__gthread_key_t key)
450117395Skan{
451117395Skan  return __gthr_win32_getspecific (key);
452117395Skan}
453117395Skan
454117395Skanstatic inline int
455117395Skan__gthread_setspecific (__gthread_key_t key, const void *ptr)
456117395Skan{
457117395Skan  return __gthr_win32_setspecific (key, ptr);
458117395Skan}
459117395Skan
460117395Skanstatic inline void
461117395Skan__gthread_mutex_init_function (__gthread_mutex_t *mutex)
462117395Skan{
463117395Skan  __gthr_win32_mutex_init_function (mutex);
464117395Skan}
465117395Skan
466117395Skanstatic inline int
467117395Skan__gthread_mutex_lock (__gthread_mutex_t *mutex)
468117395Skan{
469117395Skan  if (__gthread_active_p ())
470117395Skan    return __gthr_win32_mutex_lock (mutex);
471117395Skan  else
472117395Skan    return 0;
473117395Skan}
474117395Skan
475117395Skanstatic inline int
476117395Skan__gthread_mutex_trylock (__gthread_mutex_t *mutex)
477117395Skan{
478117395Skan  if (__gthread_active_p ())
479117395Skan    return __gthr_win32_mutex_trylock (mutex);
480117395Skan  else
481117395Skan    return 0;
482117395Skan}
483117395Skan
484117395Skanstatic inline int
485117395Skan__gthread_mutex_unlock (__gthread_mutex_t *mutex)
486117395Skan{
487117395Skan  if (__gthread_active_p ())
488117395Skan    return __gthr_win32_mutex_unlock (mutex);
489117395Skan  else
490117395Skan    return 0;
491117395Skan}
492117395Skan
493169689Skanstatic inline void
494169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
495169689Skan{
496169689Skan   __gthr_win32_recursive_mutex_init_function (mutex);
497169689Skan}
498169689Skan
499169689Skanstatic inline int
500169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
501169689Skan{
502169689Skan  if (__gthread_active_p ())
503169689Skan    return __gthr_win32_recursive_mutex_lock (mutex);
504169689Skan  else
505169689Skan    return 0;
506169689Skan}
507169689Skan
508169689Skanstatic inline int
509169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
510169689Skan{
511169689Skan  if (__gthread_active_p ())
512169689Skan    return __gthr_win32_recursive_mutex_trylock (mutex);
513169689Skan  else
514169689Skan    return 0;
515169689Skan}
516169689Skan
517169689Skanstatic inline int
518169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
519169689Skan{
520169689Skan  if (__gthread_active_p ())
521169689Skan    return __gthr_win32_recursive_mutex_unlock (mutex);
522169689Skan  else
523169689Skan    return 0;
524169689Skan}
525169689Skan
526117395Skan#else /* ! __GTHREAD_HIDE_WIN32API */
527117395Skan
528117395Skan#include <windows.h>
529117395Skan#include <errno.h>
530117395Skan
531117395Skanstatic inline int
532117395Skan__gthread_once (__gthread_once_t *once, void (*func) (void))
533117395Skan{
53496263Sobrien  if (! __gthread_active_p ())
53596263Sobrien    return -1;
53696263Sobrien  else if (once == NULL || func == NULL)
53796263Sobrien    return EINVAL;
53896263Sobrien
53996263Sobrien  if (! once->done)
54096263Sobrien    {
54196263Sobrien      if (InterlockedIncrement (&(once->started)) == 0)
542117395Skan	{
54396263Sobrien	  (*func) ();
54496263Sobrien	  once->done = TRUE;
54596263Sobrien	}
54696263Sobrien      else
54796263Sobrien	{
548117395Skan	  /* Another thread is currently executing the code, so wait for it
549117395Skan	     to finish; yield the CPU in the meantime.  If performance
550117395Skan	     does become an issue, the solution is to use an Event that
551117395Skan	     we wait on here (and set above), but that implies a place to
552117395Skan	     create the event before this routine is called.  */
55396263Sobrien	  while (! once->done)
55496263Sobrien	    Sleep (0);
55596263Sobrien	}
55696263Sobrien    }
557117395Skan
55896263Sobrien  return 0;
55996263Sobrien}
56096263Sobrien
56196263Sobrien/* Windows32 thread local keys don't support destructors; this leads to
562117395Skan   leaks, especially in threaded applications making extensive use of
56396263Sobrien   C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
56496263Sobrienstatic inline int
56596263Sobrien__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
56696263Sobrien{
56796263Sobrien  int status = 0;
56896263Sobrien  DWORD tls_index = TlsAlloc ();
56996263Sobrien  if (tls_index != 0xFFFFFFFF)
57096263Sobrien    {
57196263Sobrien      *key = tls_index;
57296263Sobrien#ifdef MINGW32_SUPPORTS_MT_EH
57396263Sobrien      /* Mingw runtime will run the dtors in reverse order for each thread
57496263Sobrien         when the thread exits.  */
57596263Sobrien      status = __mingwthr_key_dtor (*key, dtor);
57696263Sobrien#endif
57796263Sobrien    }
57896263Sobrien  else
57996263Sobrien    status = (int) GetLastError ();
58096263Sobrien  return status;
58196263Sobrien}
58296263Sobrien
58396263Sobrienstatic inline int
58496263Sobrien__gthread_key_delete (__gthread_key_t key)
58596263Sobrien{
58696263Sobrien  return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
58796263Sobrien}
58896263Sobrien
58996263Sobrienstatic inline void *
59096263Sobrien__gthread_getspecific (__gthread_key_t key)
59196263Sobrien{
59296263Sobrien  DWORD lasterror;
59396263Sobrien  void *ptr;
59496263Sobrien
595117395Skan  lasterror = GetLastError ();
59696263Sobrien
597117395Skan  ptr = TlsGetValue (key);
59896263Sobrien
599117395Skan  SetLastError (lasterror);
60096263Sobrien
60196263Sobrien  return ptr;
60296263Sobrien}
60396263Sobrien
60496263Sobrienstatic inline int
60596263Sobrien__gthread_setspecific (__gthread_key_t key, const void *ptr)
60696263Sobrien{
60796263Sobrien  return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
60896263Sobrien}
60996263Sobrien
61096263Sobrienstatic inline void
61196263Sobrien__gthread_mutex_init_function (__gthread_mutex_t *mutex)
61296263Sobrien{
613146895Skan  mutex->counter = -1;
614146895Skan  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
61596263Sobrien}
61696263Sobrien
61796263Sobrienstatic inline int
61896263Sobrien__gthread_mutex_lock (__gthread_mutex_t *mutex)
61996263Sobrien{
62096263Sobrien  int status = 0;
62196263Sobrien
62296263Sobrien  if (__gthread_active_p ())
62396263Sobrien    {
624146895Skan      if (InterlockedIncrement (&mutex->counter) == 0 ||
625146895Skan	  WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
62696263Sobrien	status = 0;
62796263Sobrien      else
628146895Skan	{
629146895Skan	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
630146895Skan	     some best-effort cleanup here.  */
631146895Skan	  InterlockedDecrement (&mutex->counter);
632146895Skan	  status = 1;
633146895Skan	}
63496263Sobrien    }
63596263Sobrien  return status;
63696263Sobrien}
63796263Sobrien
63896263Sobrienstatic inline int
63996263Sobrien__gthread_mutex_trylock (__gthread_mutex_t *mutex)
64096263Sobrien{
64196263Sobrien  int status = 0;
64296263Sobrien
64396263Sobrien  if (__gthread_active_p ())
64496263Sobrien    {
645146895Skan      if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
64696263Sobrien	status = 0;
64796263Sobrien      else
64896263Sobrien	status = 1;
64996263Sobrien    }
65096263Sobrien  return status;
65196263Sobrien}
65296263Sobrien
65396263Sobrienstatic inline int
65496263Sobrien__gthread_mutex_unlock (__gthread_mutex_t *mutex)
65596263Sobrien{
65696263Sobrien  if (__gthread_active_p ())
657146895Skan    {
658146895Skan      if (InterlockedDecrement (&mutex->counter) >= 0)
659146895Skan	return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
660146895Skan    }
661146895Skan  return 0;
66296263Sobrien}
66396263Sobrien
664169689Skanstatic inline void
665169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
666169689Skan{
667169689Skan  mutex->counter = -1;
668169689Skan  mutex->depth = 0;
669169689Skan  mutex->owner = 0;
670169689Skan  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
671169689Skan}
672169689Skan
673169689Skanstatic inline int
674169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
675169689Skan{
676169689Skan  if (__gthread_active_p ())
677169689Skan    {
678169689Skan      DWORD me = GetCurrentThreadId();
679169689Skan      if (InterlockedIncrement (&mutex->counter) == 0)
680169689Skan	{
681169689Skan	  mutex->depth = 1;
682169689Skan	  mutex->owner = me;
683169689Skan	}
684169689Skan      else if (mutex->owner == me)
685169689Skan	{
686169689Skan	  InterlockedDecrement (&mutex->counter);
687169689Skan	  ++(mutex->depth);
688169689Skan	}
689169689Skan      else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
690169689Skan	{
691169689Skan	  mutex->depth = 1;
692169689Skan	  mutex->owner = me;
693169689Skan	}
694169689Skan      else
695169689Skan	{
696169689Skan	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
697169689Skan	     some best-effort cleanup here.  */
698169689Skan	  InterlockedDecrement (&mutex->counter);
699169689Skan	  return 1;
700169689Skan	}
701169689Skan    }
702169689Skan  return 0;
703169689Skan}
704169689Skan
705169689Skanstatic inline int
706169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
707169689Skan{
708169689Skan  if (__gthread_active_p ())
709169689Skan    {
710169689Skan      DWORD me = GetCurrentThreadId();
711169689Skan      if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
712169689Skan	{
713169689Skan	  mutex->depth = 1;
714169689Skan	  mutex->owner = me;
715169689Skan	}
716169689Skan      else if (mutex->owner == me)
717169689Skan	++(mutex->depth);
718169689Skan      else
719169689Skan	return 1;
720169689Skan    }
721169689Skan  return 0;
722169689Skan}
723169689Skan
724169689Skanstatic inline int
725169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
726169689Skan{
727169689Skan  if (__gthread_active_p ())
728169689Skan    {
729169689Skan      --(mutex->depth);
730169689Skan      if (mutex->depth == 0)
731169689Skan	{
732169689Skan	  mutex->owner = 0;
733169689Skan
734169689Skan	  if (InterlockedDecrement (&mutex->counter) >= 0)
735169689Skan	    return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
736169689Skan	}
737169689Skan    }
738169689Skan  return 0;
739169689Skan}
740169689Skan
741117395Skan#endif /*  __GTHREAD_HIDE_WIN32API */
742117395Skan
743117395Skan#ifdef __cplusplus
744117395Skan}
745117395Skan#endif
746117395Skan
74796263Sobrien#endif /* _LIBOBJC */
74896263Sobrien
74996263Sobrien#endif /* ! GCC_GTHR_WIN32_H */
750