Chris@16: #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP Chris@16: #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP Chris@16: Chris@16: // (C) Copyright 2006-8 Anthony Williams Chris@16: // (C) Copyright 2011-2012 Vicente J. Botet Escriba Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: #include Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: class shared_mutex Chris@16: { Chris@16: private: Chris@16: struct state_data Chris@16: { Chris@16: unsigned shared_count:11, Chris@16: shared_waiting:11, Chris@16: exclusive:1, Chris@16: upgrade:1, Chris@16: exclusive_waiting:7, Chris@16: exclusive_waiting_blocked:1; Chris@16: Chris@16: friend bool operator==(state_data const& lhs,state_data const& rhs) Chris@16: { Chris@16: return *reinterpret_cast(&lhs)==*reinterpret_cast(&rhs); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: T interlocked_compare_exchange(T* target,T new_value,T comparand) Chris@16: { Chris@16: BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); Chris@16: long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast(target), Chris@16: *reinterpret_cast(&new_value), Chris@16: *reinterpret_cast(&comparand)); Chris@16: return *reinterpret_cast(&res); Chris@16: } Chris@16: Chris@16: enum Chris@16: { Chris@16: unlock_sem = 0, Chris@16: exclusive_sem = 1 Chris@16: }; Chris@16: Chris@16: state_data state; Chris@16: detail::win32::handle semaphores[2]; Chris@16: detail::win32::handle upgrade_sem; Chris@16: Chris@16: void release_waiters(state_data old_state) Chris@16: { Chris@16: if(old_state.exclusive_waiting) Chris@16: { Chris@16: BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); Chris@16: } Chris@16: Chris@16: if(old_state.shared_waiting || old_state.exclusive_waiting) Chris@16: { Chris@16: BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); Chris@16: } Chris@16: } Chris@101: void release_shared_waiters(state_data old_state) Chris@101: { Chris@101: if(old_state.shared_waiting || old_state.exclusive_waiting) Chris@101: { Chris@101: BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); Chris@101: } Chris@101: } Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(shared_mutex) Chris@16: shared_mutex() Chris@16: { Chris@16: semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); Chris@16: semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); Chris@16: if (!semaphores[exclusive_sem]) Chris@16: { Chris@16: detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); Chris@16: boost::throw_exception(thread_resource_error()); Chris@16: } Chris@16: upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); Chris@16: if (!upgrade_sem) Chris@16: { Chris@16: detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); Chris@16: detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX); Chris@16: boost::throw_exception(thread_resource_error()); Chris@16: } Chris@16: state_data state_={0,0,0,0,0,0}; Chris@16: state=state_; Chris@16: } Chris@16: Chris@16: ~shared_mutex() Chris@16: { Chris@16: detail::win32::CloseHandle(upgrade_sem); Chris@16: detail::win32::CloseHandle(semaphores[unlock_sem]); Chris@16: detail::win32::CloseHandle(semaphores[exclusive_sem]); Chris@16: } Chris@16: Chris@16: bool try_lock_shared() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: return !(old_state.exclusive| old_state.exclusive_waiting_blocked); Chris@16: } Chris@16: Chris@16: void lock_shared() Chris@16: { Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); Chris@16: #else Chris@16: BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now())); Chris@16: #endif Chris@16: } Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: template Chris@16: bool timed_lock_shared(TimeDuration const & relative_time) Chris@16: { Chris@16: return timed_lock_shared(get_system_time()+relative_time); Chris@16: } Chris@16: bool timed_lock_shared(boost::system_time const& wait_until) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked) Chris@16: { Chris@16: ++new_state.shared_waiting; Chris@16: if(!new_state.shared_waiting) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@101: unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0); Chris@16: if(res==detail::win32::timeout) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked) Chris@16: { Chris@16: if(new_state.shared_waiting) Chris@16: { Chris@16: --new_state.shared_waiting; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: BOOST_ASSERT(res==0); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: template Chris@16: bool try_lock_shared_for(const chrono::duration& rel_time) Chris@16: { Chris@16: return try_lock_shared_until(chrono::steady_clock::now() + rel_time); Chris@16: } Chris@16: template Chris@16: bool try_lock_shared_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: system_clock::time_point s_now = system_clock::now(); Chris@16: typename Clock::time_point c_now = Clock::now(); Chris@16: return try_lock_shared_until(s_now + ceil(t - c_now)); Chris@16: } Chris@16: template Chris@16: bool try_lock_shared_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: typedef time_point sys_tmpt; Chris@16: return try_lock_shared_until(sys_tmpt(chrono::ceil(t.time_since_epoch()))); Chris@16: } Chris@16: bool try_lock_shared_until(const chrono::time_point& tp) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked) Chris@16: { Chris@16: ++new_state.shared_waiting; Chris@16: if(!new_state.shared_waiting) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@16: chrono::system_clock::time_point n = chrono::system_clock::now(); Chris@16: unsigned long res; Chris@16: if (tp>n) { Chris@16: chrono::milliseconds rel_time= chrono::ceil(tp-n); Chris@101: res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem], Chris@101: static_cast(rel_time.count()), 0); Chris@16: } else { Chris@16: res=detail::win32::timeout; Chris@16: } Chris@16: if(res==detail::win32::timeout) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked) Chris@16: { Chris@16: if(new_state.shared_waiting) Chris@16: { Chris@16: --new_state.shared_waiting; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: BOOST_ASSERT(res==0); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: void unlock_shared() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: bool const last_reader=!--new_state.shared_count; Chris@16: Chris@16: if(last_reader) Chris@16: { Chris@16: if(new_state.upgrade) Chris@16: { Chris@16: new_state.upgrade=false; Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: else Chris@16: { Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: } Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: if(last_reader) Chris@16: { Chris@16: if(old_state.upgrade) Chris@16: { Chris@16: BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0); Chris@16: } Chris@16: else Chris@16: { Chris@16: release_waiters(old_state); Chris@16: } Chris@16: } Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: } Chris@16: Chris@16: void lock() Chris@16: { Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); Chris@16: #else Chris@16: BOOST_VERIFY(try_lock_until(chrono::steady_clock::now())); Chris@16: #endif Chris@16: } Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: template Chris@16: bool timed_lock(TimeDuration const & relative_time) Chris@16: { Chris@16: return timed_lock(get_system_time()+relative_time); Chris@16: } Chris@16: #endif Chris@16: Chris@16: bool try_lock() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.shared_count || new_state.exclusive) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: else Chris@16: { Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: bool timed_lock(boost::system_time const& wait_until) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data old_state=state; Chris@16: Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.shared_count || new_state.exclusive) Chris@16: { Chris@16: ++new_state.exclusive_waiting; Chris@16: if(!new_state.exclusive_waiting) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: Chris@16: new_state.exclusive_waiting_blocked=true; Chris@16: } Chris@16: else Chris@16: { Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!old_state.shared_count && !old_state.exclusive) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: #ifndef UNDER_CE Chris@16: const bool wait_all = true; Chris@16: #else Chris@16: const bool wait_all = false; Chris@16: #endif Chris@101: unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0); Chris@16: if(wait_res==detail::win32::timeout) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: bool must_notify = false; Chris@16: state_data new_state=old_state; Chris@16: if(new_state.shared_count || new_state.exclusive) Chris@16: { Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: if(!--new_state.exclusive_waiting) Chris@16: { Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: must_notify = true; Chris@16: } Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if (must_notify) Chris@16: { Chris@16: BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); Chris@16: } Chris@16: Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: if(!old_state.shared_count && !old_state.exclusive) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: BOOST_ASSERT(wait_res<2); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: template Chris@16: bool try_lock_for(const chrono::duration& rel_time) Chris@16: { Chris@16: return try_lock_until(chrono::steady_clock::now() + rel_time); Chris@16: } Chris@16: template Chris@16: bool try_lock_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: system_clock::time_point s_now = system_clock::now(); Chris@16: typename Clock::time_point c_now = Clock::now(); Chris@16: return try_lock_until(s_now + ceil(t - c_now)); Chris@16: } Chris@16: template Chris@16: bool try_lock_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: typedef time_point sys_tmpt; Chris@16: return try_lock_until(sys_tmpt(chrono::ceil(t.time_since_epoch()))); Chris@16: } Chris@16: bool try_lock_until(const chrono::time_point& tp) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data old_state=state; Chris@16: Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.shared_count || new_state.exclusive) Chris@16: { Chris@16: ++new_state.exclusive_waiting; Chris@16: if(!new_state.exclusive_waiting) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: Chris@16: new_state.exclusive_waiting_blocked=true; Chris@16: } Chris@16: else Chris@16: { Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!old_state.shared_count && !old_state.exclusive) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: #ifndef UNDER_CE Chris@16: const bool wait_all = true; Chris@16: #else Chris@16: const bool wait_all = false; Chris@16: #endif Chris@16: Chris@16: chrono::system_clock::time_point n = chrono::system_clock::now(); Chris@16: unsigned long wait_res; Chris@16: if (tp>n) { Chris@16: chrono::milliseconds rel_time= chrono::ceil(tp-chrono::system_clock::now()); Chris@101: wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all, Chris@101: static_cast(rel_time.count()), 0); Chris@16: } else { Chris@16: wait_res=detail::win32::timeout; Chris@16: } Chris@16: if(wait_res==detail::win32::timeout) Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: bool must_notify = false; Chris@16: state_data new_state=old_state; Chris@16: if(new_state.shared_count || new_state.exclusive) Chris@16: { Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: if(!--new_state.exclusive_waiting) Chris@16: { Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: must_notify = true; Chris@16: } Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if (must_notify) Chris@16: { Chris@16: BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); Chris@16: } Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: if(!old_state.shared_count && !old_state.exclusive) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: BOOST_ASSERT(wait_res<2); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: new_state.exclusive=false; Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: release_waiters(old_state); Chris@16: } Chris@16: Chris@16: void lock_upgrade() Chris@16: { Chris@16: for(;;) Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) Chris@16: { Chris@16: ++new_state.shared_waiting; Chris@16: if(!new_state.shared_waiting) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: boost::throw_exception(boost::lock_error()); Chris@16: } Chris@16: new_state.upgrade=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: Chris@16: if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) Chris@16: { Chris@16: return; Chris@16: } Chris@16: Chris@101: BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0)); Chris@16: } Chris@16: } Chris@16: Chris@16: bool try_lock_upgrade() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: else Chris@16: { Chris@16: ++new_state.shared_count; Chris@16: if(!new_state.shared_count) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: new_state.upgrade=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: void unlock_upgrade() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: new_state.upgrade=false; Chris@16: bool const last_reader=!--new_state.shared_count; Chris@16: Chris@16: if(last_reader) Chris@16: { Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: if(last_reader) Chris@16: { Chris@16: release_waiters(old_state); Chris@16: } Chris@101: else { Chris@101: release_shared_waiters(old_state); Chris@101: } Chris@16: // #7720 Chris@16: //else { Chris@16: // release_waiters(old_state); Chris@16: //} Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: } Chris@16: Chris@16: void unlock_upgrade_and_lock() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: bool const last_reader=!--new_state.shared_count; Chris@16: Chris@16: if(last_reader) Chris@16: { Chris@16: new_state.upgrade=false; Chris@16: new_state.exclusive=true; Chris@16: } Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: if(!last_reader) Chris@16: { Chris@101: BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0)); Chris@16: } Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: } Chris@16: Chris@16: void unlock_and_lock_upgrade() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: new_state.exclusive=false; Chris@16: new_state.upgrade=true; Chris@16: ++new_state.shared_count; Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: release_waiters(old_state); Chris@16: } Chris@16: // bool try_unlock_upgrade_and_lock() Chris@16: // { Chris@16: // return false; Chris@16: // } Chris@16: //#ifdef BOOST_THREAD_USES_CHRONO Chris@16: // template Chris@16: // bool Chris@16: // try_unlock_upgrade_and_lock_for( Chris@16: // const chrono::duration& rel_time) Chris@16: // { Chris@16: // return try_unlock_upgrade_and_lock_until( Chris@16: // chrono::steady_clock::now() + rel_time); Chris@16: // } Chris@16: // template Chris@16: // bool Chris@16: // try_unlock_upgrade_and_lock_until( Chris@16: // const chrono::time_point& abs_time) Chris@16: // { Chris@16: // return false; Chris@16: // } Chris@16: //#endif Chris@16: Chris@16: void unlock_and_lock_shared() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: new_state.exclusive=false; Chris@16: ++new_state.shared_count; Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: release_waiters(old_state); Chris@16: } Chris@16: void unlock_upgrade_and_lock_shared() Chris@16: { Chris@16: state_data old_state=state; Chris@16: for(;;) Chris@16: { Chris@16: state_data new_state=old_state; Chris@16: new_state.upgrade=false; Chris@16: if(new_state.exclusive_waiting) Chris@16: { Chris@16: --new_state.exclusive_waiting; Chris@16: new_state.exclusive_waiting_blocked=false; Chris@16: } Chris@16: new_state.shared_waiting=0; Chris@16: Chris@16: state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); Chris@16: if(current_state==old_state) Chris@16: { Chris@16: break; Chris@16: } Chris@16: old_state=current_state; Chris@16: } Chris@16: release_waiters(old_state); Chris@16: } Chris@16: Chris@16: }; Chris@16: typedef shared_mutex upgrade_mutex; Chris@16: Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: #endif