summaryrefslogtreecommitdiff
path: root/boost/thread/win32/shared_mutex.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/thread/win32/shared_mutex.hpp')
-rw-r--r--boost/thread/win32/shared_mutex.hpp496
1 files changed, 221 insertions, 275 deletions
diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp
index d1bd971770..76ee2579b3 100644
--- a/boost/thread/win32/shared_mutex.hpp
+++ b/boost/thread/win32/shared_mutex.hpp
@@ -2,7 +2,7 @@
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 Anthony Williams
-// (C) Copyright 2011-2012 Vicente J. Botet Escriba
+// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -19,6 +19,7 @@
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -29,7 +30,7 @@ namespace boost
private:
struct state_data
{
- unsigned shared_count:11,
+ unsigned long shared_count:11,
shared_waiting:11,
exclusive:1,
upgrade:1,
@@ -38,19 +39,16 @@ namespace boost
friend bool operator==(state_data const& lhs,state_data const& rhs)
{
- return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
+ return *reinterpret_cast<unsigned long const*>(&lhs)==*reinterpret_cast<unsigned long const*>(&rhs);
}
};
-
- template<typename T>
- T interlocked_compare_exchange(T* target,T new_value,T comparand)
+ state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand)
{
- BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
*reinterpret_cast<long*>(&new_value),
*reinterpret_cast<long*>(&comparand));
- return *reinterpret_cast<T const*>(&res);
+ return *reinterpret_cast<state_data const*>(&res);
}
enum
@@ -67,19 +65,19 @@ namespace boost
{
if(old_state.exclusive_waiting)
{
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
+ BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
+ BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
void release_shared_waiters(state_data old_state)
{
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
+ BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
@@ -107,9 +105,9 @@ namespace boost
~shared_mutex()
{
- detail::winapi::CloseHandle(upgrade_sem);
- detail::winapi::CloseHandle(semaphores[unlock_sem]);
- detail::winapi::CloseHandle(semaphores[exclusive_sem]);
+ winapi::CloseHandle(upgrade_sem);
+ winapi::CloseHandle(semaphores[unlock_sem]);
+ winapi::CloseHandle(semaphores[exclusive_sem]);
}
bool try_lock_shared()
@@ -139,21 +137,60 @@ namespace boost
void lock_shared()
{
+ for(;;)
+ {
+ state_data old_state=state;
+ for(;;)
+ {
+ state_data new_state=old_state;
+ if(new_state.exclusive || new_state.exclusive_waiting_blocked)
+ {
+ ++new_state.shared_waiting;
+ if(!new_state.shared_waiting)
+ {
+ boost::throw_exception(boost::lock_error());
+ }
+ }
+ else
+ {
+ ++new_state.shared_count;
+ if(!new_state.shared_count)
+ {
+ boost::throw_exception(boost::lock_error());
+ }
+ }
-#if defined BOOST_THREAD_USES_DATETIME
- BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
-#else
- BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
-#endif
+ state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
+ if(current_state==old_state)
+ {
+ break;
+ }
+ old_state=current_state;
+ }
+
+ if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
+ {
+ return;
+ }
+
+ BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0);
+ }
}
-#if defined BOOST_THREAD_USES_DATETIME
- template<typename TimeDuration>
- bool timed_lock_shared(TimeDuration const & relative_time)
+ private:
+ unsigned long getMs(detail::platform_duration const& d)
{
- return timed_lock_shared(get_system_time()+relative_time);
+ return static_cast<unsigned long>(d.getMs());
}
- bool timed_lock_shared(boost::system_time const& wait_until)
+
+ template <typename Duration>
+ unsigned long getMs(Duration const& d)
+ {
+ return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
+ }
+
+ template <typename Clock, typename Timepoint, typename Duration>
+ bool do_lock_shared_until(Timepoint const& t, Duration const& max)
{
for(;;)
{
@@ -191,7 +228,30 @@ namespace boost
return true;
}
- unsigned long const res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
+ // If the clock is the system clock, it may jump while this function
+ // is waiting. To compensate for this and time out near the correct
+ // time, we call WaitForSingleObjectEx() in a loop with a short
+ // timeout and recheck the time remaining each time through the loop.
+ unsigned long res=0;
+ for(;;)
+ {
+ Duration d(t - Clock::now());
+ if(d <= Duration::zero()) // timeout occurred
+ {
+ res=detail::win32::timeout;
+ break;
+ }
+ if(max != Duration::zero())
+ {
+ d = (std::min)(d, max);
+ }
+ res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0);
+ if(res!=detail::win32::timeout) // semaphore released
+ {
+ break;
+ }
+ }
+
if(res==detail::win32::timeout)
{
for(;;)
@@ -231,114 +291,45 @@ namespace boost
BOOST_ASSERT(res==0);
}
}
+ public:
+
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename TimeDuration>
+ bool timed_lock_shared(TimeDuration const & relative_time)
+ {
+ const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
+ }
+ bool timed_lock_shared(boost::system_time const& wait_until)
+ {
+ const detail::real_platform_timepoint t(wait_until);
+ return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
- }
- template <class Clock, class Duration>
- bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- typename Clock::time_point c_now = Clock::now();
- return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
+ const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
+ typedef typename chrono::duration<Rep, Period> Duration;
+ typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Duration>
- bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
+ bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
- using namespace chrono;
- typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
- return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
+ typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
}
- bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
+ template <class Clock, class Duration>
+ bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
{
- for(;;)
- {
- state_data old_state=state;
- for(;;)
- {
- state_data new_state=old_state;
- if(new_state.exclusive || new_state.exclusive_waiting_blocked)
- {
- ++new_state.shared_waiting;
- if(!new_state.shared_waiting)
- {
- boost::throw_exception(boost::lock_error());
- }
- }
- else
- {
- ++new_state.shared_count;
- if(!new_state.shared_count)
- {
- boost::throw_exception(boost::lock_error());
- }
- }
-
- state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
- if(current_state==old_state)
- {
- break;
- }
- old_state=current_state;
- }
-
- if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
- {
- return true;
- }
-
- chrono::system_clock::time_point n = chrono::system_clock::now();
- unsigned long res;
- if (tp>n) {
- chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
- res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],
- static_cast<unsigned long>(rel_time.count()), 0);
- } else {
- res=detail::win32::timeout;
- }
- if(res==detail::win32::timeout)
- {
- for(;;)
- {
- state_data new_state=old_state;
- if(new_state.exclusive || new_state.exclusive_waiting_blocked)
- {
- if(new_state.shared_waiting)
- {
- --new_state.shared_waiting;
- }
- }
- else
- {
- ++new_state.shared_count;
- if(!new_state.shared_count)
- {
- return false;
- }
- }
-
- state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
- if(current_state==old_state)
- {
- break;
- }
- old_state=current_state;
- }
-
- if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
- {
- return true;
- }
- return false;
- }
-
- BOOST_ASSERT(res==0);
- }
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
#endif
@@ -375,7 +366,7 @@ namespace boost
{
if(old_state.upgrade)
{
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
+ BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
}
else
{
@@ -388,24 +379,6 @@ namespace boost
}
}
- void lock()
- {
-
-#if defined BOOST_THREAD_USES_DATETIME
- BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
-#else
- BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
-#endif
- }
-
-#if defined BOOST_THREAD_USES_DATETIME
- template<typename TimeDuration>
- bool timed_lock(TimeDuration const & relative_time)
- {
- return timed_lock(get_system_time()+relative_time);
- }
-#endif
-
bool try_lock()
{
state_data old_state=state;
@@ -431,14 +404,11 @@ namespace boost
return true;
}
-
-#if defined BOOST_THREAD_USES_DATETIME
- bool timed_lock(boost::system_time const& wait_until)
+ void lock()
{
for(;;)
{
state_data old_state=state;
-
for(;;)
{
state_data new_state=old_state;
@@ -467,14 +437,86 @@ namespace boost
if(!old_state.shared_count && !old_state.exclusive)
{
- return true;
+ return;
}
+
#ifndef UNDER_CE
const bool wait_all = true;
#else
const bool wait_all = false;
#endif
- unsigned long const wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
+ BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2);
+ }
+ }
+
+ private:
+ template <typename Clock, typename Timepoint, typename Duration>
+ bool do_lock_until(Timepoint const& t, Duration const& max)
+ {
+ for(;;)
+ {
+ state_data old_state=state;
+ for(;;)
+ {
+ state_data new_state=old_state;
+ if(new_state.shared_count || new_state.exclusive)
+ {
+ ++new_state.exclusive_waiting;
+ if(!new_state.exclusive_waiting)
+ {
+ boost::throw_exception(boost::lock_error());
+ }
+
+ new_state.exclusive_waiting_blocked=true;
+ }
+ else
+ {
+ new_state.exclusive=true;
+ }
+
+ state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
+ if(current_state==old_state)
+ {
+ break;
+ }
+ old_state=current_state;
+ }
+
+ if(!old_state.shared_count && !old_state.exclusive)
+ {
+ return true;
+ }
+
+ // If the clock is the system clock, it may jump while this function
+ // is waiting. To compensate for this and time out near the correct
+ // time, we call WaitForMultipleObjectsEx() in a loop with a short
+ // timeout and recheck the time remaining each time through the loop.
+ unsigned long wait_res=0;
+ for(;;)
+ {
+ Duration d(t - Clock::now());
+ if(d <= Duration::zero()) // timeout occurred
+ {
+ wait_res=detail::win32::timeout;
+ break;
+ }
+ if(max != Duration::zero())
+ {
+ d = (std::min)(d, max);
+ }
+ #ifndef UNDER_CE
+ wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0);
+ #else
+ wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0);
+ #endif
+ //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0);
+
+ if(wait_res!=detail::win32::timeout) // semaphore released
+ {
+ break;
+ }
+ }
+
if(wait_res==detail::win32::timeout)
{
for(;;)
@@ -500,7 +542,7 @@ namespace boost
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if (must_notify)
{
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
+ BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
}
if(current_state==old_state)
@@ -515,123 +557,48 @@ namespace boost
}
return false;
}
+
BOOST_ASSERT(wait_res<2);
}
}
+ public:
+
+#if defined BOOST_THREAD_USES_DATETIME
+ bool timed_lock(boost::system_time const& wait_until)
+ {
+ const detail::real_platform_timepoint t(wait_until);
+ return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ template<typename TimeDuration>
+ bool timed_lock(TimeDuration const & relative_time)
+ {
+ const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
+ }
#endif
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_until(chrono::steady_clock::now() + rel_time);
- }
- template <class Clock, class Duration>
- bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- typename Clock::time_point c_now = Clock::now();
- return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
+ const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
+ typedef typename chrono::duration<Rep, Period> Duration;
+ typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
template <class Duration>
- bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
+ bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
- using namespace chrono;
- typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
- return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
+ typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
+ // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
+ return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
}
- bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
+ template <class Clock, class Duration>
+ bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
{
- for(;;)
- {
- state_data old_state=state;
-
- for(;;)
- {
- state_data new_state=old_state;
- if(new_state.shared_count || new_state.exclusive)
- {
- ++new_state.exclusive_waiting;
- if(!new_state.exclusive_waiting)
- {
- boost::throw_exception(boost::lock_error());
- }
-
- new_state.exclusive_waiting_blocked=true;
- }
- else
- {
- new_state.exclusive=true;
- }
-
- state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
- if(current_state==old_state)
- {
- break;
- }
- old_state=current_state;
- }
-
- if(!old_state.shared_count && !old_state.exclusive)
- {
- return true;
- }
- #ifndef UNDER_CE
- const bool wait_all = true;
- #else
- const bool wait_all = false;
- #endif
-
- chrono::system_clock::time_point n = chrono::system_clock::now();
- unsigned long wait_res;
- if (tp>n) {
- chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
- wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,
- static_cast<unsigned long>(rel_time.count()), 0);
- } else {
- wait_res=detail::win32::timeout;
- }
- if(wait_res==detail::win32::timeout)
- {
- for(;;)
- {
- bool must_notify = false;
- state_data new_state=old_state;
- if(new_state.shared_count || new_state.exclusive)
- {
- if(new_state.exclusive_waiting)
- {
- if(!--new_state.exclusive_waiting)
- {
- new_state.exclusive_waiting_blocked=false;
- must_notify = true;
- }
- }
- }
- else
- {
- new_state.exclusive=true;
- }
-
- state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
- if (must_notify)
- {
- BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
- }
- if(current_state==old_state)
- {
- break;
- }
- old_state=current_state;
- }
- if(!old_state.shared_count && !old_state.exclusive)
- {
- return true;
- }
- return false;
- }
- BOOST_ASSERT(wait_res<2);
- }
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
}
#endif
@@ -698,7 +665,7 @@ namespace boost
return;
}
- BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],detail::winapi::infinite, 0));
+ BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0);
}
}
@@ -790,7 +757,7 @@ namespace boost
{
if(!last_reader)
{
- BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
+ BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0);
}
break;
}
@@ -823,27 +790,6 @@ namespace boost
}
release_waiters(old_state);
}
-// bool try_unlock_upgrade_and_lock()
-// {
-// return false;
-// }
-//#ifdef BOOST_THREAD_USES_CHRONO
-// template <class Rep, class Period>
-// bool
-// try_unlock_upgrade_and_lock_for(
-// const chrono::duration<Rep, Period>& rel_time)
-// {
-// return try_unlock_upgrade_and_lock_until(
-// chrono::steady_clock::now() + rel_time);
-// }
-// template <class Clock, class Duration>
-// bool
-// try_unlock_upgrade_and_lock_until(
-// const chrono::time_point<Clock, Duration>& abs_time)
-// {
-// return false;
-// }
-//#endif
void unlock_and_lock_shared()
{