This is GCC Bugzilla
This is GCC Bugzilla Version 2.20+
View Bug Activity | Format For Printing | Clone This Bug
I'm entering this bug to track: http://gcc.gnu.org/ml/libstdc++/2009-04/msg00009.html The following program fails using gcc configured --disable-tls #include <mutex> #include <thread> #include <assert.h> 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(); assert( value == 1 ); return 0; } Multiple threads try to call unique_lock<mutex>::lock() on the same object simultaneously, after the first one acquires the lock the subsequent threads will fail due to this check in unique_lock::lock() else if (_M_owns) __throw_system_error(int(errc::resource_deadlock_would_occur)); The unhandled exceptions terminate the program. The obvious fix is to stop using a single, global lock object shared between all threads, and use a different lock object in each thread's stack, sharing a global mutex. Concurrent operations on a single mutex are safe, but not on a single lock. That fix requires an ABI change, since __get_once_functor_lock is exported. An alternative would be to replicate the code used when TLS is available, but using pthread_getspecific / pthread_setspecific instead.
Just in case Chris wants to help with this.
Created an attachment (id=17707) [edit] fix call_once without breaking ABI Fix call_once to not use the global lock object, but retain the global for ABI reasons. __once_proxy detects if it was called by new code that provides the address of a local lock object, or by old code that uses the global lock. Without that check any uses of call_once inlined in old objects will be liable to deadlock (because the global lock won't be unlocked before invoking the functor) or segfaults (if the pointer is null when __once_proxy uses it). Multiple concurrent calls to call_once from old object code will still terminate, but it should be OK for new object code to use call_once freely, and even for exactly one thread using the old call_once to run concurrently with new code using call_once (because there would only be the single thread using the global lock object.) This patch adds the new symbols to the GLIBCXX_3.4.11 version but they should be in a new 3.4.12 block - I don't know what I need to do for that. Tested x86_64/linux --disable-tls
Thanks Jon, for following up about this. Let's try to close the issue during the next days... About 3.4.12, it's just matter of manually editing gnu.ver, adding the block + manually adding GLIBCXX_3.4.12 to testsuite_abi.cc. Then regression testing should still succeed after the changes.
Created an attachment (id=17709) [edit] use GLIBCXX_3.4.12 version for new symbols same patch again, with the new symbols using a new version and testsuite changes included
(In reply to comment #4) > same patch again, with the new symbols using a new version and testsuite > changes included passes all regression tests both with and without tls
Jon, patch looks generally good to me, can you please send it to the mailing list for higher visibility? Then we can commit it and close this annoying issue once and for all ;)
Subject: Bug 39909 Author: redi Date: Tue May 5 21:32:38 2009 New Revision: 147137 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=147137 Log: 2009-05-05 Jonathan Wakely <jwakely.gcc@gmail.com> 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. Added: trunk/libstdc++-v3/testsuite/30_threads/call_once/39909.cc Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/config/abi/pre/gnu.ver trunk/libstdc++-v3/include/std/mutex trunk/libstdc++-v3/src/mutex.cc trunk/libstdc++-v3/testsuite/util/testsuite_abi.cc
Subject: Bug 39909 Author: redi Date: Tue May 5 21:44:27 2009 New Revision: 147138 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=147138 Log: 2009-05-05 Jonathan Wakely <jwakely.gcc@gmail.com> 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. Added: branches/gcc-4_4-branch/libstdc++-v3/testsuite/30_threads/call_once/39909.cc Modified: branches/gcc-4_4-branch/libstdc++-v3/ChangeLog branches/gcc-4_4-branch/libstdc++-v3/config/abi/pre/gnu.ver branches/gcc-4_4-branch/libstdc++-v3/include/std/mutex branches/gcc-4_4-branch/libstdc++-v3/src/mutex.cc branches/gcc-4_4-branch/libstdc++-v3/testsuite/util/testsuite_abi.cc
Fixed for 4.5.0 and 4.4.1