Commit afd82ef5 by Doug Kwan Committed by Jason Merrill

gthr-posix.h (__gthread_cond_broadcast, [...]): Add to extend interface for…

gthr-posix.h (__gthread_cond_broadcast, [...]): Add to extend interface for POSIX conditional variables.

2007-09-13  Doug Kwan  <dougkwan@google.com>

        * 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.

From-SVN: r129030
parent 90e965bb
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> 2007-10-04 Geoffrey Keating <geoffk@apple.com>
* cgraphunit.c (cgraph_build_static_cdtor): Don't set * cgraphunit.c (cgraph_build_static_cdtor): Don't set
...@@ -47,6 +47,11 @@ typedef pthread_key_t __gthread_key_t; ...@@ -47,6 +47,11 @@ typedef pthread_key_t __gthread_key_t;
typedef pthread_once_t __gthread_once_t; typedef pthread_once_t __gthread_once_t;
typedef pthread_mutex_t __gthread_mutex_t; typedef pthread_mutex_t __gthread_mutex_t;
typedef pthread_mutex_t __gthread_recursive_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_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
...@@ -57,6 +62,7 @@ typedef pthread_mutex_t __gthread_recursive_mutex_t; ...@@ -57,6 +62,7 @@ typedef pthread_mutex_t __gthread_recursive_mutex_t;
#else #else
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
#endif #endif
#define __GTHREAD_COND_INIT PTHREAD_COND_INITIALIZER
#if SUPPORTS_WEAK && GTHREAD_USE_WEAK #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
# ifndef __gthrw_pragma # ifndef __gthrw_pragma
...@@ -88,6 +94,8 @@ __gthrw3(pthread_mutex_lock) ...@@ -88,6 +94,8 @@ __gthrw3(pthread_mutex_lock)
__gthrw3(pthread_mutex_trylock) __gthrw3(pthread_mutex_trylock)
__gthrw3(pthread_mutex_unlock) __gthrw3(pthread_mutex_unlock)
__gthrw3(pthread_mutex_init) __gthrw3(pthread_mutex_init)
__gthrw3(pthread_cond_broadcast)
__gthrw3(pthread_cond_wait)
#else #else
__gthrw(pthread_once) __gthrw(pthread_once)
__gthrw(pthread_getspecific) __gthrw(pthread_getspecific)
...@@ -98,6 +106,8 @@ __gthrw(pthread_mutex_lock) ...@@ -98,6 +106,8 @@ __gthrw(pthread_mutex_lock)
__gthrw(pthread_mutex_trylock) __gthrw(pthread_mutex_trylock)
__gthrw(pthread_mutex_unlock) __gthrw(pthread_mutex_unlock)
__gthrw(pthread_mutex_init) __gthrw(pthread_mutex_init)
__gthrw(pthread_cond_broadcast)
__gthrw(pthread_cond_wait)
#endif #endif
__gthrw(pthread_key_create) __gthrw(pthread_key_create)
...@@ -110,20 +120,16 @@ __gthrw(pthread_mutexattr_destroy) ...@@ -110,20 +120,16 @@ __gthrw(pthread_mutexattr_destroy)
#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK) #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
/* Objective-C. */ /* Objective-C. */
#if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_) #if defined(__osf__) && defined(_PTHREAD_USE_MANGLED_NAMES_)
__gthrw3(pthread_cond_broadcast)
__gthrw3(pthread_cond_destroy) __gthrw3(pthread_cond_destroy)
__gthrw3(pthread_cond_init) __gthrw3(pthread_cond_init)
__gthrw3(pthread_cond_signal) __gthrw3(pthread_cond_signal)
__gthrw3(pthread_cond_wait)
__gthrw3(pthread_exit) __gthrw3(pthread_exit)
__gthrw3(pthread_mutex_destroy) __gthrw3(pthread_mutex_destroy)
__gthrw3(pthread_self) __gthrw3(pthread_self)
#else #else
__gthrw(pthread_cond_broadcast)
__gthrw(pthread_cond_destroy) __gthrw(pthread_cond_destroy)
__gthrw(pthread_cond_init) __gthrw(pthread_cond_init)
__gthrw(pthread_cond_signal) __gthrw(pthread_cond_signal)
__gthrw(pthread_cond_wait)
__gthrw(pthread_exit) __gthrw(pthread_exit)
__gthrw(pthread_mutex_destroy) __gthrw(pthread_mutex_destroy)
__gthrw(pthread_self) __gthrw(pthread_self)
...@@ -737,6 +743,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) ...@@ -737,6 +743,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
return __gthread_mutex_unlock (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 /* _LIBOBJC */
#endif /* ! GCC_GTHR_POSIX_H */ #endif /* ! GCC_GTHR_POSIX_H */
...@@ -45,6 +45,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -45,6 +45,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
typedef pthread_key_t __gthread_key_t; typedef pthread_key_t __gthread_key_t;
typedef pthread_once_t __gthread_once_t; typedef pthread_once_t __gthread_once_t;
typedef pthread_mutex_t __gthread_mutex_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 { typedef struct {
long depth; long depth;
...@@ -55,6 +60,7 @@ typedef struct { ...@@ -55,6 +60,7 @@ typedef struct {
#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER #define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT #define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
#define __GTHREAD_COND_INIT PTHREAD_COND_INITIALIZER
#if SUPPORTS_WEAK && GTHREAD_USE_WEAK #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
# define __gthrw(name) \ # define __gthrw(name) \
...@@ -81,14 +87,14 @@ __gthrw(pthread_mutexattr_init) ...@@ -81,14 +87,14 @@ __gthrw(pthread_mutexattr_init)
__gthrw(pthread_mutexattr_destroy) __gthrw(pthread_mutexattr_destroy)
__gthrw(pthread_mutex_init) __gthrw(pthread_mutex_init)
__gthrw(pthread_cond_broadcast)
__gthrw(pthread_cond_wait)
#if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK) #if defined(_LIBOBJC) || defined(_LIBOBJC_WEAK)
/* Objective-C. */ /* Objective-C. */
__gthrw(pthread_cond_broadcast)
__gthrw(pthread_cond_destroy) __gthrw(pthread_cond_destroy)
__gthrw(pthread_cond_init) __gthrw(pthread_cond_init)
__gthrw(pthread_cond_signal) __gthrw(pthread_cond_signal)
__gthrw(pthread_cond_wait)
__gthrw(pthread_exit) __gthrw(pthread_exit)
__gthrw(pthread_mutex_destroy) __gthrw(pthread_mutex_destroy)
#ifdef _POSIX_PRIORITY_SCHEDULING #ifdef _POSIX_PRIORITY_SCHEDULING
...@@ -719,6 +725,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) ...@@ -719,6 +725,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
return 0; 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 /* _LIBOBJC */
#endif /* ! GCC_GTHR_POSIX_H */ #endif /* ! GCC_GTHR_POSIX_H */
...@@ -251,6 +251,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) ...@@ -251,6 +251,25 @@ __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
return __gthread_mutex_unlock (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 */ #endif /* _LIBOBJC */
#undef UNUSED #undef UNUSED
......
...@@ -81,6 +81,24 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -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_trylock (__gthread_recursive_mutex_t *mutex);
int __gthread_recursive_mutex_unlock (__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 All functions returning int should return zero on success or the error
number. If the operation is not supported, -1 is returned. number. If the operation is not supported, -1 is returned.
......
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> 2007-10-04 Paolo Carlini <pcarlini@suse.de>
* testsuite/23_containers/vector/requirements/dr438/assign_neg.cc: * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc:
......
...@@ -81,6 +81,22 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) ...@@ -81,6 +81,22 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
{ return "__gnu_cxx::__concurrence_unlock_error"; } { 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. // Substitute for concurrence_error object in the case of -fno-exceptions.
inline void inline void
__throw_concurrence_lock_error() __throw_concurrence_lock_error()
...@@ -102,6 +118,28 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) ...@@ -102,6 +118,28 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
#endif #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 class __mutex
{ {
private: private:
...@@ -147,6 +185,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) ...@@ -147,6 +185,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
} }
#endif #endif
} }
__gthread_mutex_t* gthread_mutex(void)
{ return &_M_mutex; }
}; };
class __recursive_mutex class __recursive_mutex
...@@ -194,6 +235,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) ...@@ -194,6 +235,9 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
} }
#endif #endif
} }
__gthread_recursive_mutex_t* gthread_recursive_mutex(void)
{ return &_M_mutex; }
}; };
/// @brief Scoped lock idiom. /// @brief Scoped lock idiom.
...@@ -218,6 +262,66 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) ...@@ -218,6 +262,66 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
{ _M_device.unlock(); } { _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 _GLIBCXX_END_NAMESPACE
#endif #endif
...@@ -62,6 +62,28 @@ namespace ...@@ -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 #ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
inline bool inline bool
__test_and_acquire (__cxxabiv1::__guard *g) __test_and_acquire (__cxxabiv1::__guard *g)
...@@ -110,34 +132,87 @@ namespace __gnu_cxx ...@@ -110,34 +132,87 @@ namespace __gnu_cxx
recursive_init_error::~recursive_init_error() throw() { } 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 namespace __cxxabiv1
{ {
static inline int static inline int
recursion_push (__guard* g) init_in_progress_flag(__guard* g)
{ return ((char *)g)[1]++; } { return ((char *)g)[1]; }
static inline void static inline void
recursion_pop (__guard* g) set_init_in_progress_flag(__guard* g, int v)
{ --((char *)g)[1]; } { ((char *)g)[1] = v; }
static int static inline void
acquire (__guard *g) throw_recursive_init_exception()
{ {
if (_GLIBCXX_GUARD_TEST (g))
return 0;
if (recursion_push (g))
{
#ifdef __EXCEPTIONS #ifdef __EXCEPTIONS
throw __gnu_cxx::recursive_init_error(); throw __gnu_cxx::recursive_init_error();
#else #else
// Use __builtin_trap so we don't require abort(). // Use __builtin_trap so we don't require abort().
__builtin_trap (); __builtin_trap();
#endif #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; 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" extern "C"
int __cxa_guard_acquire (__guard *g) int __cxa_guard_acquire (__guard *g)
{ {
...@@ -150,28 +225,39 @@ namespace __cxxabiv1 ...@@ -150,28 +225,39 @@ namespace __cxxabiv1
if (__gthread_active_p ()) 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; mutex_wrapper mw;
if (acquire (g))
while (1) // When this loop is executing, mutex is locked.
{ {
mw.unlock = false; #ifdef __GTHREAD_HAS_COND
return 1; // 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 #endif
...@@ -181,8 +267,24 @@ namespace __cxxabiv1 ...@@ -181,8 +267,24 @@ namespace __cxxabiv1
extern "C" extern "C"
void __cxa_guard_abort (__guard *g) void __cxa_guard_abort (__guard *g)
{ {
recursion_pop (g); #ifdef __GTHREAD_HAS_COND
#ifdef __GTHREADS 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 ()) if (__gthread_active_p ())
static_mutex->unlock(); static_mutex->unlock();
#endif #endif
...@@ -191,10 +293,26 @@ namespace __cxxabiv1 ...@@ -191,10 +293,26 @@ namespace __cxxabiv1
extern "C" extern "C"
void __cxa_guard_release (__guard *g) 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); _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(); static_mutex->unlock();
#endif #endif
} }
......
//
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment