Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/interprocess/sync/spin/condition.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 ////////////////////////////////////////////////////////////////////////////// | |
2 // | |
3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost | |
4 // Software License, Version 1.0. (See accompanying file | |
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 // | |
7 // See http://www.boost.org/libs/interprocess for documentation. | |
8 // | |
9 ////////////////////////////////////////////////////////////////////////////// | |
10 | |
11 #ifndef BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP | |
12 #define BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP | |
13 | |
14 #include <boost/interprocess/detail/config_begin.hpp> | |
15 #include <boost/interprocess/detail/workaround.hpp> | |
16 #include <boost/interprocess/sync/spin/mutex.hpp> | |
17 #include <boost/interprocess/detail/posix_time_types_wrk.hpp> | |
18 #include <boost/interprocess/detail/atomic.hpp> | |
19 #include <boost/interprocess/sync/scoped_lock.hpp> | |
20 #include <boost/interprocess/exceptions.hpp> | |
21 #include <boost/interprocess/detail/os_thread_functions.hpp> | |
22 #include <boost/interprocess/sync/spin/wait.hpp> | |
23 #include <boost/move/move.hpp> | |
24 #include <boost/cstdint.hpp> | |
25 | |
26 namespace boost { | |
27 namespace interprocess { | |
28 namespace ipcdetail { | |
29 | |
30 class spin_condition | |
31 { | |
32 spin_condition(const spin_condition &); | |
33 spin_condition &operator=(const spin_condition &); | |
34 public: | |
35 spin_condition(); | |
36 ~spin_condition(); | |
37 | |
38 void notify_one(); | |
39 void notify_all(); | |
40 | |
41 template <typename L> | |
42 bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time) | |
43 { | |
44 if(abs_time == boost::posix_time::pos_infin){ | |
45 this->wait(lock); | |
46 return true; | |
47 } | |
48 if (!lock) | |
49 throw lock_exception(); | |
50 return this->do_timed_wait(abs_time, *lock.mutex()); | |
51 } | |
52 | |
53 template <typename L, typename Pr> | |
54 bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred) | |
55 { | |
56 if(abs_time == boost::posix_time::pos_infin){ | |
57 this->wait(lock, pred); | |
58 return true; | |
59 } | |
60 if (!lock) | |
61 throw lock_exception(); | |
62 while (!pred()){ | |
63 if (!this->do_timed_wait(abs_time, *lock.mutex())) | |
64 return pred(); | |
65 } | |
66 return true; | |
67 } | |
68 | |
69 template <typename L> | |
70 void wait(L& lock) | |
71 { | |
72 if (!lock) | |
73 throw lock_exception(); | |
74 do_wait(*lock.mutex()); | |
75 } | |
76 | |
77 template <typename L, typename Pr> | |
78 void wait(L& lock, Pr pred) | |
79 { | |
80 if (!lock) | |
81 throw lock_exception(); | |
82 | |
83 while (!pred()) | |
84 do_wait(*lock.mutex()); | |
85 } | |
86 | |
87 template<class InterprocessMutex> | |
88 void do_wait(InterprocessMutex &mut); | |
89 | |
90 template<class InterprocessMutex> | |
91 bool do_timed_wait(const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); | |
92 | |
93 private: | |
94 template<class InterprocessMutex> | |
95 bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, InterprocessMutex &mut); | |
96 | |
97 enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL }; | |
98 spin_mutex m_enter_mut; | |
99 volatile boost::uint32_t m_command; | |
100 volatile boost::uint32_t m_num_waiters; | |
101 void notify(boost::uint32_t command); | |
102 }; | |
103 | |
104 inline spin_condition::spin_condition() | |
105 { | |
106 //Note that this class is initialized to zero. | |
107 //So zeroed memory can be interpreted as an initialized | |
108 //condition variable | |
109 m_command = SLEEP; | |
110 m_num_waiters = 0; | |
111 } | |
112 | |
113 inline spin_condition::~spin_condition() | |
114 { | |
115 //Trivial destructor | |
116 } | |
117 | |
118 inline void spin_condition::notify_one() | |
119 { | |
120 this->notify(NOTIFY_ONE); | |
121 } | |
122 | |
123 inline void spin_condition::notify_all() | |
124 { | |
125 this->notify(NOTIFY_ALL); | |
126 } | |
127 | |
128 inline void spin_condition::notify(boost::uint32_t command) | |
129 { | |
130 //This mutex guarantees that no other thread can enter to the | |
131 //do_timed_wait method logic, so that thread count will be | |
132 //constant until the function writes a NOTIFY_ALL command. | |
133 //It also guarantees that no other notification can be signaled | |
134 //on this spin_condition before this one ends | |
135 m_enter_mut.lock(); | |
136 | |
137 //Return if there are no waiters | |
138 if(!atomic_read32(&m_num_waiters)) { | |
139 m_enter_mut.unlock(); | |
140 return; | |
141 } | |
142 | |
143 //Notify that all threads should execute wait logic | |
144 spin_wait swait; | |
145 while(SLEEP != atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){ | |
146 swait.yield(); | |
147 } | |
148 //The enter mutex will rest locked until the last waiting thread unlocks it | |
149 } | |
150 | |
151 template<class InterprocessMutex> | |
152 inline void spin_condition::do_wait(InterprocessMutex &mut) | |
153 { | |
154 this->do_timed_wait(false, boost::posix_time::ptime(), mut); | |
155 } | |
156 | |
157 template<class InterprocessMutex> | |
158 inline bool spin_condition::do_timed_wait | |
159 (const boost::posix_time::ptime &abs_time, InterprocessMutex &mut) | |
160 { | |
161 return this->do_timed_wait(true, abs_time, mut); | |
162 } | |
163 | |
164 template<class InterprocessMutex> | |
165 inline bool spin_condition::do_timed_wait(bool tout_enabled, | |
166 const boost::posix_time::ptime &abs_time, | |
167 InterprocessMutex &mut) | |
168 { | |
169 boost::posix_time::ptime now = microsec_clock::universal_time(); | |
170 | |
171 if(tout_enabled){ | |
172 if(now >= abs_time) return false; | |
173 } | |
174 | |
175 typedef boost::interprocess::scoped_lock<spin_mutex> InternalLock; | |
176 //The enter mutex guarantees that while executing a notification, | |
177 //no other thread can execute the do_timed_wait method. | |
178 { | |
179 //--------------------------------------------------------------- | |
180 InternalLock lock; | |
181 if(tout_enabled){ | |
182 InternalLock dummy(m_enter_mut, abs_time); | |
183 lock = boost::move(dummy); | |
184 } | |
185 else{ | |
186 InternalLock dummy(m_enter_mut); | |
187 lock = boost::move(dummy); | |
188 } | |
189 | |
190 if(!lock) | |
191 return false; | |
192 //--------------------------------------------------------------- | |
193 //We increment the waiting thread count protected so that it will be | |
194 //always constant when another thread enters the notification logic. | |
195 //The increment marks this thread as "waiting on spin_condition" | |
196 atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters)); | |
197 | |
198 //We unlock the external mutex atomically with the increment | |
199 mut.unlock(); | |
200 } | |
201 | |
202 //By default, we suppose that no timeout has happened | |
203 bool timed_out = false, unlock_enter_mut= false; | |
204 | |
205 //Loop until a notification indicates that the thread should | |
206 //exit or timeout occurs | |
207 while(1){ | |
208 //The thread sleeps/spins until a spin_condition commands a notification | |
209 //Notification occurred, we will lock the checking mutex so that | |
210 spin_wait swait; | |
211 while(atomic_read32(&m_command) == SLEEP){ | |
212 swait.yield(); | |
213 | |
214 //Check for timeout | |
215 if(tout_enabled){ | |
216 now = microsec_clock::universal_time(); | |
217 | |
218 if(now >= abs_time){ | |
219 //If we can lock the mutex it means that no notification | |
220 //is being executed in this spin_condition variable | |
221 timed_out = m_enter_mut.try_lock(); | |
222 | |
223 //If locking fails, indicates that another thread is executing | |
224 //notification, so we play the notification game | |
225 if(!timed_out){ | |
226 //There is an ongoing notification, we will try again later | |
227 continue; | |
228 } | |
229 //No notification in execution, since enter mutex is locked. | |
230 //We will execute time-out logic, so we will decrement count, | |
231 //release the enter mutex and return false. | |
232 break; | |
233 } | |
234 } | |
235 } | |
236 | |
237 //If a timeout occurred, the mutex will not execute checking logic | |
238 if(tout_enabled && timed_out){ | |
239 //Decrement wait count | |
240 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); | |
241 unlock_enter_mut = true; | |
242 break; | |
243 } | |
244 else{ | |
245 boost::uint32_t result = atomic_cas32 | |
246 (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE); | |
247 if(result == SLEEP){ | |
248 //Other thread has been notified and since it was a NOTIFY one | |
249 //command, this thread must sleep again | |
250 continue; | |
251 } | |
252 else if(result == NOTIFY_ONE){ | |
253 //If it was a NOTIFY_ONE command, only this thread should | |
254 //exit. This thread has atomically marked command as sleep before | |
255 //so no other thread will exit. | |
256 //Decrement wait count. | |
257 unlock_enter_mut = true; | |
258 atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); | |
259 break; | |
260 } | |
261 else{ | |
262 //If it is a NOTIFY_ALL command, all threads should return | |
263 //from do_timed_wait function. Decrement wait count. | |
264 unlock_enter_mut = 1 == atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters)); | |
265 //Check if this is the last thread of notify_all waiters | |
266 //Only the last thread will release the mutex | |
267 if(unlock_enter_mut){ | |
268 atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL); | |
269 } | |
270 break; | |
271 } | |
272 } | |
273 } | |
274 | |
275 //Unlock the enter mutex if it is a single notification, if this is | |
276 //the last notified thread in a notify_all or a timeout has occurred | |
277 if(unlock_enter_mut){ | |
278 m_enter_mut.unlock(); | |
279 } | |
280 | |
281 //Lock external again before returning from the method | |
282 mut.lock(); | |
283 return !timed_out; | |
284 } | |
285 | |
286 } //namespace ipcdetail | |
287 } //namespace interprocess | |
288 } //namespace boost | |
289 | |
290 #include <boost/interprocess/detail/config_end.hpp> | |
291 | |
292 #endif //BOOST_INTERPROCESS_DETAIL_SPIN_CONDITION_HPP |