From 2a1e4496bac692ae00004242841920bbdc8cfdca Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Wed, 28 Nov 2007 22:03:59 +0000 Subject: [PATCH] Merged revisions 41399-41442 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r41400 | igaztanaga | 2007-11-26 08:34:13 -0800 (Mon, 26 Nov 2007) | 1 line Added missing #include ........ r41401 | anthonyw | 2007-11-26 09:01:08 -0800 (Mon, 26 Nov 2007) | 1 line once_flag uses zero-initialization on POSIX as well as windows ........ r41402 | niels_dekker | 2007-11-26 09:36:52 -0800 (Mon, 26 Nov 2007) | 1 line Marked value_init_test failures on Borland C++ as "expected failures", as discussed with Fernando Cacciola. ........ r41404 | rwgk | 2007-11-26 12:46:28 -0800 (Mon, 26 Nov 2007) | 1 line g++ 4.3.0 compatibility (4.3.0 20071125 (experimental)) ........ r41405 | anthonyw | 2007-11-26 13:15:04 -0800 (Mon, 26 Nov 2007) | 1 line reverted accidental checkin of new timed_wait functions on condition_variable ........ r41406 | nasonov | 2007-11-26 13:29:04 -0800 (Mon, 26 Nov 2007) | 3 lines Remove redundant BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION. ........ r41407 | chris_kohlhoff | 2007-11-26 13:29:38 -0800 (Mon, 26 Nov 2007) | 3 lines WinCE doesn't work with all multicast addresses, and even though it doesn't support the multicast::enable_loopback option you can still get the value. ........ r41408 | dave | 2007-11-26 14:01:50 -0800 (Mon, 26 Nov 2007) | 2 lines Try to extend the workaround to SunPro 5.9, since we're marked as not working on 5.8 ........ r41409 | dave | 2007-11-26 17:40:01 -0800 (Mon, 26 Nov 2007) | 3 lines Allow Sun-5.7 and Sun-5.8 to fail loudly for Boost.Python so I can see what's really wrong. ........ r41413 | anthonyw | 2007-11-27 06:24:29 -0800 (Tue, 27 Nov 2007) | 1 line add support for relative timeouts to condition timed_wait ........ r41414 | grafik | 2007-11-27 09:53:56 -0800 (Tue, 27 Nov 2007) | 1 line Remove non-existent option info. ........ r41415 | grafik | 2007-11-27 09:55:13 -0800 (Tue, 27 Nov 2007) | 1 line Add some utility output formatting functions. ........ r41416 | grafik | 2007-11-27 09:57:15 -0800 (Tue, 27 Nov 2007) | 1 line Check empty string invariants, instead of assuming all strings are allocated. And reset strings when they are freed. ........ r41417 | grafik | 2007-11-27 09:58:50 -0800 (Tue, 27 Nov 2007) | 1 line Fix buffer overrun bug in expanding @() subexpressions. ........ r41418 | hkaiser | 2007-11-27 10:18:10 -0800 (Tue, 27 Nov 2007) | 1 line Wave: Fixed gcc warning, bumped version number. ........ r41419 | djenkins | 2007-11-27 10:57:48 -0800 (Tue, 27 Nov 2007) | 1 line Changes for msvc-9.0 /clr flag ........ r41420 | djenkins | 2007-11-27 10:59:06 -0800 (Tue, 27 Nov 2007) | 1 line Changes for msvc-9.0 /clr flag ........ r41423 | niels_dekker | 2007-11-27 13:34:08 -0800 (Tue, 27 Nov 2007) | 1 line Added value_init test for struct as used in MSVC bug report regarding value-initialization. ........ r41429 | noel_belcourt | 2007-11-27 18:27:13 -0800 (Tue, 27 Nov 2007) | 3 lines Fix pathscale rpath issue per Alain Minussi's suggestion. ........ r41430 | grafik | 2007-11-27 23:08:13 -0800 (Tue, 27 Nov 2007) | 1 line Add test for result status values of simple actions, i.e. empty actions. ........ r41431 | grafik | 2007-11-27 23:21:49 -0800 (Tue, 27 Nov 2007) | 19 lines build-system.jam * Reflect added start/end timestamps for actions in xml output. And update action rules for new args. execcmd.h * Add start/end timestamps to action timing info. execnt.c * Fix filetime_seconds calculation when time is larger than low 32 bit value. * Add calc of C time_t from Windows FILETIME. * Add start/end timestamps recording to action timing info. execunix.c * Add start/end timestamps recording to action timing info. jam.c * Change JAMDATE to use common ISO date format. make1.c * Redo __TIMING_RULE__ and __ACTION__RULE__ invocations to new argument ordering and added end/result timestamp values. ........ r41432 | chris_kohlhoff | 2007-11-28 05:26:33 -0800 (Wed, 28 Nov 2007) | 3 lines Make async operations fail with an error if the socket descriptor doesn't fit into the select call's fd_set. ........ r41433 | bgubenko | 2007-11-28 07:33:16 -0800 (Wed, 28 Nov 2007) | 1 line add "gcc*hpux*" toolset for serialization library bug on big endian platforms ........ r41436 | niels_dekker | 2007-11-28 09:19:37 -0800 (Wed, 28 Nov 2007) | 1 line Added tests for two more struct types to value_init_test -- discussed with Fernando Cacciola ........ r41439 | bgubenko | 2007-11-28 11:04:53 -0800 (Wed, 28 Nov 2007) | 1 line add "-lrt" for acc* toolsets ........ r41440 | grafik | 2007-11-28 12:24:17 -0800 (Wed, 28 Nov 2007) | 1 line Fix for latest Doxygen namespace file names. And support for method groups. From Samuel Debionne. ........ [SVN r41444] --- .../thread/pthread/condition_variable.hpp | 8 +- .../thread/pthread/condition_variable_fwd.hpp | 8 ++ include/boost/thread/pthread/once.hpp | 12 +- .../boost/thread/win32/condition_variable.hpp | 134 +++++++++++++++--- .../boost/thread/win32/thread_primitives.hpp | 3 + src/pthread/once.cpp | 5 +- test/test_condition.cpp | 50 ++++++- 7 files changed, 189 insertions(+), 31 deletions(-) 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; }