This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

std::call_once without TLS


when _GLIBCXX_HAVE_TLS is not defined, call_once uses a global lock to
protect the global __once_functor.  All threads manipulate the same
static lock object. These means that two threads calling call_once
(even on different once_flags) will both try to call
unique_lock::lock() on the same object.  Isn't that unsafe?  Separate
threads should use different unique_lock instances that share a mutex.

Am I missing something, or would a change like this (not tested or
even compiled) be better, and also ensure the mutex doesn't stay
locked if the std::function::operator= throws?

Index: include/std/mutex
===================================================================
--- include/std/mutex   (revision 145468)
+++ include/std/mutex   (working copy)
@@ -733,9 +733,10 @@ namespace std
     }
 #else
   extern function<void()> __once_functor;
+  extern unique_lock<mutex>* __once_functor_lock;

-  extern unique_lock<mutex>&
-  __get_once_functor_lock();
+  extern mutex&
+  __get_once_mutex();
 #endif

   extern "C" void __once_proxy();
@@ -750,18 +751,13 @@ namespace std
       __once_callable = &__bound_functor;
       __once_call = &__once_call_impl<decltype(__bound_functor)>;
 #else
-      unique_lock<mutex>& __functor_lock = __get_once_functor_lock();
-      __functor_lock.lock();
+      unique_lock<mutex> __functor_lock(__get_once_mutex());
       __once_functor = bind(__f, __args...);
+      __once_functor_lock = &__functor_lock;
 #endif

       int __e = __gthread_once(&(__once._M_once), &__once_proxy);

-#ifndef _GLIBCXX_HAVE_TLS
-      if (__functor_lock)
-       __functor_lock.unlock();
-#endif
-
       if (__e)
        __throw_system_error(__e);
     }
Index: src/mutex.cc
===================================================================
--- src/mutex.cc        (revision 145468)
+++ src/mutex.cc        (working copy)
@@ -30,18 +30,6 @@
 #include <mutex>

 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
-#ifndef _GLIBCXX_HAVE_TLS
-namespace
-{
-  std::mutex&
-  get_once_mutex()
-  {
-    static std::mutex once_mutex;
-    return once_mutex;
-  }
-}
-#endif
-
 namespace std
 {
   const defer_lock_t defer_lock = defer_lock_t();
@@ -60,11 +48,13 @@ namespace std
   template class function<void()>;
   function<void()> __once_functor;

-  unique_lock<mutex>&
-  __get_once_functor_lock()
+  unique_lock<mutex>* __once_functor_lock;
+
+  mutex&
+  __get_once_mutex()
   {
-    static unique_lock<mutex> once_functor_lock(get_once_mutex(), defer_lock);
-    return once_functor_lock;
+    static mutex once_mutex;
+    return once_mutex;
   }
 #endif

@@ -74,7 +64,7 @@ namespace std
     {
 #ifndef _GLIBCXX_HAVE_TLS
       function<void()> __once_call = std::move(__once_functor);
-      __get_once_functor_lock().unlock();
+      __once_functor_lock->unlock();
 #endif
       __once_call();
     }
@@ -60,11 +48,13 @@ namespace std
   template class function<void()>;
   function<void()> __once_functor;

-  unique_lock<mutex>&
-  __get_once_functor_lock()
+  unique_lock<mutex>* __once_functor_lock;
+
+  mutex&
+  __get_once_mutex()
   {
-    static unique_lock<mutex> once_functor_lock(get_once_mutex(), defer_lock);
-    return once_functor_lock;
+    static mutex once_mutex;
+    return once_mutex;
   }
 #endif

@@ -74,7 +64,7 @@ namespace std
     {
 #ifndef _GLIBCXX_HAVE_TLS
       function<void()> __once_call = std::move(__once_functor);
-      __get_once_functor_lock().unlock();
+      __once_functor_lock->unlock();
 #endif
       __once_call();
     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]