OSDN Git Service

* de.po, zh_CN.po: Update.
[pf3gnuchains/gcc-fork.git] / gcc / gthr-win32.h
index fe8743a..5e17360 100644 (file)
@@ -1,6 +1,8 @@
 /* Threads compatibility routines for libgcc2 and libobjc.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
+
+/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
 
 This file is part of GCC.
@@ -54,10 +56,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
       This may cause incorrect error return due to truncation values on
       hw where sizeof (DWORD) > sizeof (int).
 
-   3. We might consider using Critical Sections instead of Windows32
-      mutexes for better performance, but emulating __gthread_mutex_trylock
-      interface becomes more complicated (Win9x does not support
-      TryEnterCriticalSectioni, while NT does).
+   3. We are currently using a special mutex instead of the Critical
+      Sections, since Win9x does not support TryEnterCriticalSection
+      (while NT does).
 
    The basic framework should work well enough. In the long term, GCC
    needs to use Structured Exception Handling on Windows32.  */
@@ -72,7 +73,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #ifdef _LIBOBJC
 
 /* This is necessary to prevent windef.h (included from windows.h) from
-   defining it's own BOOL as a typedef.  */
+   defining its own BOOL as a typedef.  */
 #ifndef __OBJC__
 #define __OBJC__
 #endif
@@ -89,7 +90,7 @@ static DWORD  __gthread_objc_data_tls = (DWORD) -1;
 int
 __gthread_objc_init_thread_system (void)
 {
-  /* Initialize the thread storage key */
+  /* Initialize the thread storage key */
   if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
     return 0;
   else
@@ -339,11 +340,24 @@ typedef struct {
   long started;
 } __gthread_once_t;
 
-typedef void* __gthread_mutex_t;
+typedef struct {
+  long counter;
+  void *sema;
+} __gthread_mutex_t;
+
+typedef struct {
+  long counter;
+  long depth;
+  unsigned long owner;
+  void *sema;
+} __gthread_recursive_mutex_t;
 
 #define __GTHREAD_ONCE_INIT {0, -1}
 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
-#define __GTHREAD_MUTEX_INIT_DEFAULT 0
+#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
+  __gthread_recursive_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
 
 #if __MINGW32_MAJOR_VERSION >= 1 || \
   (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
@@ -355,6 +369,29 @@ extern int _CRT_MT;
 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
 #endif /* __MINGW32__ version */
 
+/* The Windows95 kernel does not export InterlockedCompareExchange.
+   This provides a substitute.   When building apps that reference
+   gthread_mutex_try_lock, the  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
+   macro  must be defined if Windows95 is a target.  Currently
+   gthread_mutex_try_lock is not referenced by libgcc or libstdc++.  */
+#ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
+static inline long
+__gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
+{
+  long result;
+  __asm__ __volatile__ ("\n\
+       lock\n\
+       cmpxchg{l} {%4, %1|%1, %4}\n"
+       : "=a" (result), "=m" (*dest)
+       : "0" (comperand), "m" (*dest), "r" (xchg)
+       : "cc");
+  return result;
+}
+#define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
+#else  /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
+#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
+#endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
+
 static inline int
 __gthread_active_p (void)
 {
@@ -365,7 +402,7 @@ __gthread_active_p (void)
 #endif
 }
 
-#ifdef __GTHREAD_HIDE_WIN32API
+#if __GTHREAD_HIDE_WIN32API
 
 /* The implementations are in config/i386/gthr-win32.c in libgcc.a.
    Only stubs are exposed to avoid polluting the C++ namespace with
@@ -380,6 +417,12 @@ extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
 extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
 extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
 extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
+extern void
+  __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
+extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
+extern int
+  __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
+extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
 
 static inline int
 __gthread_once (__gthread_once_t *once, void (*func) (void))
@@ -447,6 +490,39 @@ __gthread_mutex_unlock (__gthread_mutex_t *mutex)
     return 0;
 }
 
+static inline void
+__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
+{
+   __gthr_win32_recursive_mutex_init_function (mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_recursive_mutex_lock (mutex);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_recursive_mutex_trylock (mutex);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_recursive_mutex_unlock (mutex);
+  else
+    return 0;
+}
+
 #else /* ! __GTHREAD_HIDE_WIN32API */
 
 #include <windows.h>
@@ -534,8 +610,8 @@ __gthread_setspecific (__gthread_key_t key, const void *ptr)
 static inline void
 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
 {
-  /* Create unnamed mutex with default security attr and no initial owner.  */
-  *mutex = CreateMutex (NULL, 0, NULL);
+  mutex->counter = -1;
+  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
 }
 
 static inline int
@@ -545,10 +621,16 @@ __gthread_mutex_lock (__gthread_mutex_t *mutex)
 
   if (__gthread_active_p ())
     {
-      if (WaitForSingleObject (*mutex, INFINITE) == WAIT_OBJECT_0)
+      if (InterlockedIncrement (&mutex->counter) == 0 ||
+         WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
        status = 0;
       else
-       status = 1;
+       {
+         /* WaitForSingleObject returns WAIT_FAILED, and we can only do
+            some best-effort cleanup here.  */
+         InterlockedDecrement (&mutex->counter);
+         status = 1;
+       }
     }
   return status;
 }
@@ -560,7 +642,7 @@ __gthread_mutex_trylock (__gthread_mutex_t *mutex)
 
   if (__gthread_active_p ())
     {
-      if (WaitForSingleObject (*mutex, 0) == WAIT_OBJECT_0)
+      if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
        status = 0;
       else
        status = 1;
@@ -572,9 +654,88 @@ static inline int
 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
 {
   if (__gthread_active_p ())
-    return (ReleaseMutex (*mutex) != 0) ? 0 : 1;
-  else
-    return 0;
+    {
+      if (InterlockedDecrement (&mutex->counter) >= 0)
+       return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
+    }
+  return 0;
+}
+
+static inline void
+__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
+{
+  mutex->counter = -1;
+  mutex->depth = 0;
+  mutex->owner = 0;
+  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    {
+      DWORD me = GetCurrentThreadId();
+      if (InterlockedIncrement (&mutex->counter) == 0)
+       {
+         mutex->depth = 1;
+         mutex->owner = me;
+       }
+      else if (mutex->owner == me)
+       {
+         InterlockedDecrement (&mutex->counter);
+         ++(mutex->depth);
+       }
+      else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
+       {
+         mutex->depth = 1;
+         mutex->owner = me;
+       }
+      else
+       {
+         /* WaitForSingleObject returns WAIT_FAILED, and we can only do
+            some best-effort cleanup here.  */
+         InterlockedDecrement (&mutex->counter);
+         return 1;
+       }
+    }
+  return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    {
+      DWORD me = GetCurrentThreadId();
+      if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
+       {
+         mutex->depth = 1;
+         mutex->owner = me;
+       }
+      else if (mutex->owner == me)
+       ++(mutex->depth);
+      else
+       return 1;
+    }
+  return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+{
+  if (__gthread_active_p ())
+    {
+      --(mutex->depth);
+      if (mutex->depth == 0)
+       {
+         mutex->owner = 0;
+
+         if (InterlockedDecrement (&mutex->counter) >= 0)
+           return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
+       }
+    }
+  return 0;
 }
 
 #endif /*  __GTHREAD_HIDE_WIN32API */