diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b42f1799025..3ff387c17ce 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2009-05-05 Jonathan Wakely + + PR libstdc++/39909 + * include/std/mutex (__get_once_functor_lock, __get_once_mutex, + __set_once_functor_lock_ptr): Replace global lock object with local + locks on global mutex. + * src/mutex.cc (__get_once_functor_lock, __get_once_mutex, + __set_once_functor_lock_ptr): Likewise, keeping old function to + preserve ABI. + (__once_proxy): Use pointer to local lock if set, global lock + otherwise. + * config/abi/pre/gnu.ver: Add new symbols to new ABI version. + * testsuite/util/testsuite_abi.cc: Add GLIBCX_3.4.12 version. + * testsuite/30_threads/call_once/39909.cc: New. + 2009-05-03 Jan Hubicka * include/parallel/settings.h (get): Mark const. diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 57183c1a670..240e7bcf09b 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -958,6 +958,14 @@ GLIBCXX_3.4.11 { } GLIBCXX_3.4.10; +GLIBCXX_3.4.12 { + + # mutex + _ZSt27__set_once_functor_lock_ptrPSt11unique_lockISt5mutexE; + _ZSt16__get_once_mutexv; + +} GLIBCXX_3.4.11; + # Symbols in the support library (libsupc++) have their own tag. CXXABI_1.3 { diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index f26acc02f4f..c090608cb53 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -729,8 +729,11 @@ namespace std #else extern function __once_functor; - extern unique_lock& - __get_once_functor_lock(); + extern void + __set_once_functor_lock_ptr(unique_lock*); + + extern mutex& + __get_once_mutex(); #endif extern "C" void __once_proxy(); @@ -745,16 +748,16 @@ namespace std __once_callable = &__bound_functor; __once_call = &__once_call_impl; #else - unique_lock& __functor_lock = __get_once_functor_lock(); - __functor_lock.lock(); + unique_lock __functor_lock(__get_once_mutex()); __once_functor = bind(__f, __args...); + __set_once_functor_lock_ptr(&__functor_lock); #endif int __e = __gthread_once(&(__once._M_once), &__once_proxy); #ifndef _GLIBCXX_HAVE_TLS if (__functor_lock) - __functor_lock.unlock(); + __set_once_functor_lock_ptr(0); #endif if (__e) diff --git a/libstdc++-v3/src/mutex.cc b/libstdc++-v3/src/mutex.cc index e0a94892158..fcc1eb97a89 100644 --- a/libstdc++-v3/src/mutex.cc +++ b/libstdc++-v3/src/mutex.cc @@ -28,11 +28,11 @@ #ifndef _GLIBCXX_HAVE_TLS namespace { - std::mutex& - get_once_mutex() + inline std::unique_lock*& + __get_once_functor_lock_ptr() { - static std::mutex once_mutex; - return once_mutex; + static std::unique_lock* __once_functor_lock_ptr = 0; + return __once_functor_lock_ptr; } } #endif @@ -55,10 +55,25 @@ namespace std template class function; function __once_functor; + mutex& + __get_once_mutex() + { + static mutex once_mutex; + return once_mutex; + } + + // code linked against ABI 3.4.12 and later uses this + void + __set_once_functor_lock_ptr(unique_lock* __ptr) + { + __get_once_functor_lock_ptr() = __ptr; + } + + // unsafe - retained for compatibility with ABI 3.4.11 unique_lock& __get_once_functor_lock() { - static unique_lock once_functor_lock(get_once_mutex(), defer_lock); + static unique_lock once_functor_lock(__get_once_mutex(), defer_lock); return once_functor_lock; } #endif @@ -69,7 +84,14 @@ namespace std { #ifndef _GLIBCXX_HAVE_TLS function __once_call = std::move(__once_functor); - __get_once_functor_lock().unlock(); + if (unique_lock* __lock = __get_once_functor_lock_ptr()) + { + // caller is using new ABI and provided lock ptr + __get_once_functor_lock_ptr() = 0; + __lock->unlock(); + } + else + __get_once_functor_lock().unlock(); // global lock #endif __once_call(); } diff --git a/libstdc++-v3/testsuite/30_threads/call_once/39909.cc b/libstdc++-v3/testsuite/30_threads/call_once/39909.cc new file mode 100644 index 00000000000..aa125919bf8 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/call_once/39909.cc @@ -0,0 +1,56 @@ +// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } } +// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } + +// Copyright (C) 2009 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 3, 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 COPYING3. If not see +// . + + +#include +#include +#include + +std::once_flag flag; +int value = 0; + +struct Inc { void operator()() const { ++value; } }; + +struct Func +{ + void operator()() const + { + Inc inc; + for (int i = 0; i < 10000; ++i) + std::call_once(flag, inc); + } +}; + +int main() +{ + Func f; + std::thread t1(f); + std::thread t2(f); + std::thread t3(f); + t1.join(); + t2.join(); + t3.join(); + VERIFY( value == 1 ); + return 0; +} diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc index e9df9f80299..ca1bb912ce5 100644 --- a/libstdc++-v3/testsuite/util/testsuite_abi.cc +++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc @@ -183,6 +183,7 @@ check_version(symbol& test, bool added) known_versions.push_back("GLIBCXX_3.4.9"); known_versions.push_back("GLIBCXX_3.4.10"); known_versions.push_back("GLIBCXX_3.4.11"); + known_versions.push_back("GLIBCXX_3.4.12"); known_versions.push_back("GLIBCXX_LDBL_3.4"); known_versions.push_back("GLIBCXX_LDBL_3.4.7"); known_versions.push_back("GLIBCXX_LDBL_3.4.10");