OSDN Git Service

2004-08-04 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / gthr-win32.h
index 38b8f04..b761804 100644 (file)
@@ -1,6 +1,6 @@
 /* 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  Free Software Foundation, Inc.
    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
 
 This file is part of GCC.
@@ -54,10 +54,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.  */
@@ -339,11 +338,14 @@ typedef struct {
   long started;
 } __gthread_once_t;
 
-typedef void* __gthread_mutex_t;
+typedef struct {
+  long counter;
+  void *sema;
+} __gthread_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}
 
 #if __MINGW32_MAJOR_VERSION >= 1 || \
   (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
@@ -355,6 +357,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 +390,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
@@ -397,13 +422,6 @@ __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
 }
 
 static inline int
-__gthread_key_dtor (__gthread_key_t key, void *ptr)
-{
-  /* Nothing needed.  */
-  return 0;
-}
-
-static inline int
 __gthread_key_delete (__gthread_key_t key)
 {
   return __gthr_win32_key_delete (key);
@@ -511,15 +529,6 @@ __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
   return status;
 }
 
-/* Currently, this routine is called only for Mingw runtime, and if
-   -mthreads option is chosen to link in the thread support DLL.  */
-static inline int
-__gthread_key_dtor (__gthread_key_t key, void *ptr)
-{
-  /* Nothing needed.  */
-  return 0;
-}
-
 static inline int
 __gthread_key_delete (__gthread_key_t key)
 {
@@ -550,8 +559,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
@@ -561,10 +570,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;
 }
@@ -576,7 +591,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;
@@ -588,9 +603,11 @@ 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;
 }
 
 #endif /*  __GTHREAD_HIDE_WIN32API */