1 // Copyright (C) 2002-2003
2 // David Moore, William E. Kempf
3 // Copyright (C) 2007-8 Anthony Williams
4 // (C) Copyright 2013 Vicente J. Botet Escriba
5 //
6 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_BARRIER_JDM030602_HPP
10 #define BOOST_BARRIER_JDM030602_HPP
11 
12 #include <boost/thread/detail/config.hpp>
13 #include <boost/thread/detail/delete.hpp>
14 
15 #include <boost/throw_exception.hpp>
16 #include <boost/thread/mutex.hpp>
17 #include <boost/thread/lock_types.hpp>
18 #include <boost/thread/condition_variable.hpp>
19 #include <string>
20 #include <stdexcept>
21 #include <boost/thread/detail/nullary_function.hpp>
22 #include <boost/type_traits/is_same.hpp>
23 #include <boost/type_traits/is_void.hpp>
24 #include <boost/core/enable_if.hpp>
25 #include <boost/utility/result_of.hpp>
26 
27 #include <boost/config/abi_prefix.hpp>
28 
29 namespace boost
30 {
31   namespace thread_detail
32   {
33     typedef detail::nullary_function<void()> void_completion_function;
34     typedef detail::nullary_function<size_t()> size_completion_function;
35 
36     struct default_barrier_reseter
37     {
38       unsigned int size_;
default_barrier_reseterboost::thread_detail::default_barrier_reseter39       default_barrier_reseter(unsigned int size) :
40         size_(size)
41       {
42       }
43       BOOST_THREAD_MOVABLE(default_barrier_reseter)
44       //BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter)
45 
default_barrier_reseterboost::thread_detail::default_barrier_reseter46       default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
47       size_(other.size_)
48       {
49       }
default_barrier_reseterboost::thread_detail::default_barrier_reseter50       default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT :
51       size_(BOOST_THREAD_RV(other).size_)
52       {
53       }
54 
operator ()boost::thread_detail::default_barrier_reseter55       unsigned int operator()()
56       {
57         return size_;
58       }
59     };
60 
61     struct void_functor_barrier_reseter
62     {
63       unsigned int size_;
64       void_completion_function fct_;
65       template <typename F>
void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter66       void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
67       : size_(size), fct_(boost::move(funct))
68       {}
69       template <typename F>
void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter70       void_functor_barrier_reseter(unsigned int size, F& funct)
71       : size_(size), fct_(funct)
72       {}
73 
74       BOOST_THREAD_MOVABLE(void_functor_barrier_reseter)
75       //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_functor_barrier_reseter)
76 
void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter77       void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT :
78       size_(other.size_), fct_(other.fct_)
79       {
80       }
void_functor_barrier_reseterboost::thread_detail::void_functor_barrier_reseter81       void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT :
82       size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
83       //size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(BOOST_THREAD_RV(other).fct_))
84       {
85       }
86 
operator ()boost::thread_detail::void_functor_barrier_reseter87       unsigned int operator()()
88       {
89         fct_();
90         return size_;
91       }
92     };
93     struct void_fct_ptr_barrier_reseter
94     {
95       unsigned int size_;
96       void(*fct_)();
void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter97       void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) :
98         size_(size), fct_(funct)
99       {
100       }
101       BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter)
102       //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_fct_ptr_barrier_reseter)
103 
void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter104       void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT :
105       size_(other.size_), fct_(other.fct_)
106       {
107       }
void_fct_ptr_barrier_reseterboost::thread_detail::void_fct_ptr_barrier_reseter108       void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT :
109       size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
110       {
111       }
operator ()boost::thread_detail::void_fct_ptr_barrier_reseter112       unsigned int operator()()
113       {
114         fct_();
115         return size_;
116       }
117     };
118   }
119   //BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter)
120   //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter)
121   //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter)
122 
123   class barrier
124   {
check_counter(unsigned int count)125     static inline unsigned int check_counter(unsigned int count)
126     {
127       if (count == 0) boost::throw_exception(
128           thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
129       return count;
130     }
131     struct dummy
132     {
133     };
134 
135   public:
136     BOOST_THREAD_NO_COPYABLE( barrier)
137 
barrier(unsigned int count)138     explicit barrier(unsigned int count) :
139       m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))
140     {
141     }
142 
143     template <typename F>
barrier(unsigned int count,BOOST_THREAD_RV_REF (F)funct,typename enable_if<typename is_void<typename result_of<F ()>::type>::type,dummy * >::type=0)144     barrier(
145         unsigned int count,
146         BOOST_THREAD_RV_REF(F) funct,
147         typename enable_if<
148         typename is_void<typename result_of<F()>::type>::type, dummy*
149         >::type=0
150     )
151     : m_count(check_counter(count)),
152       m_generation(0),
153       fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
154         boost::move(funct)))
155     )
156     {
157     }
158     template <typename F>
barrier(unsigned int count,F & funct,typename enable_if<typename is_void<typename result_of<F ()>::type>::type,dummy * >::type=0)159     barrier(
160         unsigned int count,
161         F &funct,
162         typename enable_if<
163         typename is_void<typename result_of<F()>::type>::type, dummy*
164         >::type=0
165     )
166     : m_count(check_counter(count)),
167       m_generation(0),
168       fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
169         funct))
170     )
171     {
172     }
173 
174     template <typename F>
barrier(unsigned int count,BOOST_THREAD_RV_REF (F)funct,typename enable_if<typename is_same<typename result_of<F ()>::type,unsigned int>::type,dummy * >::type=0)175     barrier(
176         unsigned int count,
177         BOOST_THREAD_RV_REF(F) funct,
178         typename enable_if<
179         typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy*
180         >::type=0
181     )
182     : m_count(check_counter(count)),
183       m_generation(0),
184       fct_(boost::move(funct))
185     {
186     }
187     template <typename F>
barrier(unsigned int count,F & funct,typename enable_if<typename is_same<typename result_of<F ()>::type,unsigned int>::type,dummy * >::type=0)188     barrier(
189         unsigned int count,
190         F& funct,
191         typename enable_if<
192         typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy*
193         >::type=0
194     )
195     : m_count(check_counter(count)),
196       m_generation(0),
197       fct_(funct)
198     {
199     }
200 
barrier(unsigned int count,void (* funct)())201     barrier(unsigned int count, void(*funct)()) :
202       m_count(check_counter(count)), m_generation(0),
203       fct_(funct
204           ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct))))
205           : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
206       )
207     {
208     }
barrier(unsigned int count,unsigned int (* funct)())209     barrier(unsigned int count, unsigned int(*funct)()) :
210       m_count(check_counter(count)), m_generation(0),
211       fct_(funct
212           ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct))
213           : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
214       )
215     {
216     }
217 
wait()218     bool wait()
219     {
220       boost::unique_lock < boost::mutex > lock(m_mutex);
221       unsigned int gen = m_generation;
222 
223       if (--m_count == 0)
224       {
225         m_generation++;
226         m_count = static_cast<unsigned int>(fct_());
227         BOOST_ASSERT(m_count != 0);
228         lock.unlock();
229         m_cond.notify_all();
230         return true;
231       }
232 
233       while (gen == m_generation)
234         m_cond.wait(lock);
235       return false;
236     }
237 
count_down_and_wait()238     void count_down_and_wait()
239     {
240       wait();
241     }
242 
243   private:
244     mutex m_mutex;
245     condition_variable m_cond;
246     unsigned int m_count;
247     unsigned int m_generation;
248     thread_detail::size_completion_function fct_;
249   };
250 
251 } // namespace boost
252 
253 #include <boost/config/abi_suffix.hpp>
254 
255 #endif
256