Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug
Bug#: 39909
Product:  
Component:  
Status: RESOLVED
Resolution: FIXED
Assigned To: Not yet assigned to anyone <unassigned@gcc.gnu.org>
Host:
Reported against  
Priority:  
Severity:  
Target Milestone:  
 
 
Target:
Reporter: Jonathan Wakely <jwakely.gcc@gmail.com>
Add CC:
CC:
Remove selected CCs
Build:
URL:
Summary:
Keywords:
Known to work:
Known to fail:

Attachment Description Type Created Size Actions
once5.patch fix call_once without breaking ABI patch 2009-04-26 17:40 1021 bytes Edit | Diff
once6.patch use GLIBCXX_3.4.12 version for new symbols patch 2009-04-26 18:06 1.90 KB Edit | Diff
Create a New Attachment (proposed patch, testcase, etc.) View All

Bug 39909 depends on: Show dependency tree
Show dependency graph
Bug 39909 blocks:

Additional Comments:






View Bug Activity   |   Format For Printing   |   Clone This Bug


Description:   Last confirmed: 2009-04-26 17:53 Opened: 2009-04-26 13:51
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.

------- Comment #1 From Paolo Carlini 2009-04-26 14:28 -------
Just in case Chris wants to help with this.

------- Comment #2 From Jonathan Wakely 2009-04-26 17:40 -------
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

------- Comment #3 From Paolo Carlini 2009-04-26 17:53 -------
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.

------- Comment #4 From Jonathan Wakely 2009-04-26 18:06 -------
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

------- Comment #5 From Jonathan Wakely 2009-04-26 21:39 -------
(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

------- Comment #6 From Paolo Carlini 2009-04-29 09:17 -------
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 ;)

------- Comment #7 From Jonathan Wakely 2009-05-05 21:33 -------
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

------- Comment #8 From Jonathan Wakely 2009-05-05 21:44 -------
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

------- Comment #9 From Jonathan Wakely 2009-05-05 22:14 -------
Fixed for 4.5.0 and 4.4.1

Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug