Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r82513 - in trunk: boost/thread boost/thread/detail boost/thread/pthread libs/thread/example libs/thread/src/pthread libs/thread/test libs/thread/test/sync/mutual_exclusion/once/call_once
From: vicente.botet_at_[hidden]
Date: 2013-01-16 16:50:00


Author: viboes
Date: 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
New Revision: 82513
URL: http://svn.boost.org/trac/boost/changeset/82513

Log:
Thread: Added atomic once implementation + variadi call_once for pthread
Added:
   trunk/boost/thread/pthread/once_atomic.hpp (contents, props changed)
   trunk/libs/thread/src/pthread/once_atomic.cpp (contents, props changed)
   trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp (contents, props changed)
Text files modified:
   trunk/boost/thread/detail/config.hpp | 25 ++++
   trunk/boost/thread/once.hpp | 7 +
   trunk/boost/thread/pthread/once.hpp | 239 ++++++++++++++++++++++++++++++---------
   trunk/libs/thread/example/once.cpp | 7
   trunk/libs/thread/src/pthread/once.cpp | 11 +
   trunk/libs/thread/src/pthread/thread.cpp | 1
   trunk/libs/thread/test/Jamfile.v2 | 10 +
   7 files changed, 237 insertions(+), 63 deletions(-)

Modified: trunk/boost/thread/detail/config.hpp
==============================================================================
--- trunk/boost/thread/detail/config.hpp (original)
+++ trunk/boost/thread/detail/config.hpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -109,6 +109,20 @@
 #define BOOST_THREAD_USES_CHRONO
 #endif
 
+#if ! defined BOOST_THREAD_DONT_USE_ATOMIC \
+ && ! defined BOOST_THREAD_USES_ATOMIC
+#define BOOST_THREAD_USES_ATOMIC
+//#define BOOST_THREAD_DONT_USE_ATOMIC
+#endif
+
+#if defined BOOST_THREAD_USES_ATOMIC
+// Andrey Semashev
+#define BOOST_THREAD_ONCE_ATOMIC
+#else
+//#elif ! defined BOOST_NO_CXX11_THREAD_LOCAL && ! defined BOOST_NO_THREAD_LOCAL && ! defined BOOST_THREAD_NO_UINT32_PSEUDO_ATOMIC
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html#Appendix
+#define BOOST_THREAD_ONCE_FAST_EPOCH
+#endif
 #if BOOST_THREAD_VERSION==2
 
 // PROVIDE_PROMISE_LAZY
@@ -131,7 +145,7 @@
 // fixme BOOST_THREAD_PROVIDES_ONCE_CXX11 doesn't works when thread.cpp is compiled BOOST_THREAD_VERSION 3
 #if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \
  && ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11
-#define BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11
+#define BOOST_THREAD_PROVIDES_ONCE_CXX11
 #endif
 
 // THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
@@ -277,6 +291,15 @@
 #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
 #endif
 
+// For C++11 call_once interface the compiler MUST support constexpr.
+// Otherwise once_flag would be initialized during dynamic initialization stage, which is not thread-safe.
+#if defined(BOOST_THREAD_PROVIDES_ONCE_CXX11)
+#if defined(BOOST_NO_CXX11_CONSTEXPR)
+#undef BOOST_THREAD_PROVIDES_ONCE_CXX11
+#endif
+#endif
+
+
 // BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52
 // BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
 #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0

Modified: trunk/boost/thread/once.hpp
==============================================================================
--- trunk/boost/thread/once.hpp (original)
+++ trunk/boost/thread/once.hpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -9,11 +9,18 @@
 // accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt)
 
+#include <boost/thread/detail/config.hpp>
 #include <boost/thread/detail/platform.hpp>
 #if defined(BOOST_THREAD_PLATFORM_WIN32)
 #include <boost/thread/win32/once.hpp>
 #elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
+#if defined BOOST_THREAD_ONCE_FAST_EPOCH
 #include <boost/thread/pthread/once.hpp>
+#elif defined BOOST_THREAD_ONCE_ATOMIC
+#include <boost/thread/pthread/once_atomic.hpp>
+#else
+#error "Once Not Implemented"
+#endif
 #else
 #error "Boost threads unavailable on this platform"
 #endif

Modified: trunk/boost/thread/pthread/once.hpp
==============================================================================
--- trunk/boost/thread/pthread/once.hpp (original)
+++ trunk/boost/thread/pthread/once.hpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -11,6 +11,7 @@
 // http://www.boost.org/LICENSE_1_0.txt)
 
 #include <boost/thread/detail/config.hpp>
+#include <boost/thread/detail/move.hpp>
 
 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
 #include <boost/thread/detail/delete.hpp>
@@ -26,21 +27,35 @@
 namespace boost
 {
 
-#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
+ struct once_flag;
+
+ #define BOOST_ONCE_INITIAL_FLAG_VALUE 0
 
   namespace thread_detail
   {
-//#ifdef SIG_ATOMIC_MAX
-// typedef sig_atomic_t uintmax_atomic_t;
-// #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C SIG_ATOMIC_MAX
-//#else
- typedef unsigned long uintmax_atomic_t;
- #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##ul
+ typedef boost::uint32_t uintmax_atomic_t;
+ #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u
     #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0)
-//#endif
+
+ inline bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ inline void commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ inline void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
   }
 
 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
+#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
+ template<typename Function, class ...ArgTypes>
+ inline void call_once(once_flag& flag, Function f, BOOST_THREAD_RV_REF(ArgTypes)... args);
+#else
+ template<typename Function>
+ inline void call_once(once_flag& flag, Function f);
+ template<typename Function, typename T1>
+ inline void call_once(once_flag& flag, Function f, T1 p1);
+ template<typename Function, typename T1, typename T2>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
+ template<typename Function, typename T1, typename T2, typename T3>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
+#endif
 
   struct once_flag
   {
@@ -50,11 +65,30 @@
       {}
   private:
       volatile thread_detail::uintmax_atomic_t epoch;
+
+#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
+ template<typename Function, class ...ArgTypes>
+ friend void call_once(once_flag& flag, Function f, BOOST_THREAD_RV_REF(ArgTypes)... args);
+#else
       template<typename Function>
- friend
- void call_once(once_flag& flag,Function f);
+ friend void call_once(once_flag& flag, Function f);
+ template<typename Function, typename T1>
+ friend void call_once(once_flag& flag, Function f, T1 p1);
+ template<typename Function, typename T1, typename T2>
+ friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2);
+ template<typename Function, typename T1, typename T2, typename T3>
+ friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3);
+
+ friend inline bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ friend inline void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ friend inline void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
+
+#endif
+
   };
 
+#define BOOST_ONCE_INIT once_flag()
+
 #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
 
     struct once_flag
@@ -65,59 +99,156 @@
 #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
 #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
 
- namespace detail
+ namespace thread_detail
     {
- BOOST_THREAD_DECL thread_detail::uintmax_atomic_t& get_once_per_thread_epoch();
- BOOST_THREAD_DECL extern thread_detail::uintmax_atomic_t once_global_epoch;
+ BOOST_THREAD_DECL uintmax_atomic_t& get_once_per_thread_epoch();
+ BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch;
         BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
         BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
     }
 
     // Based on Mike Burrows fast_pthread_once algorithm as described in
     // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
- template<typename Function>
- void call_once(once_flag& flag,Function f)
+
+ namespace thread_detail
+ {
+ static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
+ static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
+ inline bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT
+ {
+ thread_detail::uintmax_atomic_t const epoch=flag.epoch;
+ thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch();
+ if(epoch<this_thread_epoch)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+
+ while(flag.epoch<=being_initialized)
+ {
+ if(flag.epoch==uninitialized_flag)
+ {
+ flag.epoch=being_initialized;
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+ inline void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT
     {
- static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
- static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1;
- thread_detail::uintmax_atomic_t const epoch=flag.epoch;
- thread_detail::uintmax_atomic_t& this_thread_epoch=detail::get_once_per_thread_epoch();
-
- if(epoch<this_thread_epoch)
- {
- pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
-
- while(flag.epoch<=being_initialized)
- {
- if(flag.epoch==uninitialized_flag)
- {
- flag.epoch=being_initialized;
- BOOST_TRY
- {
- pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
- f();
- }
- BOOST_CATCH (...)
- {
- flag.epoch=uninitialized_flag;
- BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
- BOOST_RETHROW
- }
- BOOST_CATCH_END
- flag.epoch=--detail::once_global_epoch;
- BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
- }
- else
- {
- while(flag.epoch==being_initialized)
- {
- BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
- }
- }
- }
- this_thread_epoch=detail::once_global_epoch;
- }
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+ flag.epoch=uninitialized_flag;
+ }
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
     }
+ inline void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT
+ {
+ {
+ pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex);
+ flag.epoch=--thread_detail::once_global_epoch;
+ }
+ BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv));
+ }
+ }
+#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
+
+ template<typename Function, class ...ArgTypes>
+ inline void call_once(once_flag& flag, Function f, BOOST_THREAD_RV_REF(ArgTypes)... args)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(boost::forward<ArgTypes>(args)...);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+#else
+ template<typename Function>
+ inline void call_once(once_flag& flag, Function f)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f();
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1>
+ inline void call_once(once_flag& flag, Function f, T1 p1)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1, typename T2>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1, p2);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1, typename T2, typename T3>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1, p2, p3);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+#endif
+
 }
 
 #include <boost/config/abi_suffix.hpp>

Added: trunk/boost/thread/pthread/once_atomic.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/pthread/once_atomic.hpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -0,0 +1,171 @@
+#ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
+#define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
+
+// once.hpp
+//
+// (C) Copyright 2013 Andrey Semashev
+// (C) Copyright 2013 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/thread/detail/move.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+
+#include <boost/config/abi_prefix.hpp>
+
+namespace boost
+{
+
+ struct once_flag;
+
+ namespace thread_detail
+ {
+ BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ }
+
+#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
+
+ struct once_flag
+ {
+ BOOST_THREAD_NO_COPYABLE(once_flag)
+ BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0)
+ {
+ }
+
+ private:
+ #if defined(__GNUC__)
+ __attribute__((may_alias))
+ #endif
+ uintmax_t storage;
+
+ friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
+ };
+
+#define BOOST_ONCE_INIT boost::once_flag()
+
+#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
+ struct once_flag
+ {
+ #if defined(__GNUC__)
+ __attribute__((may_alias))
+ #endif
+ uintmax_t storage;
+ };
+
+ #define BOOST_ONCE_INIT {0}
+
+#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
+
+#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
+
+ template<typename Function, class ...ArgTypes>
+ inline void call_once(once_flag& flag, Function f, BOOST_THREAD_RV_REF(ArgTypes)... args)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(boost::forward<ArgTypes>(args)...);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+#else
+ template<typename Function>
+ inline void call_once(once_flag& flag, Function f)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f();
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1>
+ inline void call_once(once_flag& flag, Function f, T1 p1)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1, typename T2>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1, p2);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+ template<typename Function, typename T1, typename T2, typename T3>
+ inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
+ {
+ if (thread_detail::enter_once_region(flag))
+ {
+ BOOST_TRY
+ {
+ f(p1, p2, p3);
+ }
+ BOOST_CATCH (...)
+ {
+ thread_detail::rollback_once_region(flag);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ thread_detail::commit_once_region(flag);
+ }
+ }
+
+#endif
+}
+
+#include <boost/config/abi_suffix.hpp>
+
+#endif
+

Modified: trunk/libs/thread/example/once.cpp
==============================================================================
--- trunk/libs/thread/example/once.cpp (original)
+++ trunk/libs/thread/example/once.cpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -12,10 +12,11 @@
 
 int value=0;
 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
-boost::once_flag once;
+static boost::once_flag once;
+//static boost::once_flag once2 = BOOST_ONCE_INIT;
 #else
-boost::once_flag once = BOOST_ONCE_INIT;
-boost::once_flag once2 = once;
+static boost::once_flag once = BOOST_ONCE_INIT;
+//static boost::once_flag once2 = once;
 #endif
 
 void init()

Modified: trunk/libs/thread/src/pthread/once.cpp
==============================================================================
--- trunk/libs/thread/src/pthread/once.cpp (original)
+++ trunk/libs/thread/src/pthread/once.cpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -3,6 +3,10 @@
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
+#include <boost/thread/detail/config.hpp>
+#ifdef BOOST_THREAD_ONCE_ATOMIC
+#include "./once_atomic.cpp"
+#else
 #define __STDC_CONSTANT_MACROS
 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
 #include <boost/thread/once.hpp>
@@ -13,9 +17,9 @@
 
 namespace boost
 {
- namespace detail
+ namespace thread_detail
     {
- BOOST_THREAD_DECL thread_detail::uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
+ BOOST_THREAD_DECL uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
         BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
         BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
 
@@ -56,7 +60,7 @@
 #endif
         }
 
- thread_detail::uintmax_atomic_t& get_once_per_thread_epoch()
+ uintmax_atomic_t& get_once_per_thread_epoch()
         {
             BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
             void* data=pthread_getspecific(epoch_tss_key);
@@ -71,3 +75,4 @@
     }
 
 }
+#endif //

Added: trunk/libs/thread/src/pthread/once_atomic.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/src/pthread/once_atomic.cpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -0,0 +1,107 @@
+// (C) Copyright 2013 Andrey Semashev
+// (C) Copyright 2013 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#define __STDC_CONSTANT_MACROS
+#include <boost/thread/detail/config.hpp>
+#include <boost/thread/once.hpp>
+#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/atomic.hpp>
+#include <boost/memory_order.hpp>
+#include <pthread.h>
+
+namespace boost
+{
+ namespace thread_detail
+ {
+
+ enum flag_states
+ {
+ uninitialized, in_progress, initialized
+ };
+
+#if BOOST_ATOMIC_INT_LOCK_FREE == 2
+ typedef unsigned int atomic_int_type;
+#elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2
+ typedef unsigned short atomic_int_type;
+#elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2
+ typedef unsigned char atomic_int_type;
+#elif BOOST_ATOMIC_LONG_LOCK_FREE == 2
+ typedef unsigned long atomic_int_type;
+#elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2
+ typedef ulong_long_type atomic_int_type;
+#else
+ // All tested integer types are not atomic, the spinlock pool will be used
+ typedef unsigned int atomic_int_type;
+#endif
+
+ typedef boost::atomic<atomic_int_type> atomic_type
+ //#if defined(__GNUC__)
+ // __attribute__((may_alias))
+ //#endif
+ ;
+ BOOST_STATIC_ASSERT_MSG(sizeof(once_flag) >= sizeof(atomic_type), "Boost.Thread: unsupported platform");
+
+ static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER;
+
+ BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT
+ {
+ atomic_type& f = reinterpret_cast< atomic_type& >(flag.storage);
+ if (f.load(memory_order_acquire) != initialized)
+ {
+ pthread::pthread_mutex_scoped_lock lk(&once_mutex);
+ if (f.load(memory_order_acquire) != initialized)
+ {
+ while (true)
+ {
+ atomic_int_type expected = uninitialized;
+ if (f.compare_exchange_strong(expected, in_progress, memory_order_acq_rel, memory_order_acquire))
+ {
+ // We have set the flag to in_progress
+ return true;
+ }
+ else if (expected == initialized)
+ {
+ // Another thread managed to complete the initialization
+ return false;
+ }
+ else
+ {
+ // Wait until the initialization is complete
+ //pthread::pthread_mutex_scoped_lock lk(&once_mutex);
+ BOOST_VERIFY(!pthread_cond_wait(&once_cv, &once_mutex));
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT
+ {
+ atomic_type& f = reinterpret_cast< atomic_type& >(flag.storage);
+ {
+ pthread::pthread_mutex_scoped_lock lk(&once_mutex);
+ f.store(initialized, memory_order_release);
+ }
+ BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
+ }
+
+ BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT
+ {
+ atomic_type& f = reinterpret_cast< atomic_type& >(flag.storage);
+ {
+ pthread::pthread_mutex_scoped_lock lk(&once_mutex);
+ f.store(uninitialized, memory_order_release);
+ }
+ BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
+ }
+
+ } // namespace thread_detail
+
+} // namespace boost

Modified: trunk/libs/thread/src/pthread/thread.cpp
==============================================================================
--- trunk/libs/thread/src/pthread/thread.cpp (original)
+++ trunk/libs/thread/src/pthread/thread.cpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -6,7 +6,6 @@
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-//#define BOOST_THREAD_VERSION 3
 #include <boost/thread/detail/config.hpp>
 
 #include <boost/thread/thread.hpp>

Modified: trunk/libs/thread/test/Jamfile.v2
==============================================================================
--- trunk/libs/thread/test/Jamfile.v2 (original)
+++ trunk/libs/thread/test/Jamfile.v2 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -509,6 +509,15 @@
     ;
 
 
+ #explicit ts_once ;
+ test-suite ts_once
+ :
+ #[ thread-compile-fail ./sync/mutual_exclusion/once/once_flag/assign_fail.cpp : : once_flag__assign_f ]
+ #[ thread-compile-fail ./sync/mutual_exclusion/once/once_flag/copy_fail.cpp : : once_flag__copy_f ]
+ #[ thread-run2-noit ./sync/mutual_exclusion/once/once_flag/default_pass.cpp : once_flag__default_p ]
+ [ thread-run2-noit ./sync/mutual_exclusion/once/call_once/call_once_pass.cpp : call_once_p ]
+ ;
+
     #explicit ts_mutex ;
     test-suite ts_mutex
     :
@@ -677,7 +686,6 @@
     test-suite ts_
     :
 
- #[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
           #[ thread-run ../example/test_so.cpp ]
           #[ thread-run ../example/test_so2.cpp ]
 

Added: trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/thread/test/sync/mutual_exclusion/once/call_once/call_once_pass.cpp 2013-01-16 16:49:59 EST (Wed, 16 Jan 2013)
@@ -0,0 +1,217 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (C) 2013 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// <boost/thread/once.hpp>
+
+// struct once_flag;
+
+// template<class Callable, class ...Args>
+// void call_once(once_flag& flag, Callable func, Args&&... args);
+
+//#define BOOST_THREAD_VERSION 4
+
+#include <boost/thread/once.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
+#define BOOST_INIT_ONCE_INIT
+#else
+#define BOOST_INIT_ONCE_INIT =BOOST_ONCE_INIT
+#endif
+
+typedef boost::chrono::milliseconds ms;
+
+boost::once_flag flg0 BOOST_INIT_ONCE_INIT;
+
+int init0_called = 0;
+
+void init0()
+{
+ boost::this_thread::sleep_for(ms(250));
+ ++init0_called;
+}
+
+void f0()
+{
+ boost::call_once(flg0, init0);
+}
+
+boost::once_flag flg3 BOOST_INIT_ONCE_INIT;
+
+int init3_called = 0;
+int init3_completed = 0;
+
+void init3()
+{
+ ++init3_called;
+ boost::this_thread::sleep_for(ms(250));
+ if (init3_called == 1)
+ throw 1;
+ ++init3_completed;
+}
+
+void f3()
+{
+ try
+ {
+ boost::call_once(flg3, init3);
+ }
+ catch (...)
+ {
+ }
+}
+
+#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES && defined(BOOST_THREAD_PLATFORM_PTHREAD)
+
+struct init1
+{
+ static int called;
+
+ void operator()(int i) {called += i;}
+};
+
+int init1::called = 0;
+
+boost::once_flag flg1 BOOST_INIT_ONCE_INIT;
+
+void f1()
+{
+ boost::call_once(flg1, init1(), 1);
+}
+
+struct init2
+{
+ static int called;
+
+ void operator()(int i, int j) const {called += i + j;}
+};
+
+int init2::called = 0;
+
+boost::once_flag flg2 BOOST_INIT_ONCE_INIT;
+
+void f2()
+{
+ boost::call_once(flg2, init2(), 2, 3);
+ boost::call_once(flg2, init2(), 4, 5);
+}
+
+#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
+
+boost::once_flag flg41 BOOST_INIT_ONCE_INIT;
+boost::once_flag flg42 BOOST_INIT_ONCE_INIT;
+
+int init41_called = 0;
+int init42_called = 0;
+
+void init42();
+
+void init41()
+{
+ boost::this_thread::sleep_for(ms(250));
+ ++init41_called;
+}
+
+void init42()
+{
+ boost::this_thread::sleep_for(ms(250));
+ ++init42_called;
+}
+
+void f41()
+{
+ boost::call_once(flg41, init41);
+ boost::call_once(flg42, init42);
+}
+
+void f42()
+{
+ boost::call_once(flg42, init42);
+ boost::call_once(flg41, init41);
+}
+
+#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
+
+class MoveOnly
+{
+public:
+ BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
+ MoveOnly()
+ {
+ }
+ MoveOnly(BOOST_THREAD_RV_REF(MoveOnly))
+ {}
+
+ void operator()(BOOST_THREAD_RV_REF(MoveOnly))
+ {
+ }
+};
+
+#endif
+
+int main()
+{
+ // check basic functionality
+ {
+ boost::thread t0(f0);
+ boost::thread t1(f0);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init0_called == 1);
+ }
+ // check basic exception safety
+ {
+ boost::thread t0(f3);
+ boost::thread t1(f3);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init3_called == 2);
+ BOOST_TEST(init3_completed == 1);
+ }
+ // check deadlock avoidance
+ {
+ boost::thread t0(f41);
+ boost::thread t1(f42);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init41_called == 1);
+ BOOST_TEST(init42_called == 1);
+ }
+#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES && defined(BOOST_THREAD_PLATFORM_PTHREAD)
+ // check functors with 1 arg
+ {
+ boost::thread t0(f1);
+ boost::thread t1(f1);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init1::called == 1);
+ }
+ // check functors with 2 args
+ {
+ boost::thread t0(f2);
+ boost::thread t1(f2);
+ t0.join();
+ t1.join();
+ BOOST_TEST(init2::called == 5);
+ }
+ {
+ boost::once_flag f BOOST_INIT_ONCE_INIT;
+ boost::call_once(f, MoveOnly(), MoveOnly());
+ }
+#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
+ return boost::report_errors();
+}
+
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk