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
29namespace 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_;
39 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
46 default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
47 size_(other.size_)
48 {
49 }
50 default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT :
51 size_(BOOST_THREAD_RV(other).size_)
52 {
53 }
54
55 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>
66 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>
70 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
77 void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT :
78 size_(other.size_), fct_(other.fct_)
79 {
80 }
81 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
87 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_)();
97 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
104 void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT :
105 size_(other.size_), fct_(other.fct_)
106 {
107 }
108 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 }
112 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 {
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
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>
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>
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>
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>
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
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 }
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
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
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