2007-09-13 Doug Kwan <dougkwan@google.com>
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Oct 2007 05:35:46 +0000 (05:35 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Oct 2007 05:35:46 +0000 (05:35 +0000)
        * gcc/gthr-posix.h (__gthread_cond_broadcast, __gthread_cond_wait,
        __gthread_cond_wait_recursive): Add to extend interface for POSIX
        conditional variables. (__GTHREAD_HAS_COND): Macro defined to signify
        support of conditional variables.
        * gcc/gthr-posix95.h (__gthread_cond_broadcast, __gthread_cond_wait,
        __gthread_cond_wait_recursive): Add to extend interface for POSIX
        conditional variables. (__GTHREAD_HAS_COND): Macro defined to signify
        support of conditional variables.
        * gcc/gthr-single.h (__gthread_cond_broadcast, __gthread_cond_wait,
        __gthread_cond_wait_recursive): Add to extend interface for POSIX
        conditional variables.
        * gcc/gthr.h: Update comments to document new interface.
        * libstdc++-v3/include/ext/concurrent.h (class __mutex,
        class __recursive_mutex): Add new method gthread_mutex to access
        inner gthread mutex.
        [__GTHREAD_HAS_COND] (class __concurrence_broadcast_error,
        class __concurrence_wait_error, class __cond): Add.
        * guard.cc (recursive_push, recursive_pop): Delete.
        (init_in_progress_flag, set_init_in_progress_flag): Add to
        replace recursive_push and recursive_pop.
        (throw_recursive_init_exception): Add.
        (acquire, __cxa_guard_acquire, __cxa_guard_abort and
        __cxa_guard_release): [__GTHREAD_HAS_COND] Use a conditional
        for synchronization of static variable initialization.
        The global mutex is only held briefly when guards are
        accessed. [!__GTHREAD_HAS_COND] Fall back to the old code,
        which deadlocks.
        * testsuite/thread/guard.cc: Add new test. It deadlocks with the
        old locking code in libstdc++-v3/libsup++/guard.cc.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@129030 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gthr-posix.h
gcc/gthr-posix95.h
gcc/gthr-single.h
gcc/gthr.h
libstdc++-v3/ChangeLog
libstdc++-v3/include/ext/concurrence.h
libstdc++-v3/libsupc++/guard.cc
libstdc++-v3/testsuite/thread/guard.cc [new file with mode: 0644]

index 35003ed..3dabeea 100644 (file)
@@ -1,3 +1,18 @@
+2007-10-04  Doug Kwan  <dougkwan@google.com>
+
+       * gthr-posix.h (__gthread_cond_broadcast, __gthread_cond_wait,
+       __gthread_cond_wait_recursive): Add to extend interface for POSIX
+       conditional variables. (__GTHREAD_HAS_COND): Macro defined to signify
+       support of conditional variables.
+       * gthr-posix95.h (__gthread_cond_broadcast, __gthread_cond_wait,
+       __gthread_cond_wait_recursive): Add to extend interface for POSIX
+       conditional variables. (__GTHREAD_HAS_COND): Macro defined to signify
+       support of conditional variables.
+       * gthr-single.h (__gthread_cond_broadcast, __gthread_cond_wait,
+       __gthread_cond_wait_recursive): Add to extend interface for POSIX
+       conditional variables.
+       * gthr.h: Update comments to document new interface.
+
 2007-10-04  Geoffrey Keating  <geoffk@apple.com>
 
        * cgraphunit.c (cgraph_build_static_cdtor): Don't set
index a290b6a..5c00cd3 100644 (file)
@@ -47,6 +47,11 @@ typedef pthread_key_t __gthread_key_t;
 typedef pthread_once_t __gthread_once_t;
 typedef pthread_mutex_t __gthread_mutex_t;
 typedef pthread_mutex_t __gthread_recursive_mutex_t;
+typedef pthread_cond_t __gthread_cond_t;
+
+/* POSIX like conditional variables are supported.  Please look at comments
+   in gthr.h for details. */
+#define __GTHREAD_HAS_COND     1       
 
 #define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
 #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
@@ -57,6 +62,7 @@ typedef pthread_mutex_t __gthread_recursive_mutex_t;
 #else
 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
 #endif
+#define __GTHREAD_COND_INIT PTHREAD_COND_INITIALIZER
 
 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
 # ifndef __gthrw_pragma
@@ -88,6 +94,8 @@ __gthrw3(pthread_mutex_lock)
 __gthrw3(pthread_mutex_trylock)
 __gthrw3(pthread_mutex_unlock)
 __gthrw3(pthread_mutex_init)
+__gthrw3(pthread_cond_broadcast)
+__gthrw3(pthread_cond_wait)
 #else
 __gthrw(pthread_once)
 __gthrw(pthread_getspecific)
@@ -98,6 +106,8 @@ __gthrw(pthread_mutex_lock)
 __gthrw(pthread_mutex_trylock)
 __gthrw(pthread_mutex_unlock)
 __gthrw(pthread_mutex_init)
+__gthrw(pthread_cond_broadcast)
+__gthrw(pthread_cond_wait)
 #endif
 
 __gthrw(pthread_key_create)
@@ -110,20 +120,16 @@ __gthrw(pthread_mutexattr_destroy)
 #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
 /* Objective-C.  */
 #if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_)
-__gthrw3(pthread_cond_broadcast)
 __gthrw3(pthread_cond_destroy)
 __gthrw3(pthread_cond_init)
 __gthrw3(pthread_cond_signal)
-__gthrw3(pthread_cond_wait)
 __gthrw3(pthread_exit)
 __gthrw3(pthread_mutex_destroy)
 __gthrw3(pthread_self)
 #else
-__gthrw(pthread_cond_broadcast)
 __gthrw(pthread_cond_destroy)
 __gthrw(pthread_cond_init)
 __gthrw(pthread_cond_signal)
-__gthrw(pthread_cond_wait)
 __gthrw(pthread_exit)
 __gthrw(pthread_mutex_destroy)
 __gthrw(pthread_self)
@@ -737,6 +743,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
   return __gthread_mutex_unlock (mutex);
 }
 
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *cond)
+{
+  return __gthrw_(pthread_cond_broadcast) (cond);
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthrw_(pthread_cond_wait) (cond, mutex);
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                              __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_cond_wait (cond, mutex);
+}
+
 #endif /* _LIBOBJC */
 
 #endif /* ! GCC_GTHR_POSIX_H */
index f0d1553..df250d2 100644 (file)
@@ -45,6 +45,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 typedef pthread_key_t __gthread_key_t;
 typedef pthread_once_t __gthread_once_t;
 typedef pthread_mutex_t __gthread_mutex_t;
+typedef pthread_cond_t __gthread_cond_t;
+
+/* POSIX like conditional variables are supported.  Please look at comments
+   in gthr.h for details. */
+#define __GTHREAD_HAS_COND     1
 
 typedef struct {
   long depth;
@@ -55,6 +60,7 @@ typedef struct {
 #define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
 #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
+#define __GTHREAD_COND_INIT PTHREAD_COND_INITIALIZER
 
 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
 # define __gthrw(name) \
@@ -81,14 +87,14 @@ __gthrw(pthread_mutexattr_init)
 __gthrw(pthread_mutexattr_destroy)
 
 __gthrw(pthread_mutex_init)
+__gthrw(pthread_cond_broadcast)
+__gthrw(pthread_cond_wait)
 
 #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
 /* Objective-C.  */
-__gthrw(pthread_cond_broadcast)
 __gthrw(pthread_cond_destroy)
 __gthrw(pthread_cond_init)
 __gthrw(pthread_cond_signal)
-__gthrw(pthread_cond_wait)
 __gthrw(pthread_exit)
 __gthrw(pthread_mutex_destroy)
 #ifdef _POSIX_PRIORITY_SCHEDULING
@@ -719,6 +725,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
   return 0;
 }
 
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *cond)
+{
+  return __gthrw_(pthread_cond_broadcast) (cond);
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthrw_(pthread_cond_wait) (cond, mutex);
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                              __gthread_recursive_mutex_t *mutex)
+{
+  return __gthrw_(pthread_cond_wait) (cond, mutex->actual);
+}
+
 #endif /* _LIBOBJC */
 
 #endif /* ! GCC_GTHR_POSIX_H */
index c3a903d..56fd3a7 100644 (file)
@@ -251,6 +251,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
   return __gthread_mutex_unlock (mutex);
 }
 
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t cond)
+{
+  return 0;
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t cond, __gthread_mutex_t *mutex)
+{
+  return 0;
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t cond,
+                              __gthread_recursive_mutex_t *mutex)
+{
+  return 0;
+}
+
 #endif /* _LIBOBJC */
 
 #undef UNUSED
index b9d1641..a37b911 100644 (file)
@@ -81,6 +81,24 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
      int __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex);
      int __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex);
 
+   The following are supported in POSIX threads only. They are required to
+   fix a deadlock in static initialization inside libsupc++. The header file
+   gthr-posix.h defines a symbol __GTHREAD_HAS_COND to signify that these extra
+   features are supported.
+
+   Types:
+     __gthread_cond_t
+
+   Macros:
+     __GTHREAD_COND_INIT
+     __GTHREAD_COND_INIT_FUNCTION
+
+   Interface:
+     int __gthread_cond_broadcast (__gthread_cond_t *cond);
+     int __gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex);
+     int __gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                                       __gthread_recursive_mutex_t *mutex);
+
    All functions returning int should return zero on success or the error
    number.  If the operation is not supported, -1 is returned.
 
index d02e602..cfd6c2f 100644 (file)
@@ -1,3 +1,23 @@
+2007-10-04  Doug Kwan  <dougkwan@google.com>
+
+       * include/ext/concurrent.h (class __mutex,
+       class __recursive_mutex): Add new method gthread_mutex to access
+       inner gthread mutex.
+       [__GTHREAD_HAS_COND] (class __concurrence_broadcast_error,
+       class __concurrence_wait_error, class __cond): Add.
+       * libsupc++/guard.cc (recursive_push, recursive_pop): Delete.
+       (init_in_progress_flag, set_init_in_progress_flag): Add to
+       replace recursive_push and recursive_pop.
+       (throw_recursive_init_exception): Add.
+       (acquire, __cxa_guard_acquire, __cxa_guard_abort and
+       __cxa_guard_release): [__GTHREAD_HAS_COND] Use a conditional
+       for synchronization of static variable initialization.
+       The global mutex is only held briefly when guards are
+       accessed. [!__GTHREAD_HAS_COND] Fall back to the old code,
+       which deadlocks.
+       * testsuite/thread/guard.cc: Add new test. It deadlocks with the
+       old locking code in libstdc++-v3/libsup++/guard.cc.
+
 2007-10-04  Paolo Carlini  <pcarlini@suse.de>
 
        * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
index 3556acf..765b93d 100644 (file)
@@ -81,6 +81,22 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
     { return "__gnu_cxx::__concurrence_unlock_error"; }
   };
 
+  class __concurrence_broadcast_error : public std::exception
+  {
+  public:
+    virtual char const*
+    what() const throw()
+    { return "__gnu_cxx::__concurrence_broadcast_error"; }
+  };
+
+  class __concurrence_wait_error : public std::exception
+  {
+  public:
+    virtual char const*
+    what() const throw()
+    { return "__gnu_cxx::__concurrence_wait_error"; }
+  };
+
   // Substitute for concurrence_error object in the case of -fno-exceptions.
   inline void
   __throw_concurrence_lock_error()
@@ -102,6 +118,28 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
 #endif
   }
 
+#ifdef __GTHREAD_HAS_COND
+  inline void
+  __throw_concurrence_broadcast_error()
+  {
+#if __EXCEPTIONS
+    throw __concurrence_broadcast_error();
+#else
+    __builtin_abort();
+#endif
+  }
+
+  inline void
+  __throw_concurrence_wait_error()
+  {
+#if __EXCEPTIONS
+    throw __concurrence_wait_error();
+#else
+    __builtin_abort();
+#endif
+  }
+#endif
   class __mutex 
   {
   private:
@@ -147,6 +185,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
        }
 #endif
     }
+
+    __gthread_mutex_t* gthread_mutex(void)
+      { return &_M_mutex; }
   };
 
   class __recursive_mutex 
@@ -194,6 +235,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
        }
 #endif
     }
+
+    __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
+      { return &_M_mutex; }
   };
 
   /// @brief  Scoped lock idiom.
@@ -218,6 +262,66 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
     { _M_device.unlock(); }
   };
 
+#ifdef __GTHREAD_HAS_COND
+  class __cond
+  {
+  private:
+    __gthread_cond_t _M_cond;
+
+    __cond(const __cond&);
+    __cond& operator=(const __cond&);
+
+  public:
+    __cond() 
+    { 
+#if __GTHREADS
+      if (__gthread_active_p())
+       {
+#if defined __GTHREAD_COND_INIT
+         __gthread_cond_t __tmp = __GTHREAD_COND_INIT;
+         _M_cond = __tmp;
+#else
+         __GTHREAD_MUTEX_INIT_FUNCTION(&_M_cond);
+#endif
+       }
+#endif 
+    }
+
+    void broadcast()
+    {
+#if __GTHREADS
+      if (__gthread_active_p())
+       {
+         if (__gthread_cond_broadcast(&_M_cond) != 0)
+           __throw_concurrence_broadcast_error();
+       }
+#endif
+    }
+
+    void wait(__mutex *mutex)
+    {
+#if __GTHREADS
+      {
+         if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
+           __throw_concurrence_wait_error();
+      }
+#endif
+    }
+
+    void wait_recursive(__recursive_mutex *mutex)
+    {
+#if __GTHREADS
+      {
+         if (__gthread_cond_wait_recursive(&_M_cond,
+                                           mutex->gthread_recursive_mutex())
+             != 0)
+           __throw_concurrence_wait_error();
+      }
+#endif
+    }
+  };
+#endif
+
 _GLIBCXX_END_NAMESPACE
 
 #endif
index eb64216..b714aec 100644 (file)
@@ -62,6 +62,28 @@ namespace
   }
 }
 
+namespace
+{
+  // A single conditional variable controlling all static initializations.
+  static __gnu_cxx::__cond* static_cond;  
+
+  // using a fake type to avoid initializing a static class.
+  typedef char fake_cond_t[sizeof(__gnu_cxx::__cond)]
+  __attribute__ ((aligned(__alignof__(__gnu_cxx::__cond))));
+  fake_cond_t fake_cond;
+
+  static void init_static_cond()
+  { static_cond =  new (&fake_cond) __gnu_cxx::__cond(); }
+
+  __gnu_cxx::__cond&
+  get_static_cond()
+  {
+    static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+    __gthread_once(&once, init_static_cond);
+    return *static_cond;
+  }
+}
+
 #ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
 inline bool
 __test_and_acquire (__cxxabiv1::__guard *g)
@@ -110,34 +132,87 @@ namespace __gnu_cxx
   recursive_init_error::~recursive_init_error() throw() { }
 }
 
+//
+// Here are C++ run-time routines for guarded initiailization of static
+// variables. There are 4 scenarios under which these routines are called:
+//
+//   1. Threads not supported (__GTHREADS not defined)
+//   2. Threads are supported but not enabled at run-time.
+//   3. Threads enabled at run-time but __gthreads_* are not fully POSIX.
+//   4. Threads enabled at run-time and __gthreads_* support all POSIX threads
+//      primitives we need here.
+//
+// The old code supported scenarios 1-3 but was broken since it used a global
+// mutex for all threads and had the mutex locked during the whole duration of
+// initlization of a guarded static variable. The following created a dead-lock
+// with the old code.
+//
+//     Thread 1 acquires the global mutex.
+//     Thread 1 starts initializing static variable.
+//     Thread 1 creates thread 2 during initialization.
+//     Thread 2 attempts to acuqire mutex to initialize another variable.
+//     Thread 2 blocks since thread 1 is locking the mutex.
+//     Thread 1 waits for result from thread 2 and also blocks. A deadlock.
+//
+// The new code here can handle this situation and thus is more robust. Howere,
+// we need to use the POSIX thread conditional variable, which is not supported
+// in all platforms, notably older versions of Microsoft Windows. The gthr*.h
+// headers define a symbol __GTHREAD_HAS_COND for platforms that support POSIX
+// like conditional variables. For platforms that do not support conditional
+// variables, we need to fall back to the old code.
 namespace __cxxabiv1 
 {
   static inline int
-  recursion_push (__guard* g)
-  { return ((char *)g)[1]++; }
+  init_in_progress_flag(__guard* g)
+  { return ((char *)g)[1]; }
 
   static inline void
-  recursion_pop (__guard* g)
-  { --((char *)g)[1]; }
+  set_init_in_progress_flag(__guard* g, int v)
+  { ((char *)g)[1] = v; }
 
-  static int
-  acquire (__guard *g)
+  static inline void
+  throw_recursive_init_exception()
   {
-    if (_GLIBCXX_GUARD_TEST (g))
-      return 0;
-
-    if (recursion_push (g))
-      {
 #ifdef __EXCEPTIONS
        throw __gnu_cxx::recursive_init_error();
 #else
        // Use __builtin_trap so we don't require abort().
-       __builtin_trap ();
+       __builtin_trap();
 #endif
-      }
+  }
+
+  // acuire() is a helper function used to acquire guard if thread support is
+  // not compiled in or is compiled in but not enabled at run-time.
+  static int
+  acquire(__guard *g)
+  {
+    // Quit if the object is already initialized.
+    if (_GLIBCXX_GUARD_TEST(g))
+      return 0;
+
+    if (init_in_progress_flag(g))
+       throw_recursive_init_exception();
+
+    set_init_in_progress_flag(g, 1);
     return 1;
   }
 
+  // Simple wrapper for exception safety.
+  struct mutex_wrapper
+  {
+#ifdef __GTHREADS
+    bool unlock;
+    mutex_wrapper() : unlock(true)
+    { get_static_mutex().lock(); }
+
+    ~mutex_wrapper()
+    {
+      if (unlock)
+       static_mutex->unlock();
+    }
+#endif
+  };
+
   extern "C"
   int __cxa_guard_acquire (__guard *g) 
   {
@@ -150,28 +225,39 @@ namespace __cxxabiv1
 
     if (__gthread_active_p ())
       {
-       // Simple wrapper for exception safety.
-       struct mutex_wrapper
-       {
-         bool unlock;
-         mutex_wrapper() : unlock(true)
-         { get_static_mutex().lock(); }
-
-         ~mutex_wrapper()
-         {
-           if (unlock)
-             static_mutex->unlock();
-         }
-       };
-
        mutex_wrapper mw;
-       if (acquire (g))
+
+       while (1)       // When this loop is executing, mutex is locked.
          {
-           mw.unlock = false;
-           return 1;
-         }
+#ifdef __GTHREAD_HAS_COND
+           // The static is allready initialized.
+           if (_GLIBCXX_GUARD_TEST(g))
+             return 0; // The mutex will be unlocked via wrapper
 
-       return 0;
+           if (init_in_progress_flag(g))
+             {
+               // The guarded static is currently being initialized by
+               // another thread, so we release mutex and wait for the
+               // conditional variable. We will lock the mutex again after
+               // this.
+               get_static_cond().wait_recursive(&get_static_mutex());
+             }
+           else
+             {
+               set_init_in_progress_flag(g, 1);
+               return 1; // The mutex will be unlocked via wrapper.
+             }
+#else
+           // This provides compatibility with older systems not supporting
+           // POSIX like conditional variables.
+           if (acquire(g))
+             {
+               mw.unlock = false;
+               return 1; // The mutex still locked.
+             }
+           return 0; // The mutex will be unlocked via wrapper.
+#endif
+         }
       }
 #endif
 
@@ -181,8 +267,24 @@ namespace __cxxabiv1
   extern "C"
   void __cxa_guard_abort (__guard *g)
   {
-    recursion_pop (g);
-#ifdef __GTHREADS
+#ifdef __GTHREAD_HAS_COND
+    if (__gthread_active_p())
+      {        
+       mutex_wrapper mw;
+
+       set_init_in_progress_flag(g, 0);
+
+       // If we abort, we still need to wake up all other threads waiting for
+       // the conditional variable.
+        get_static_cond().broadcast();
+       return;
+      }        
+#endif
+
+    set_init_in_progress_flag(g, 0);
+#if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
+    // This provides compatibility with older systems not supporting POSIX like
+    // conditional variables.
     if (__gthread_active_p ())
       static_mutex->unlock();
 #endif
@@ -191,10 +293,26 @@ namespace __cxxabiv1
   extern "C"
   void __cxa_guard_release (__guard *g)
   {
-    recursion_pop (g);
+#ifdef __GTHREAD_HAS_COND
+    if (__gthread_active_p())
+      {
+       mutex_wrapper mw;
+
+       set_init_in_progress_flag(g, 0);
+       _GLIBCXX_GUARD_SET_AND_RELEASE(g);
+
+        get_static_cond().broadcast();
+       return;
+      }        
+#endif
+
+    set_init_in_progress_flag(g, 0);
     _GLIBCXX_GUARD_SET_AND_RELEASE (g);
-#ifdef __GTHREADS
-    if (__gthread_active_p ())
+
+#if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
+    // This provides compatibility with older systems not supporting POSIX like
+    // conditional variables.
+    if (__gthread_active_p())
       static_mutex->unlock();
 #endif
   }
diff --git a/libstdc++-v3/testsuite/thread/guard.cc b/libstdc++-v3/testsuite/thread/guard.cc
new file mode 100644 (file)
index 0000000..0e9e827
--- /dev/null
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2007 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* } }
+// { dg-options "-pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-darwin* alpha*-*-osf* } }
+
+#include <cstdlib>
+#include <pthread.h>
+
+// This used to deadlock with the old libstdc++ because there is only one
+// global mutex guarding initialization of statics and it is held during by
+// the initializer thread of a static until the variable is completely
+// initialized. If the initializer thread creates and waits for another thread
+// which also initializes a static variable, there will be a deadlock because
+// the first thread is holding the mutex and waiting for the second thread,
+// which is blocked when it is acquiring the mutex.
+
+int
+get_bar (void)
+{
+  return 1;
+}
+
+void*
+do_something (void *arg)
+{
+  static int bar = get_bar ();
+  return NULL;
+}
+
+int
+get_foo (void)
+{
+  int status;
+  pthread_t new_thread;
+
+  if (pthread_create (&new_thread, NULL, do_something, NULL) != 0)
+    std::abort ();
+
+  if (pthread_join (new_thread, NULL) != 0)
+    std::abort ();
+
+  return 1;
+}
+
+int
+main (int argc, char **argv)
+{
+  static int foo = get_foo ();
+  return 0;  
+}