diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 18db1363..ccf29b22 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -13,7 +13,6 @@ #include #include #include "interlocked_read.hpp" -#include #include namespace boost @@ -112,136 +111,65 @@ namespace boost }; - protected: - struct timeout + template + void start_wait_loop_first_time(relocker& locker, + detail::win32::handle_manager& local_wake_sem) { - 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 + locker.unlock(); + if(!wake_sem) { - 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 + void start_wait_loop(relocker& locker, + detail::win32::handle_manager& local_wake_sem, + detail::win32::handle_manager& sem) + { + boost::mutex::scoped_lock internal_lock(internal_mutex); + detail::interlocked_write_release(&total_count,total_count+1); + if(!local_wake_sem) + { + start_wait_loop_first_time(locker,local_wake_sem); + } + if(!generations[0].semaphore) + { + generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + BOOST_ASSERT(generations[0].semaphore); + } + ++generations[0].count; + sem=detail::win32::duplicate_handle(generations[0].semaphore); + } + protected: template bool do_wait(lock_type& lock,timeout wait_until) { detail::win32::handle_manager local_wake_sem; detail::win32::handle_manager sem; - bool first_loop=true; bool woken=false; relocker locker(lock); while(!woken) { + start_wait_loop(locker,local_wake_sem,sem); + + if(!this_thread::interruptible_wait(sem,wait_until)) { - boost::mutex::scoped_lock internal_lock(internal_mutex); - detail::interlocked_write_release(&total_count,total_count+1); - if(first_loop) - { - locker.unlock(); - if(!wake_sem) - { - wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); - BOOST_ASSERT(wake_sem); - } - local_wake_sem=detail::win32::duplicate_handle(wake_sem); - - if(generations[0].notified) - { - shift_generations_down(); - } - else if(!active_generation_count) - { - active_generation_count=1; - } - - first_loop=false; - } - if(!generations[0].semaphore) - { - generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX); - BOOST_ASSERT(generations[0].semaphore); - } - ++generations[0].count; - sem=detail::win32::duplicate_handle(generations[0].semaphore); - } - while(true) - { - 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; - } + return false; } unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0); @@ -333,7 +261,7 @@ namespace boost public: void wait(unique_lock& m) { - do_wait(m,timeout::sentinel()); + do_wait(m,detail::timeout::sentinel()); } template @@ -372,7 +300,7 @@ namespace boost template void wait(lock_type& m) { - do_wait(m,timeout::sentinel()); + do_wait(m,detail::timeout::sentinel()); } template diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index 992491d5..73cdc490 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -48,10 +48,10 @@ namespace boost } state_data state; - void* semaphores[2]; - void* &unlock_sem; - void* &exclusive_sem; - void* upgrade_sem; + detail::win32::handle semaphores[2]; + detail::win32::handle &unlock_sem; + detail::win32::handle &exclusive_sem; + detail::win32::handle upgrade_sem; void release_waiters(state_data old_state) { diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index 16315b00..93a44792 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace boost { @@ -73,6 +74,82 @@ namespace boost }; typedef boost::intrusive_ptr thread_data_ptr; + + 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(is_sentinel()) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed #include #include @@ -15,6 +18,7 @@ #include #include #include +#include namespace boost { @@ -63,11 +67,11 @@ namespace boost typedef void* uintptr_t; inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), - void* arglist, unsigned initflag, unsigned* thrdaddr) + void* arglist, unsigned initflag, unsigned* thrdaddr) { DWORD threadID; HANDLE hthread=CreateThread(static_cast(security),stack_size,ThreadProxy, - new ThreadProxyData(start_address,arglist),initflag,&threadID); + new ThreadProxyData(start_address,arglist),initflag,&threadID); if (hthread!=0) *thrdaddr=threadID; return reinterpret_cast(hthread); @@ -287,7 +291,7 @@ namespace boost detail::thread_data_ptr local_thread_info=get_thread_info(); if(local_thread_info) { - this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite); + this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); release_handle(); } } @@ -353,13 +357,57 @@ namespace boost namespace this_thread { - bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds) + namespace { - detail::win32::handle handles[2]={0}; + LARGE_INTEGER get_due_time(detail::timeout const& target_time) + { + LARGE_INTEGER due_time={0}; + if(target_time.relative) + { + unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start; + LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds); + LONGLONG const hundred_nanoseconds_in_one_millisecond=10000; + + if(remaining_milliseconds>0) + { + due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond); + } + } + else + { + SYSTEMTIME target_system_time={0}; + target_system_time.wYear=target_time.abs_time.date().year(); + target_system_time.wMonth=target_time.abs_time.date().month(); + target_system_time.wDay=target_time.abs_time.date().day(); + target_system_time.wHour=target_time.abs_time.time_of_day().hours(); + target_system_time.wMinute=target_time.abs_time.time_of_day().minutes(); + target_system_time.wSecond=target_time.abs_time.time_of_day().seconds(); + + if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time))) + { + due_time.QuadPart=0; + } + else + { + long const hundred_nanoseconds_in_one_second=10000000; + due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second()); + } + } + return due_time; + } + } + + + bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time) + { + detail::win32::handle handles[3]={0}; unsigned handle_count=0; + unsigned wait_handle_index=~0U; unsigned interruption_index=~0U; + unsigned timeout_index=~0U; if(handle_to_wait_for!=detail::win32::invalid_handle_value) { + wait_handle_index=handle_count; handles[handle_count++]=handle_to_wait_for; } if(get_current_thread_data() && get_current_thread_data()->interruption_enabled) @@ -367,24 +415,79 @@ namespace boost interruption_index=handle_count; handles[handle_count++]=get_current_thread_data()->interruption_handle; } + + detail::win32::handle_manager timer_handle; + +#ifndef UNDER_CE + unsigned const min_timer_wait_period=20; + + if(!target_time.is_sentinel()) + { + detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds(); + if(time_left.milliseconds > min_timer_wait_period) + { + // for a long-enough timeout, use a waitable timer (which tracks clock changes) + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) + { + LARGE_INTEGER due_time=get_due_time(target_time); + + bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0; + if(set_time_succeeded) + { + timeout_index=handle_count; + handles[handle_count++]=timer_handle; + } + } + } + else if(!target_time.relative) + { + // convert short absolute-time timeouts into relative ones, so we don't race against clock changes + target_time=detail::timeout(time_left.milliseconds); + } + } +#endif - if(handle_count) + bool const using_timer=timeout_index!=~0u; + detail::timeout::remaining_time time_left(0); + + do { - unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds); - if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index) + if(!using_timer) { - return true; + time_left=target_time.remaining_milliseconds(); } - else if(notified_index==interruption_index) + + if(handle_count) { - detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); - throw thread_interrupted(); + unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds); + if(notified_indexinterruption_handle); + throw thread_interrupted(); + } + else if(notified_index==timeout_index) + { + return false; + } + } + } + else + { + detail::win32::Sleep(time_left.milliseconds); + } + if(target_time.relative) + { + target_time.milliseconds-=detail::timeout::max_non_infinite_wait; } } - else - { - detail::win32::Sleep(milliseconds); - } + while(time_left.more); return false; } diff --git a/src/win32/tss_pe.cpp b/src/win32/tss_pe.cpp index 4528b90f..dec71c3b 100644 --- a/src/win32/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -230,13 +230,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { - OutputDebugString("on_tls_callback\n"); - switch (dwReason) { case DLL_THREAD_DETACH: { - OutputDebugString("on_tls_callback: thread_exit\n"); on_thread_exit(); break; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 209e6b07..be5fea7b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,4 +1,5 @@ # (C) Copyright William E. Kempf 2001. +# (C) Copyright 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) # @@ -35,6 +36,9 @@ rule thread-run ( sources ) test-suite "threads" : [ thread-run test_thread.cpp ] [ thread-run test_mutex.cpp ] + [ thread-run test_condition_notify_one.cpp ] + [ thread-run test_condition_timed_wait_times_out.cpp ] + [ thread-run test_condition_notify_all.cpp ] [ thread-run test_condition.cpp ] [ thread-run test_tss.cpp ] [ thread-run test_once.cpp ] diff --git a/test/condition_test_common.hpp b/test/condition_test_common.hpp new file mode 100644 index 00000000..df7d5edc --- /dev/null +++ b/test/condition_test_common.hpp @@ -0,0 +1,95 @@ +#ifndef CONDITION_TEST_COMMON_HPP +#define CONDITION_TEST_COMMON_HPP +// 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) + +#include +#include +#include + +unsigned const timeout_seconds=5; + +struct wait_for_flag +{ + boost::mutex mutex; + boost::condition_variable cond_var; + bool flag; + unsigned woken; + + wait_for_flag(): + flag(false),woken(0) + {} + + struct check_flag + { + bool const& flag; + + check_flag(bool const& flag_): + flag(flag_) + {} + + bool operator()() const + { + return flag; + } + }; + + + void wait_without_predicate() + { + boost::mutex::scoped_lock lock(mutex); + while(!flag) + { + cond_var.wait(lock); + } + ++woken; + } + + void wait_with_predicate() + { + boost::mutex::scoped_lock lock(mutex); + cond_var.wait(lock,check_flag(flag)); + if(flag) + { + ++woken; + } + } + + void timed_wait_without_predicate() + { + boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); + + boost::mutex::scoped_lock lock(mutex); + while(!flag) + { + if(!cond_var.timed_wait(lock,timeout)) + { + return; + } + } + ++woken; + } + + void timed_wait_with_predicate() + { + boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); + boost::mutex::scoped_lock lock(mutex); + if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag) + { + ++woken; + } + } + void relative_timed_wait_with_predicate() + { + boost::mutex::scoped_lock lock(mutex); + if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag) + { + ++woken; + } + } +}; + + +#endif diff --git a/test/test_barrier.cpp b/test/test_barrier.cpp index bccd346f..e4879704 100644 --- a/test/test_barrier.cpp +++ b/test/test_barrier.cpp @@ -52,7 +52,7 @@ void test_barrier() throw; } - BOOST_CHECK(global_parameter == 5); + BOOST_CHECK_EQUAL(global_parameter,5); } boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/test_condition.cpp b/test/test_condition.cpp index 17182e9f..96b1e86e 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -94,66 +94,6 @@ void condition_test_waits(condition_test_data* data) data->condition.notify_one(); } -void do_test_condition_notify_one() -{ - condition_test_data data; - - boost::thread thread(bind(&condition_test_thread, &data)); - - { - boost::mutex::scoped_lock lock(data.mutex); - BOOST_CHECK(lock ? true : false); - data.notified++; - data.condition.notify_one(); - } - - thread.join(); - BOOST_CHECK_EQUAL(data.awoken, 1); -} - -void test_condition_notify_one() -{ - timed_test(&do_test_condition_notify_one, 100, execution_monitor::use_mutex); -} - -void do_test_condition_notify_all() -{ - const int NUMTHREADS = 5; - boost::thread_group threads; - condition_test_data data; - - try - { - for (int i = 0; i < NUMTHREADS; ++i) - threads.create_thread(bind(&condition_test_thread, &data)); - - { - boost::mutex::scoped_lock lock(data.mutex); - BOOST_CHECK(lock ? true : false); - data.notified++; - data.condition.notify_all(); - } - - threads.join_all(); - } - catch(...) - { - threads.interrupt_all(); - threads.join_all(); - throw; - } - - BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); -} - -void test_condition_notify_all() -{ - // We should have already tested notify_one here, so - // a timed test with the default execution_monitor::use_condition - // should be OK, and gives the fastest performance - timed_test(&do_test_condition_notify_all, 100); -} - void do_test_condition_waits() { condition_test_data data; @@ -235,43 +175,13 @@ 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*[]) { boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Threads: condition test suite"); - test->add(BOOST_TEST_CASE(&test_condition_notify_one)); - 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; } diff --git a/test/test_condition_notify_all.cpp b/test/test_condition_notify_all.cpp new file mode 100644 index 00000000..22074b44 --- /dev/null +++ b/test/test_condition_notify_all.cpp @@ -0,0 +1,180 @@ +// 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) + +#include + +#include + +#include + +#include +#include "condition_test_common.hpp" + +unsigned const number_of_test_threads=5; + +void do_test_condition_notify_all_wakes_from_wait() +{ + wait_for_flag data; + + boost::thread_group group; + + try + { + for(unsigned i=0;iadd(BOOST_TEST_CASE(&test_condition_notify_all)); + + return test; +} diff --git a/test/test_condition_notify_one.cpp b/test/test_condition_notify_one.cpp new file mode 100644 index 00000000..45447bd4 --- /dev/null +++ b/test/test_condition_notify_one.cpp @@ -0,0 +1,113 @@ +// 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) + +#include + +#include + +#include + +#include +#include "condition_test_common.hpp" + +void do_test_condition_notify_one_wakes_from_wait() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_timed_wait() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate() +{ + wait_for_flag data; + + boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + data.flag=true; + data.cond_var.notify_one(); + } + + thread.join(); + BOOST_CHECK(data.woken); +} + +void test_condition_notify_one() +{ + timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); + timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: condition test suite"); + + test->add(BOOST_TEST_CASE(&test_condition_notify_one)); + + return test; +} diff --git a/test/test_condition_timed_wait_times_out.cpp b/test/test_condition_timed_wait_times_out.cpp new file mode 100644 index 00000000..128922a4 --- /dev/null +++ b/test/test_condition_timed_wait_times_out.cpp @@ -0,0 +1,89 @@ +// 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) + +#include + +#include +#include + +#include +#include "util.inl" + +bool fake_predicate() +{ + return false; +} + +unsigned const timeout_seconds=5; +unsigned const timeout_grace=1; +boost::posix_time::milliseconds const timeout_resolution(100); + + +void do_test_timed_wait_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + while(cond.timed_wait(lock,timeout)); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_timed_wait_with_predicate_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + boost::mutex::scoped_lock lock(m); + boost::system_time const start=boost::get_system_time(); + boost::system_time const timeout=start+delay; + + bool const res=cond.timed_wait(lock,timeout,fake_predicate); + + boost::system_time const end=boost::get_system_time(); + BOOST_CHECK(!res); + BOOST_CHECK((delay-timeout_resolution)<=(end-start)); +} + +void do_test_relative_timed_wait_with_predicate_times_out() +{ + boost::condition_variable cond; + boost::mutex m; + + boost::posix_time::seconds const delay(timeout_seconds); + 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-timeout_resolution)<=(end-start)); +} + + +void test_timed_wait_times_out() +{ + timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); + timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: condition test suite"); + + test->add(BOOST_TEST_CASE(&test_timed_wait_times_out)); + + return test; +} diff --git a/test/test_shared_mutex.cpp b/test/test_shared_mutex.cpp index b43a186e..a5627835 100644 --- a/test/test_shared_mutex.cpp +++ b/test/test_shared_mutex.cpp @@ -466,7 +466,7 @@ void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() unsigned unblocked_count=0; boost::mutex::scoped_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); - boost::thread::sleep(delay(1)); + boost::this_thread::sleep(boost::posix_time::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); bool const try_succeeded=rw_mutex.try_lock_shared(); diff --git a/test/util.inl b/test/util.inl index 32e7c77a..417b255d 100644 --- a/test/util.inl +++ b/test/util.inl @@ -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) @@ -154,6 +155,26 @@ thread_binder bind(const F& func, const T& param) { return thread_binder(func, param); } + +template +class thread_member_binder +{ +public: + thread_member_binder(R (T::*func)(), T& param) + : func(func), param(param) { } + void operator()() const { (param.*func)(); } + +private: + R (T::*func)(); + T& param; +}; + + +template +thread_member_binder bind(R (T::*func)(), T& param) +{ + return thread_member_binder(func, param); +} } // namespace #endif