diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index 7c467f65..754f0ac3 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -5,11 +5,9 @@ // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007 Anthony Williams -#include #include #include #include -#include #include #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" @@ -150,6 +148,12 @@ namespace boost return true; } + template + bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred) + { + return timed_wait(m,system_time(wait_until),pred); + } + template bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) { diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 29b5a128..ca45e54b 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -6,8 +6,10 @@ // (C) Copyright 2007 Anthony Williams #include +#include #include #include +#include namespace boost { @@ -44,6 +46,12 @@ namespace boost return true; } + template + bool timed_wait(unique_lock& m,xtime const& wait_until,predicate_type pred) + { + return timed_wait(m,system_time(wait_until),pred); + } + template bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) { diff --git a/include/boost/thread/pthread/once.hpp b/include/boost/thread/pthread/once.hpp index de0dc7a5..f342ed1d 100644 --- a/include/boost/thread/pthread/once.hpp +++ b/include/boost/thread/pthread/once.hpp @@ -14,8 +14,8 @@ #include #include #include "pthread_mutex_scoped_lock.hpp" -#include #include +#include namespace boost { @@ -32,7 +32,7 @@ namespace boost { BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv; } -#define BOOST_ONCE_INITIAL_FLAG_VALUE -1 +#define BOOST_ONCE_INITIAL_FLAG_VALUE 0 #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} @@ -42,15 +42,15 @@ namespace boost { void call_once(once_flag& flag,Function f) { static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; - static boost::uintmax_t const being_initialized=uninitialized_flag-1; + static boost::uintmax_t const being_initialized=uninitialized_flag+1; boost::uintmax_t const epoch=flag.epoch; boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch(); - if(epoch>this_thread_epoch) + if(epoch=being_initialized) + while(flag.epoch<=being_initialized) { if(flag.epoch==uninitialized_flag) { @@ -66,7 +66,7 @@ namespace boost { BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); throw; } - flag.epoch=++detail::once_global_epoch; + flag.epoch=--detail::once_global_epoch; BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); } else diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 66c45ab1..18db1363 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -13,6 +13,8 @@ #include #include #include "interlocked_read.hpp" +#include +#include namespace boost { @@ -111,8 +113,78 @@ namespace boost protected: + struct timeout + { + unsigned long start; + uintmax_t milliseconds; + bool relative; + boost::system_time abs_time; + + static unsigned long const max_non_infinite_wait=0xfffffffe; + + timeout(uintmax_t milliseconds_): + start(win32::GetTickCount()), + milliseconds(milliseconds_), + relative(true), + abs_time(boost::get_system_time()) + {} + + timeout(boost::system_time const& abs_time_): + start(win32::GetTickCount()), + milliseconds(0), + relative(false), + abs_time(abs_time_) + {} + + struct remaining_time + { + bool more; + unsigned long milliseconds; + + remaining_time(uintmax_t remaining): + more(remaining>max_non_infinite_wait), + milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) + {} + }; + + remaining_time remaining_milliseconds() const + { + if(milliseconds==~uintmax_t(0)) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed - bool do_wait(lock_type& lock,::boost::system_time const& wait_until) + bool do_wait(lock_type& lock,timeout wait_until) { detail::win32::handle_manager local_wake_sem; detail::win32::handle_manager sem; @@ -155,9 +227,21 @@ namespace boost ++generations[0].count; sem=detail::win32::duplicate_handle(generations[0].semaphore); } - if(!this_thread::interruptible_wait(sem,::boost::detail::get_milliseconds_until(wait_until))) + while(true) { - break; + timeout::remaining_time const remaining=wait_until.remaining_milliseconds(); + if(this_thread::interruptible_wait(sem,remaining.milliseconds)) + { + break; + } + else if(!remaining.more) + { + return false; + } + if(wait_until.relative) + { + wait_until.milliseconds-=timeout::max_non_infinite_wait; + } } unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0); @@ -167,6 +251,17 @@ namespace boost } return woken; } + + template + bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!do_wait(m, wait_until)) + return false; + } + return true; + } basic_condition_variable(const basic_condition_variable& other); basic_condition_variable& operator=(const basic_condition_variable& other); @@ -238,7 +333,7 @@ namespace boost public: void wait(unique_lock& m) { - do_wait(m,::boost::detail::get_system_time_sentinel()); + do_wait(m,timeout::sentinel()); } template @@ -256,17 +351,17 @@ namespace boost template bool timed_wait(unique_lock& m,boost::system_time const& wait_until,predicate_type pred) { - while (!pred()) - { - if(!timed_wait(m, wait_until)) - return false; - } - return true; + return do_wait(m,wait_until,pred); + } + template + bool timed_wait(unique_lock& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_wait(m,system_time(wait_until),pred); } template bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) { - return timed_wait(m,get_system_time()+wait_duration,pred); + return do_wait(m,wait_duration.total_milliseconds(),pred); } }; @@ -277,7 +372,7 @@ namespace boost template void wait(lock_type& m) { - do_wait(m,::boost::detail::get_system_time_sentinel()); + do_wait(m,timeout::sentinel()); } template @@ -295,18 +390,19 @@ namespace boost template bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) { - while (!pred()) - { - if(!timed_wait(m, wait_until)) - return false; - } - return true; + return do_wait(m,wait_until,pred); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_wait(m,system_time(wait_until),pred); } template bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) { - return timed_wait(m,get_system_time()+wait_duration,pred); + return timed_wait(m,wait_duration.total_milliseconds(),pred); } }; diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 8f6bc0ed..c8d55d29 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -53,6 +53,7 @@ namespace boost using ::SleepEx; using ::Sleep; using ::QueueUserAPC; + using ::GetTickCount; } } } @@ -120,6 +121,8 @@ namespace boost typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr); __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr); + __declspec(dllimport) unsigned long __stdcall GetTickCount(); + # ifndef UNDER_CE __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); diff --git a/src/pthread/once.cpp b/src/pthread/once.cpp index 6203def2..6e3722a8 100755 --- a/src/pthread/once.cpp +++ b/src/pthread/once.cpp @@ -3,6 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define __STDC_CONSTANT_MACROS #include #include #include @@ -12,7 +13,7 @@ namespace boost { namespace detail { - BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=0; + BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0); BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER; BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER; @@ -41,7 +42,7 @@ namespace boost { data=malloc(sizeof(boost::uintmax_t)); BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data)); - *static_cast(data)=0; + *static_cast(data)=UINTMAX_C(~0); } return *static_cast(data); } diff --git a/test/test_condition.cpp b/test/test_condition.cpp index 2dbe32d0..17182e9f 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf +// Copyright (C) 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,7 +20,7 @@ struct condition_test_data condition_test_data() : notified(0), awoken(0) { } boost::mutex mutex; - boost::condition condition; + boost::condition_variable condition; int notified; int awoken; }; @@ -82,6 +83,15 @@ void condition_test_waits(condition_test_data* data) BOOST_CHECK_EQUAL(data->notified, 4); data->awoken++; data->condition.notify_one(); + + // Test predicate timed_wait with relative timeout + cond_predicate pred_rel(data->notified, 5); + BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel)); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK(pred_rel()); + BOOST_CHECK_EQUAL(data->notified, 5); + data->awoken++; + data->condition.notify_one(); } void do_test_condition_notify_one() @@ -185,10 +195,19 @@ void do_test_condition_waits() data.condition.wait(lock); BOOST_CHECK(lock ? true : false); BOOST_CHECK_EQUAL(data.awoken, 4); + + + boost::thread::sleep(delay(1)); + data.notified++; + data.condition.notify_one(); + while (data.awoken != 5) + data.condition.wait(lock); + BOOST_CHECK(lock ? true : false); + BOOST_CHECK_EQUAL(data.awoken, 5); } thread.join(); - BOOST_CHECK_EQUAL(data.awoken, 4); + BOOST_CHECK_EQUAL(data.awoken, 5); } void test_condition_waits() @@ -216,6 +235,32 @@ void test_condition_wait_is_a_interruption_point() timed_test(&do_test_condition_wait_is_a_interruption_point, 1); } +bool fake_predicate() +{ + return false; +} + + +void do_test_timed_wait_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(5); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + bool const res=cond.timed_wait(lock,delay,fake_predicate); + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-boost::posix_time::milliseconds(10))<=(end-start)); +} + + +void test_timed_wait_times_out() +{ + timed_test(&do_test_timed_wait_times_out, 15); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { @@ -226,6 +271,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_condition_notify_all)); test->add(BOOST_TEST_CASE(&test_condition_waits)); test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point)); + test->add(BOOST_TEST_CASE(&test_timed_wait_times_out)); return test; }