]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/include/boost/thread/win32/condition_variable.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / thread / include / boost / thread / win32 / condition_variable.hpp
1 #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
2 #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 // (C) Copyright 2007-8 Anthony Williams
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
8
9 #include <boost/thread/win32/thread_primitives.hpp>
10 #include <boost/thread/win32/thread_data.hpp>
11 #include <boost/thread/win32/thread_data.hpp>
12 #include <boost/thread/win32/interlocked_read.hpp>
13 #include <boost/thread/cv_status.hpp>
14 #if defined BOOST_THREAD_USES_DATETIME
15 #include <boost/thread/xtime.hpp>
16 #endif
17 #include <boost/thread/mutex.hpp>
18 #include <boost/thread/thread_time.hpp>
19 #include <boost/thread/lock_guard.hpp>
20 #include <boost/thread/lock_types.hpp>
21
22 #include <boost/assert.hpp>
23 #include <boost/intrusive_ptr.hpp>
24
25 #ifdef BOOST_THREAD_USES_CHRONO
26 #include <boost/chrono/system_clocks.hpp>
27 #include <boost/chrono/ceil.hpp>
28 #endif
29
30 #include <limits.h>
31 #include <algorithm>
32 #include <vector>
33
34 #include <boost/config/abi_prefix.hpp>
35
36 namespace boost
37 {
38 namespace detail
39 {
40 class basic_cv_list_entry;
41 void intrusive_ptr_add_ref(basic_cv_list_entry * p);
42 void intrusive_ptr_release(basic_cv_list_entry * p);
43
44 class basic_cv_list_entry
45 {
46 private:
47 detail::win32::handle_manager semaphore;
48 detail::win32::handle_manager wake_sem;
49 long waiters;
50 bool notified;
51 long references;
52
53 public:
54 BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
55 explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
56 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
57 wake_sem(wake_sem_.duplicate()),
58 waiters(1),notified(false),references(0)
59 {}
60
61 static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
62 {
63 return !detail::interlocked_read_acquire(&entry->waiters);
64 }
65
66 void add_waiter()
67 {
68 BOOST_INTERLOCKED_INCREMENT(&waiters);
69 }
70
71 void remove_waiter()
72 {
73 BOOST_INTERLOCKED_DECREMENT(&waiters);
74 }
75
76 void release(unsigned count_to_release)
77 {
78 notified=true;
79 detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
80 }
81
82 void release_waiters()
83 {
84 release(detail::interlocked_read_acquire(&waiters));
85 }
86
87 bool is_notified() const
88 {
89 return notified;
90 }
91
92 bool wait(timeout abs_time)
93 {
94 return this_thread::interruptible_wait(semaphore,abs_time);
95 }
96
97 bool woken()
98 {
99 unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
100 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
101 return woken_result==0;
102 }
103
104 friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
105 friend void intrusive_ptr_release(basic_cv_list_entry * p);
106 };
107
108 inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
109 {
110 BOOST_INTERLOCKED_INCREMENT(&p->references);
111 }
112
113 inline void intrusive_ptr_release(basic_cv_list_entry * p)
114 {
115 if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
116 {
117 delete p;
118 }
119 }
120
121 class basic_condition_variable
122 {
123 boost::mutex internal_mutex;
124 long total_count;
125 unsigned active_generation_count;
126
127 typedef basic_cv_list_entry list_entry;
128
129 typedef boost::intrusive_ptr<list_entry> entry_ptr;
130 typedef std::vector<entry_ptr> generation_list;
131
132 generation_list generations;
133 detail::win32::handle_manager wake_sem;
134
135 void wake_waiters(long count_to_wake)
136 {
137 detail::interlocked_write_release(&total_count,total_count-count_to_wake);
138 detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
139 }
140
141 template<typename lock_type>
142 struct relocker
143 {
144 BOOST_THREAD_NO_COPYABLE(relocker)
145 lock_type& lock;
146 bool unlocked;
147
148 relocker(lock_type& lock_):
149 lock(lock_),unlocked(false)
150 {}
151 void unlock()
152 {
153 lock.unlock();
154 unlocked=true;
155 }
156 ~relocker()
157 {
158 if(unlocked)
159 {
160 lock.lock();
161 }
162
163 }
164 };
165
166
167 entry_ptr get_wait_entry()
168 {
169 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
170
171 if(!wake_sem)
172 {
173 wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
174 BOOST_ASSERT(wake_sem);
175 }
176
177 detail::interlocked_write_release(&total_count,total_count+1);
178 if(generations.empty() || generations.back()->is_notified())
179 {
180 entry_ptr new_entry(new list_entry(wake_sem));
181 generations.push_back(new_entry);
182 return new_entry;
183 }
184 else
185 {
186 generations.back()->add_waiter();
187 return generations.back();
188 }
189 }
190
191 struct entry_manager
192 {
193 entry_ptr const entry;
194 boost::mutex& internal_mutex;
195
196 BOOST_THREAD_NO_COPYABLE(entry_manager)
197 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
198 entry(entry_), internal_mutex(mutex_)
199 {}
200
201 ~entry_manager()
202 {
203 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
204 entry->remove_waiter();
205 }
206
207 list_entry* operator->()
208 {
209 return entry.get();
210 }
211 };
212
213
214 protected:
215 template<typename lock_type>
216 bool do_wait(lock_type& lock,timeout abs_time)
217 {
218 relocker<lock_type> locker(lock);
219
220 entry_manager entry(get_wait_entry(), internal_mutex);
221
222 locker.unlock();
223
224 bool woken=false;
225 while(!woken)
226 {
227 if(!entry->wait(abs_time))
228 {
229 return false;
230 }
231
232 woken=entry->woken();
233 }
234 return woken;
235 }
236
237 template<typename lock_type,typename predicate_type>
238 bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
239 {
240 while (!pred())
241 {
242 if(!do_wait(m, abs_time))
243 return pred();
244 }
245 return true;
246 }
247
248 basic_condition_variable(const basic_condition_variable& other);
249 basic_condition_variable& operator=(const basic_condition_variable& other);
250
251 public:
252 basic_condition_variable():
253 total_count(0),active_generation_count(0),wake_sem(0)
254 {}
255
256 ~basic_condition_variable()
257 {}
258
259 void notify_one() BOOST_NOEXCEPT
260 {
261 if(detail::interlocked_read_acquire(&total_count))
262 {
263 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
264 if(!total_count)
265 {
266 return;
267 }
268 wake_waiters(1);
269
270 for(generation_list::iterator it=generations.begin(),
271 end=generations.end();
272 it!=end;++it)
273 {
274 (*it)->release(1);
275 }
276 generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
277 }
278 }
279
280 void notify_all() BOOST_NOEXCEPT
281 {
282 if(detail::interlocked_read_acquire(&total_count))
283 {
284 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
285 if(!total_count)
286 {
287 return;
288 }
289 wake_waiters(total_count);
290 for(generation_list::iterator it=generations.begin(),
291 end=generations.end();
292 it!=end;++it)
293 {
294 (*it)->release_waiters();
295 }
296 generations.clear();
297 wake_sem=detail::win32::handle(0);
298 }
299 }
300
301 };
302 }
303
304 class condition_variable:
305 private detail::basic_condition_variable
306 {
307 public:
308 BOOST_THREAD_NO_COPYABLE(condition_variable)
309 condition_variable()
310 {}
311
312 using detail::basic_condition_variable::notify_one;
313 using detail::basic_condition_variable::notify_all;
314
315 void wait(unique_lock<mutex>& m)
316 {
317 do_wait(m,detail::timeout::sentinel());
318 }
319
320 template<typename predicate_type>
321 void wait(unique_lock<mutex>& m,predicate_type pred)
322 {
323 while(!pred()) wait(m);
324 }
325
326
327 #if defined BOOST_THREAD_USES_DATETIME
328 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
329 {
330 return do_wait(m,abs_time);
331 }
332
333 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
334 {
335 return do_wait(m,system_time(abs_time));
336 }
337 template<typename duration_type>
338 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
339 {
340 if (wait_duration.is_pos_infinity())
341 {
342 wait(m); // or do_wait(m,detail::timeout::sentinel());
343 return true;
344 }
345 if (wait_duration.is_special())
346 {
347 return true;
348 }
349 return do_wait(m,wait_duration.total_milliseconds());
350 }
351
352 template<typename predicate_type>
353 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
354 {
355 return do_wait(m,abs_time,pred);
356 }
357 template<typename predicate_type>
358 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
359 {
360 return do_wait(m,system_time(abs_time),pred);
361 }
362 template<typename duration_type,typename predicate_type>
363 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
364 {
365 if (wait_duration.is_pos_infinity())
366 {
367 while (!pred())
368 {
369 wait(m); // or do_wait(m,detail::timeout::sentinel());
370 }
371 return true;
372 }
373 if (wait_duration.is_special())
374 {
375 return pred();
376 }
377 return do_wait(m,wait_duration.total_milliseconds(),pred);
378 }
379 #endif
380 #ifdef BOOST_THREAD_USES_CHRONO
381
382 template <class Clock, class Duration>
383 cv_status
384 wait_until(
385 unique_lock<mutex>& lock,
386 const chrono::time_point<Clock, Duration>& t)
387 {
388 using namespace chrono;
389 chrono::time_point<Clock, Duration> now = Clock::now();
390 if (t<=now) {
391 return cv_status::timeout;
392 }
393 do_wait(lock, ceil<milliseconds>(t-now).count());
394 return Clock::now() < t ? cv_status::no_timeout :
395 cv_status::timeout;
396 }
397
398 template <class Rep, class Period>
399 cv_status
400 wait_for(
401 unique_lock<mutex>& lock,
402 const chrono::duration<Rep, Period>& d)
403 {
404 using namespace chrono;
405 if (d<=chrono::duration<Rep, Period>::zero()) {
406 return cv_status::timeout;
407 }
408
409 steady_clock::time_point c_now = steady_clock::now();
410 do_wait(lock, ceil<milliseconds>(d).count());
411 return steady_clock::now() - c_now < d ? cv_status::no_timeout :
412 cv_status::timeout;
413 }
414
415 template <class Clock, class Duration, class Predicate>
416 bool
417 wait_until(
418 unique_lock<mutex>& lock,
419 const chrono::time_point<Clock, Duration>& t,
420 Predicate pred)
421 {
422 while (!pred())
423 {
424 if (wait_until(lock, t) == cv_status::timeout)
425 return pred();
426 }
427 return true;
428 }
429 template <class Rep, class Period, class Predicate>
430 bool
431 wait_for(
432 unique_lock<mutex>& lock,
433 const chrono::duration<Rep, Period>& d,
434 Predicate pred)
435 {
436 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
437 }
438 #endif
439 };
440
441 class condition_variable_any:
442 private detail::basic_condition_variable
443 {
444 public:
445 BOOST_THREAD_NO_COPYABLE(condition_variable_any)
446 condition_variable_any()
447 {}
448
449 using detail::basic_condition_variable::notify_one;
450 using detail::basic_condition_variable::notify_all;
451
452 template<typename lock_type>
453 void wait(lock_type& m)
454 {
455 do_wait(m,detail::timeout::sentinel());
456 }
457
458 template<typename lock_type,typename predicate_type>
459 void wait(lock_type& m,predicate_type pred)
460 {
461 while(!pred()) wait(m);
462 }
463
464 #if defined BOOST_THREAD_USES_DATETIME
465 template<typename lock_type>
466 bool timed_wait(lock_type& m,boost::system_time const& abs_time)
467 {
468 return do_wait(m,abs_time);
469 }
470
471 template<typename lock_type>
472 bool timed_wait(lock_type& m,boost::xtime const& abs_time)
473 {
474 return do_wait(m,system_time(abs_time));
475 }
476
477 template<typename lock_type,typename duration_type>
478 bool timed_wait(lock_type& m,duration_type const& wait_duration)
479 {
480 return do_wait(m,wait_duration.total_milliseconds());
481 }
482
483 template<typename lock_type,typename predicate_type>
484 bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
485 {
486 return do_wait(m,abs_time,pred);
487 }
488
489 template<typename lock_type,typename predicate_type>
490 bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
491 {
492 return do_wait(m,system_time(abs_time),pred);
493 }
494
495 template<typename lock_type,typename duration_type,typename predicate_type>
496 bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
497 {
498 return do_wait(m,wait_duration.total_milliseconds(),pred);
499 }
500 #endif
501 #ifdef BOOST_THREAD_USES_CHRONO
502
503 template <class lock_type, class Clock, class Duration>
504 cv_status
505 wait_until(
506 lock_type& lock,
507 const chrono::time_point<Clock, Duration>& t)
508 {
509 using namespace chrono;
510 chrono::time_point<Clock, Duration> now = Clock::now();
511 if (t<=now) {
512 return cv_status::timeout;
513 }
514 do_wait(lock, ceil<milliseconds>(t-now).count());
515 return Clock::now() < t ? cv_status::no_timeout :
516 cv_status::timeout;
517 }
518
519 template <class lock_type, class Rep, class Period>
520 cv_status
521 wait_for(
522 lock_type& lock,
523 const chrono::duration<Rep, Period>& d)
524 {
525 using namespace chrono;
526 if (d<=chrono::duration<Rep, Period>::zero()) {
527 return cv_status::timeout;
528 }
529 steady_clock::time_point c_now = steady_clock::now();
530 do_wait(lock, ceil<milliseconds>(d).count());
531 return steady_clock::now() - c_now < d ? cv_status::no_timeout :
532 cv_status::timeout;
533 }
534
535 template <class lock_type, class Clock, class Duration, class Predicate>
536 bool
537 wait_until(
538 lock_type& lock,
539 const chrono::time_point<Clock, Duration>& t,
540 Predicate pred)
541 {
542 while (!pred())
543 {
544 if (wait_until(lock, t) == cv_status::timeout)
545 return pred();
546 }
547 return true;
548 }
549
550 template <class lock_type, class Rep, class Period, class Predicate>
551 bool
552 wait_for(
553 lock_type& lock,
554 const chrono::duration<Rep, Period>& d,
555 Predicate pred)
556 {
557 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
558 }
559 #endif
560 };
561
562 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
563 }
564
565 #include <boost/config/abi_suffix.hpp>
566
567 #endif