1 // (C) Copyright 2013 Andrey Semashev 2 // (C) Copyright 2013 Vicente J. Botet Escriba 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 //#define __STDC_CONSTANT_MACROS 8 #include <boost/thread/detail/config.hpp> 9 #include <boost/thread/once.hpp> 10 #include <boost/thread/pthread/pthread_helpers.hpp> 11 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> 12 #include <boost/assert.hpp> 13 #include <boost/static_assert.hpp> 14 #include <boost/atomic.hpp> 15 #include <boost/memory_order.hpp> 16 #include <pthread.h> 17 18 namespace boost 19 { 20 namespace thread_detail 21 { 22 23 enum flag_states 24 { 25 uninitialized, in_progress, initialized 26 }; 27 28 29 #ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11 30 BOOST_STATIC_ASSERT_MSG(sizeof(atomic_int_type) == sizeof(atomic_type), "Boost.Thread: unsupported platform"); 31 #endif 32 33 static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; 34 static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER; 35 enter_once_region(once_flag & flag)36 BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT 37 { 38 atomic_type& f = get_atomic_storage(flag); 39 if (f.load(memory_order_acquire) != initialized) 40 { 41 pthread::pthread_mutex_scoped_lock lk(&once_mutex); 42 if (f.load(memory_order_acquire) != initialized) 43 { 44 for (;;) 45 { 46 atomic_int_type expected = uninitialized; 47 if (f.compare_exchange_strong(expected, in_progress, memory_order_acq_rel, memory_order_acquire)) 48 { 49 // We have set the flag to in_progress 50 return true; 51 } 52 else if (expected == initialized) 53 { 54 // Another thread managed to complete the initialization 55 return false; 56 } 57 else 58 { 59 // Wait until the initialization is complete 60 //pthread::pthread_mutex_scoped_lock lk(&once_mutex); 61 BOOST_VERIFY(!posix::pthread_cond_wait(&once_cv, &once_mutex)); 62 } 63 } 64 } 65 } 66 return false; 67 } 68 commit_once_region(once_flag & flag)69 BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT 70 { 71 atomic_type& f = get_atomic_storage(flag); 72 { 73 pthread::pthread_mutex_scoped_lock lk(&once_mutex); 74 f.store(initialized, memory_order_release); 75 } 76 BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv)); 77 } 78 rollback_once_region(once_flag & flag)79 BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT 80 { 81 atomic_type& f = get_atomic_storage(flag); 82 { 83 pthread::pthread_mutex_scoped_lock lk(&once_mutex); 84 f.store(uninitialized, memory_order_release); 85 } 86 BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv)); 87 } 88 89 } // namespace thread_detail 90 91 } // namespace boost 92