diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 2960822f..d9f63e6c 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -285,7 +285,6 @@ namespace boost // Oops, we weren't called often enough, we're stuck return 0xFFFFFFFF; } -#else #endif inline detail::gettickcount64_t GetTickCount64_() { diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index e02124f3..3392d01f 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -634,7 +634,36 @@ namespace boost } } - +#ifndef UNDER_CE +#if !BOOST_PLAT_WINDOWS_RUNTIME + namespace detail_ + { + typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG); + static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) + { + return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE); + } + static inline setwaitabletimerex_t SetWaitableTimerEx() + { + static setwaitabletimerex_t setwaitabletimerex_impl; + if(setwaitabletimerex_impl) + return setwaitabletimerex_impl; + void *addr=(void *) GetProcAddress( +#if !defined(BOOST_NO_ANSI_APIS) + GetModuleHandleA("KERNEL32.DLL"), +#else + GetModuleHandleW(L"KERNEL32.DLL"), +#endif + "SetWaitableTimerEx"); + if(addr) + setwaitabletimerex_impl=(setwaitabletimerex_t) addr; + else + setwaitabletimerex_impl=&SetWaitableTimerEx_emulation; + return setwaitabletimerex_impl; + } + } +#endif +#endif bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time) { detail::win32::handle handles[4]={0}; @@ -660,32 +689,26 @@ namespace boost #ifndef UNDER_CE #if !BOOST_PLAT_WINDOWS_RUNTIME - unsigned const min_timer_wait_period=20; - + // Preferentially use coalescing timers for better power consumption and timer accuracy if(!target_time.is_sentinel()) { detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds(); - if(time_left.milliseconds > min_timer_wait_period) + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) { - // for a long-enough timeout, use a waitable timer (which tracks clock changes) - timer_handle=CreateWaitableTimer(NULL,false,NULL); - if(timer_handle!=0) + REASON_CONTEXT rc={POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING}; + rc.Reason.SimpleReasonString=(LPWSTR)L"generic"; + ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26 + if(time_left.milliseconds/20>tolerable) // 5% + tolerable=time_left.milliseconds/20; + LARGE_INTEGER due_time=get_due_time(target_time); + bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,&rc,tolerable)!=0; + if(set_time_succeeded) { - 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; - } + 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 #endif @@ -752,32 +775,26 @@ namespace boost #ifndef UNDER_CE #if !BOOST_PLAT_WINDOWS_RUNTIME - unsigned const min_timer_wait_period=20; - + // Preferentially use coalescing timers for better power consumption and timer accuracy if(!target_time.is_sentinel()) { detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds(); - if(time_left.milliseconds > min_timer_wait_period) + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) { - // for a long-enough timeout, use a waitable timer (which tracks clock changes) - timer_handle=CreateWaitableTimer(NULL,false,NULL); - if(timer_handle!=0) + REASON_CONTEXT rc={POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING}; + rc.Reason.SimpleReasonString=(LPWSTR)L"generic"; + ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26 + if(time_left.milliseconds/20>tolerable) // 5% + tolerable=time_left.milliseconds/20; + LARGE_INTEGER due_time=get_due_time(target_time); + bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,&rc,tolerable)!=0; + if(set_time_succeeded) { - 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; - } + 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 #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 68d439bc..db0b3392 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -294,7 +294,6 @@ rule thread-compile ( sources : reqs * : name ) [ thread-run test_7571.cpp ] [ thread-run test_9319.cpp ] #[ thread-run test_9711.cpp ] this test is invalid and should not work :( - [ thread-run test_9856.cpp ] [ thread-compile test_10963.cpp : : test_10963_c ] [ thread-run test_10964.cpp ] ; @@ -912,6 +911,7 @@ rule thread-compile ( sources : reqs * : name ) [ thread-run test_9192.cpp ] #[ thread-run test_9303.cpp ] #[ thread-run test_9720.cpp ] + [ thread-run test_9856.cpp ] #[ thread-run test_10125.cpp ] #[ thread-run test_10128.cpp ] #[ thread-run test_10340.cpp ] diff --git a/test/test_9856.cpp b/test/test_9856.cpp index a08641de..918d232d 100644 --- a/test/test_9856.cpp +++ b/test/test_9856.cpp @@ -19,6 +19,11 @@ int main() { } } if(failures) - std::cerr << "There were " << failures << " failures out of " << total << " timed waits." << std::endl; - return failures!=0; + std::cout << "There were " << failures << " failures out of " << total << " timed waits." << std::endl; + if((100*failures)/total>10) + { + std::cerr << "This exceeds 10%, so failing the test." << std::endl; + return 1; + } + return 0; } \ No newline at end of file