• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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