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 #include <boost/thread/detail/platform_time.hpp> 22 23 #include <boost/assert.hpp> 24 #include <boost/intrusive_ptr.hpp> 25 26 #ifdef BOOST_THREAD_USES_CHRONO 27 #include <boost/chrono/system_clocks.hpp> 28 #include <boost/chrono/ceil.hpp> 29 #endif 30 31 #include <limits.h> 32 #include <algorithm> 33 #include <vector> 34 35 #include <boost/config/abi_prefix.hpp> 36 37 namespace boost 38 { 39 namespace detail 40 { 41 class basic_cv_list_entry; initializeboost::detail::basic_timed_mutex42 void intrusive_ptr_add_ref(basic_cv_list_entry * p); 43 void intrusive_ptr_release(basic_cv_list_entry * p); 44 45 class basic_cv_list_entry 46 { 47 private: destroyboost::detail::basic_timed_mutex48 detail::win32::handle_manager semaphore; 49 detail::win32::handle_manager wake_sem; 50 long waiters; 51 bool notified; 52 long references; 53 54 public: 55 BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry) 56 explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): 57 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), 58 wake_sem(wake_sem_.duplicate()), 59 waiters(1),notified(false),references(0) 60 {} 61 62 static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry) 63 { 64 return !detail::interlocked_read_acquire(&entry->waiters); try_lockboost::detail::basic_timed_mutex65 } 66 67 void add_waiter() 68 { 69 BOOST_INTERLOCKED_INCREMENT(&waiters); 70 } 71 72 void remove_waiter() 73 { 74 BOOST_INTERLOCKED_DECREMENT(&waiters); 75 } 76 77 void release(unsigned count_to_release) 78 { 79 notified=true; 80 winapi::ReleaseSemaphore(semaphore,count_to_release,0); 81 } 82 83 void release_waiters() 84 { 85 release(detail::interlocked_read_acquire(&waiters)); 86 } 87 88 bool is_notified() const 89 { 90 return notified; 91 } 92 93 bool interruptible_wait(detail::internal_platform_timepoint const &timeout) 94 { 95 return this_thread::interruptible_wait(semaphore, timeout); mark_waiting_and_try_lockboost::detail::basic_timed_mutex96 } 97 98 bool woken() 99 { 100 unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0); 101 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); 102 return woken_result==0; 103 } 104 105 friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); 106 friend void intrusive_ptr_release(basic_cv_list_entry * p); 107 }; 108 109 inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) 110 { 111 BOOST_INTERLOCKED_INCREMENT(&p->references); 112 } 113 114 inline void intrusive_ptr_release(basic_cv_list_entry * p) 115 { 116 if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) 117 { 118 delete p; 119 } clear_waiting_and_try_lockboost::detail::basic_timed_mutex120 } 121 122 class basic_condition_variable 123 { 124 boost::mutex internal_mutex; 125 long total_count; 126 unsigned active_generation_count; 127 128 typedef basic_cv_list_entry list_entry; 129 130 typedef boost::intrusive_ptr<list_entry> entry_ptr; 131 typedef std::vector<entry_ptr> generation_list; 132 133 generation_list generations; 134 detail::win32::handle_manager wake_sem; 135 136 void wake_waiters(long count_to_wake) 137 { 138 detail::interlocked_write_release(&total_count,total_count-count_to_wake); 139 winapi::ReleaseSemaphore(wake_sem,count_to_wake,0); 140 } 141 142 template<typename lock_type> 143 struct relocker 144 { 145 BOOST_THREAD_NO_COPYABLE(relocker) 146 lock_type& _lock; 147 bool _unlocked; 148 149 relocker(lock_type& lock_): 150 _lock(lock_), _unlocked(false) 151 {} 152 void unlock() 153 { 154 if ( ! _unlocked ) 155 { 156 _lock.unlock(); 157 _unlocked=true; 158 } 159 } 160 void lock() 161 { 162 if ( _unlocked ) 163 { 164 _lock.lock(); 165 _unlocked=false; 166 } 167 } 168 ~relocker() BOOST_NOEXCEPT_IF(false) 169 { 170 lock(); 171 } 172 }; 173 174 175 entry_ptr get_wait_entry() 176 { 177 boost::lock_guard<boost::mutex> lk(internal_mutex); 178 if(!wake_sem) 179 { 180 wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); 181 BOOST_ASSERT(wake_sem); 182 } 183 184 detail::interlocked_write_release(&total_count,total_count+1); 185 if(generations.empty() || generations.back()->is_notified()) 186 { 187 entry_ptr new_entry(new list_entry(wake_sem)); 188 generations.push_back(new_entry); 189 return new_entry; 190 } 191 else 192 { 193 generations.back()->add_waiter(); 194 return generations.back(); 195 } 196 } 197 198 struct entry_manager 199 { 200 entry_ptr entry; 201 boost::mutex& internal_mutex; 202 203 204 BOOST_THREAD_NO_COPYABLE(entry_manager) 205 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 206 entry_manager(entry_ptr&& entry_, boost::mutex& mutex_): 207 entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_) 208 {} 209 #else 210 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_): 211 entry(entry_), internal_mutex(mutex_) 212 {} 213 #endif 214 215 void remove_waiter_and_reset() 216 { 217 if (entry) { 218 boost::lock_guard<boost::mutex> internal_lock(internal_mutex); 219 entry->remove_waiter(); 220 entry.reset(); 221 } 222 } 223 ~entry_manager() BOOST_NOEXCEPT_IF(false) 224 { 225 remove_waiter_and_reset(); 226 } 227 228 list_entry* operator->() 229 { 230 return entry.get(); 231 } 232 }; 233 234 protected: 235 basic_condition_variable(const basic_condition_variable& other); 236 basic_condition_variable& operator=(const basic_condition_variable& other); 237 238 public: 239 basic_condition_variable(): 240 total_count(0),active_generation_count(0),wake_sem(0) 241 {} 242 243 ~basic_condition_variable() 244 {} 245 246 // When this function returns true: 247 // * A notification (or sometimes a spurious OS signal) has been received 248 // * Do not assume that the timeout has not been reached 249 // * Do not assume that the predicate has been changed 250 // 251 // When this function returns false: 252 // * The timeout has been reached 253 // * Do not assume that a notification has not been received 254 // * Do not assume that the predicate has not been changed 255 template<typename lock_type> 256 bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout) 257 { 258 relocker<lock_type> locker(lock); 259 entry_manager entry(get_wait_entry(), internal_mutex); 260 locker.unlock(); 261 262 bool woken=false; 263 while(!woken) 264 { 265 if(!entry->interruptible_wait(timeout)) 266 { 267 return false; 268 } 269 270 woken=entry->woken(); 271 } 272 // do it here to avoid throwing on the destructor 273 entry.remove_waiter_and_reset(); 274 locker.lock(); 275 return true; 276 } 277 278 void notify_one() BOOST_NOEXCEPT 279 { 280 if(detail::interlocked_read_acquire(&total_count)) 281 { 282 boost::lock_guard<boost::mutex> internal_lock(internal_mutex); 283 if(!total_count) 284 { 285 return; 286 } 287 wake_waiters(1); 288 289 for(generation_list::iterator it=generations.begin(), 290 end=generations.end(); 291 it!=end;++it) 292 { 293 (*it)->release(1); 294 } 295 generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); 296 } 297 } 298 299 void notify_all() BOOST_NOEXCEPT 300 { 301 if(detail::interlocked_read_acquire(&total_count)) 302 { 303 boost::lock_guard<boost::mutex> internal_lock(internal_mutex); 304 if(!total_count) 305 { 306 return; 307 } 308 wake_waiters(total_count); 309 for(generation_list::iterator it=generations.begin(), 310 end=generations.end(); 311 it!=end;++it) 312 { 313 (*it)->release_waiters(); 314 } 315 generations.clear(); 316 wake_sem=detail::win32::handle(0); 317 } 318 } 319 320 }; 321 } 322 323 class condition_variable: 324 private detail::basic_condition_variable 325 { 326 public: 327 BOOST_THREAD_NO_COPYABLE(condition_variable) 328 condition_variable() 329 {} 330 331 using detail::basic_condition_variable::do_wait_until; 332 using detail::basic_condition_variable::notify_one; 333 using detail::basic_condition_variable::notify_all; 334 335 void wait(unique_lock<mutex>& m) 336 { 337 do_wait_until(m, detail::internal_platform_timepoint::getMax()); 338 } 339 340 template<typename predicate_type> 341 void wait(unique_lock<mutex>& m,predicate_type pred) 342 { 343 while (!pred()) 344 { 345 wait(m); 346 } 347 } 348 349 #if defined BOOST_THREAD_USES_DATETIME 350 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time) 351 { 352 // The system time may jump while this function is waiting. To compensate for this and time 353 // out near the correct time, we could call do_wait_until() in a loop with a short timeout 354 // and recheck the time remaining each time through the loop. However, because we can't 355 // check the predicate each time do_wait_until() completes, this introduces the possibility 356 // of not exiting the function when a notification occurs, since do_wait_until() may report 357 // that it timed out even though a notification was received. The best this function can do 358 // is report correctly whether or not it reached the timeout time. 359 const detail::real_platform_timepoint ts(abs_time); 360 const detail::platform_duration d(ts - detail::real_platform_clock::now()); 361 do_wait_until(m, detail::internal_platform_clock::now() + d); 362 return ts > detail::real_platform_clock::now(); 363 } 364 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time) 365 { 366 return timed_wait(m, system_time(abs_time)); 367 } 368 template<typename duration_type> 369 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) 370 { 371 if (wait_duration.is_pos_infinity()) 372 { 373 wait(m); 374 return true; 375 } 376 if (wait_duration.is_special()) 377 { 378 return true; 379 } 380 const detail::platform_duration d(wait_duration); 381 return do_wait_until(m, detail::internal_platform_clock::now() + d); 382 } 383 384 template<typename predicate_type> 385 bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred) 386 { 387 // The system time may jump while this function is waiting. To compensate for this 388 // and time out near the correct time, we call do_wait_until() in a loop with a 389 // short timeout and recheck the time remaining each time through the loop. 390 const detail::real_platform_timepoint ts(abs_time); 391 while (!pred()) 392 { 393 detail::platform_duration d(ts - detail::real_platform_clock::now()); 394 if (d <= detail::platform_duration::zero()) break; // timeout occurred 395 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 396 do_wait_until(m, detail::internal_platform_clock::now() + d); 397 } 398 return pred(); 399 } 400 template<typename predicate_type> 401 bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred) 402 { 403 return timed_wait(m, system_time(abs_time), pred); 404 } 405 template<typename duration_type,typename predicate_type> 406 bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred) 407 { 408 if (wait_duration.is_pos_infinity()) 409 { 410 while (!pred()) 411 { 412 wait(m); 413 } 414 return true; 415 } 416 if (wait_duration.is_special()) 417 { 418 return pred(); 419 } 420 const detail::platform_duration d(wait_duration); 421 const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); 422 while (!pred()) 423 { 424 if (!do_wait_until(m, ts)) break; // timeout occurred 425 } 426 return pred(); 427 } 428 #endif 429 #ifdef BOOST_THREAD_USES_CHRONO 430 template <class Duration> 431 cv_status 432 wait_until( 433 unique_lock<mutex>& lock, 434 const chrono::time_point<detail::internal_chrono_clock, Duration>& t) 435 { 436 const detail::internal_platform_timepoint ts(t); 437 if (do_wait_until(lock, ts)) return cv_status::no_timeout; 438 else return cv_status::timeout; 439 } 440 441 template <class Clock, class Duration> 442 cv_status 443 wait_until( 444 unique_lock<mutex>& lock, 445 const chrono::time_point<Clock, Duration>& t) 446 { 447 // The system time may jump while this function is waiting. To compensate for this and time 448 // out near the correct time, we could call do_wait_until() in a loop with a short timeout 449 // and recheck the time remaining each time through the loop. However, because we can't 450 // check the predicate each time do_wait_until() completes, this introduces the possibility 451 // of not exiting the function when a notification occurs, since do_wait_until() may report 452 // that it timed out even though a notification was received. The best this function can do 453 // is report correctly whether or not it reached the timeout time. 454 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 455 common_duration d(t - Clock::now()); 456 do_wait_until(lock, detail::internal_chrono_clock::now() + d); 457 if (t > Clock::now()) return cv_status::no_timeout; 458 else return cv_status::timeout; 459 } 460 461 template <class Rep, class Period> 462 cv_status 463 wait_for( 464 unique_lock<mutex>& lock, 465 const chrono::duration<Rep, Period>& d) 466 { 467 return wait_until(lock, chrono::steady_clock::now() + d); 468 } 469 470 template <class Duration, class Predicate> 471 bool 472 wait_until( 473 unique_lock<mutex>& lock, 474 const chrono::time_point<detail::internal_chrono_clock, Duration>& t, 475 Predicate pred) 476 { 477 const detail::internal_platform_timepoint ts(t); 478 while (!pred()) 479 { 480 if (!do_wait_until(lock, ts)) break; // timeout occurred 481 } 482 return pred(); 483 } 484 485 template <class Clock, class Duration, class Predicate> 486 bool 487 wait_until( 488 unique_lock<mutex>& lock, 489 const chrono::time_point<Clock, Duration>& t, 490 Predicate pred) 491 { 492 // The system time may jump while this function is waiting. To compensate for this 493 // and time out near the correct time, we call do_wait_until() in a loop with a 494 // short timeout and recheck the time remaining each time through the loop. 495 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 496 while (!pred()) 497 { 498 common_duration d(t - Clock::now()); 499 if (d <= common_duration::zero()) break; // timeout occurred 500 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 501 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); 502 } 503 return pred(); 504 } 505 506 template <class Rep, class Period, class Predicate> 507 bool 508 wait_for( 509 unique_lock<mutex>& lock, 510 const chrono::duration<Rep, Period>& d, 511 Predicate pred) 512 { 513 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); 514 } 515 #endif 516 }; 517 518 class condition_variable_any: 519 private detail::basic_condition_variable 520 { 521 public: 522 BOOST_THREAD_NO_COPYABLE(condition_variable_any) 523 condition_variable_any() 524 {} 525 526 using detail::basic_condition_variable::do_wait_until; 527 using detail::basic_condition_variable::notify_one; 528 using detail::basic_condition_variable::notify_all; 529 530 template<typename lock_type> 531 void wait(lock_type& m) 532 { 533 do_wait_until(m, detail::internal_platform_timepoint::getMax()); 534 } 535 536 template<typename lock_type,typename predicate_type> 537 void wait(lock_type& m,predicate_type pred) 538 { 539 while (!pred()) 540 { 541 wait(m); 542 } 543 } 544 545 #if defined BOOST_THREAD_USES_DATETIME 546 template<typename lock_type> 547 bool timed_wait(lock_type& m,boost::system_time const& abs_time) 548 { 549 // The system time may jump while this function is waiting. To compensate for this and time 550 // out near the correct time, we could call do_wait_until() in a loop with a short timeout 551 // and recheck the time remaining each time through the loop. However, because we can't 552 // check the predicate each time do_wait_until() completes, this introduces the possibility 553 // of not exiting the function when a notification occurs, since do_wait_until() may report 554 // that it timed out even though a notification was received. The best this function can do 555 // is report correctly whether or not it reached the timeout time. 556 const detail::real_platform_timepoint ts(abs_time); 557 const detail::platform_duration d(ts - detail::real_platform_clock::now()); 558 do_wait_until(m, detail::internal_platform_clock::now() + d); 559 return ts > detail::real_platform_clock::now(); 560 } 561 562 template<typename lock_type> 563 bool timed_wait(lock_type& m,boost::xtime const& abs_time) 564 { 565 return timed_wait(m, system_time(abs_time)); 566 } 567 568 template<typename lock_type,typename duration_type> 569 bool timed_wait(lock_type& m,duration_type const& wait_duration) 570 { 571 if (wait_duration.is_pos_infinity()) 572 { 573 wait(m); 574 return true; 575 } 576 if (wait_duration.is_special()) 577 { 578 return true; 579 } 580 const detail::platform_duration d(wait_duration); 581 return do_wait_until(m, detail::internal_platform_clock::now() + d); 582 } 583 584 template<typename lock_type,typename predicate_type> 585 bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred) 586 { 587 // The system time may jump while this function is waiting. To compensate for this 588 // and time out near the correct time, we call do_wait_until() in a loop with a 589 // short timeout and recheck the time remaining each time through the loop. 590 const detail::real_platform_timepoint ts(abs_time); 591 while (!pred()) 592 { 593 detail::platform_duration d(ts - detail::real_platform_clock::now()); 594 if (d <= detail::platform_duration::zero()) break; // timeout occurred 595 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 596 do_wait_until(m, detail::internal_platform_clock::now() + d); 597 } 598 return pred(); 599 } 600 601 template<typename lock_type,typename predicate_type> 602 bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) 603 { 604 return timed_wait(m, system_time(abs_time), pred); 605 } 606 607 template<typename lock_type,typename duration_type,typename predicate_type> 608 bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) 609 { 610 if (wait_duration.is_pos_infinity()) 611 { 612 while (!pred()) 613 { 614 wait(m); 615 } 616 return true; 617 } 618 if (wait_duration.is_special()) 619 { 620 return pred(); 621 } 622 const detail::platform_duration d(wait_duration); 623 const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); 624 while (!pred()) 625 { 626 if (!do_wait_until(m, ts)) break; // timeout occurred 627 } 628 return pred(); 629 } 630 #endif 631 #ifdef BOOST_THREAD_USES_CHRONO 632 template <class lock_type,class Duration> 633 cv_status 634 wait_until( 635 lock_type& lock, 636 const chrono::time_point<detail::internal_chrono_clock, Duration>& t) 637 { 638 const detail::internal_platform_timepoint ts(t); 639 if (do_wait_until(lock, ts)) return cv_status::no_timeout; 640 else return cv_status::timeout; 641 } 642 643 template <class lock_type, class Clock, class Duration> 644 cv_status 645 wait_until( 646 lock_type& lock, 647 const chrono::time_point<Clock, Duration>& t) 648 { 649 // The system time may jump while this function is waiting. To compensate for this and time 650 // out near the correct time, we could call do_wait_until() in a loop with a short timeout 651 // and recheck the time remaining each time through the loop. However, because we can't 652 // check the predicate each time do_wait_until() completes, this introduces the possibility 653 // of not exiting the function when a notification occurs, since do_wait_until() may report 654 // that it timed out even though a notification was received. The best this function can do 655 // is report correctly whether or not it reached the timeout time. 656 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 657 common_duration d(t - Clock::now()); 658 do_wait_until(lock, detail::internal_chrono_clock::now() + d); 659 if (t > Clock::now()) return cv_status::no_timeout; 660 else return cv_status::timeout; 661 } 662 663 template <class lock_type, class Rep, class Period> 664 cv_status 665 wait_for( 666 lock_type& lock, 667 const chrono::duration<Rep, Period>& d) 668 { 669 return wait_until(lock, chrono::steady_clock::now() + d); 670 } 671 672 template <class lock_type, class Clock, class Duration, class Predicate> 673 bool 674 wait_until( 675 lock_type& lock, 676 const chrono::time_point<detail::internal_chrono_clock, Duration>& t, 677 Predicate pred) 678 { 679 const detail::internal_platform_timepoint ts(t); 680 while (!pred()) 681 { 682 if (!do_wait_until(lock, ts)) break; // timeout occurred 683 } 684 return pred(); 685 } 686 687 template <class lock_type, class Clock, class Duration, class Predicate> 688 bool 689 wait_until( 690 lock_type& lock, 691 const chrono::time_point<Clock, Duration>& t, 692 Predicate pred) 693 { 694 // The system time may jump while this function is waiting. To compensate for this 695 // and time out near the correct time, we call do_wait_until() in a loop with a 696 // short timeout and recheck the time remaining each time through the loop. 697 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 698 while (!pred()) 699 { 700 common_duration d(t - Clock::now()); 701 if (d <= common_duration::zero()) break; // timeout occurred 702 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 703 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); 704 } 705 return pred(); 706 } 707 708 template <class lock_type, class Rep, class Period, class Predicate> 709 bool 710 wait_for( 711 lock_type& lock, 712 const chrono::duration<Rep, Period>& d, 713 Predicate pred) 714 { 715 return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); 716 } 717 #endif 718 }; 719 720 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); 721 } 722 723 #include <boost/config/abi_suffix.hpp> 724 725 #endif 726