annotate DEPENDENCIES/generic/include/boost/thread/win32/condition_variable.hpp @ 16:2665513ce2d3

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