14f7ab58eSDimitry Andric //===---------------------- shared_mutex.cpp ------------------------------===//
24f7ab58eSDimitry Andric //
34f7ab58eSDimitry Andric //                     The LLVM Compiler Infrastructure
44f7ab58eSDimitry Andric //
54f7ab58eSDimitry Andric // This file is dual licensed under the MIT and the University of Illinois Open
64f7ab58eSDimitry Andric // Source Licenses. See LICENSE.TXT for details.
74f7ab58eSDimitry Andric //
84f7ab58eSDimitry Andric //===----------------------------------------------------------------------===//
94f7ab58eSDimitry Andric 
10d72607e9SDimitry Andric #include "__config"
11d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS
12d72607e9SDimitry Andric 
134f7ab58eSDimitry Andric #include "shared_mutex"
144f7ab58eSDimitry Andric 
154f7ab58eSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
164f7ab58eSDimitry Andric 
17854fa44bSDimitry Andric // Shared Mutex Base
__shared_mutex_base()18854fa44bSDimitry Andric __shared_mutex_base::__shared_mutex_base()
194f7ab58eSDimitry Andric     : __state_(0)
204f7ab58eSDimitry Andric {
214f7ab58eSDimitry Andric }
224f7ab58eSDimitry Andric 
234f7ab58eSDimitry Andric // Exclusive ownership
244f7ab58eSDimitry Andric 
254f7ab58eSDimitry Andric void
lock()26854fa44bSDimitry Andric __shared_mutex_base::lock()
274f7ab58eSDimitry Andric {
284f7ab58eSDimitry Andric     unique_lock<mutex> lk(__mut_);
294f7ab58eSDimitry Andric     while (__state_ & __write_entered_)
304f7ab58eSDimitry Andric         __gate1_.wait(lk);
314f7ab58eSDimitry Andric     __state_ |= __write_entered_;
324f7ab58eSDimitry Andric     while (__state_ & __n_readers_)
334f7ab58eSDimitry Andric         __gate2_.wait(lk);
344f7ab58eSDimitry Andric }
354f7ab58eSDimitry Andric 
364f7ab58eSDimitry Andric bool
try_lock()37854fa44bSDimitry Andric __shared_mutex_base::try_lock()
384f7ab58eSDimitry Andric {
394f7ab58eSDimitry Andric     unique_lock<mutex> lk(__mut_);
404f7ab58eSDimitry Andric     if (__state_ == 0)
414f7ab58eSDimitry Andric     {
424f7ab58eSDimitry Andric         __state_ = __write_entered_;
434f7ab58eSDimitry Andric         return true;
444f7ab58eSDimitry Andric     }
454f7ab58eSDimitry Andric     return false;
464f7ab58eSDimitry Andric }
474f7ab58eSDimitry Andric 
484f7ab58eSDimitry Andric void
unlock()49854fa44bSDimitry Andric __shared_mutex_base::unlock()
504f7ab58eSDimitry Andric {
514f7ab58eSDimitry Andric     lock_guard<mutex> _(__mut_);
524f7ab58eSDimitry Andric     __state_ = 0;
534f7ab58eSDimitry Andric     __gate1_.notify_all();
544f7ab58eSDimitry Andric }
554f7ab58eSDimitry Andric 
564f7ab58eSDimitry Andric // Shared ownership
574f7ab58eSDimitry Andric 
584f7ab58eSDimitry Andric void
lock_shared()59854fa44bSDimitry Andric __shared_mutex_base::lock_shared()
604f7ab58eSDimitry Andric {
614f7ab58eSDimitry Andric     unique_lock<mutex> lk(__mut_);
624f7ab58eSDimitry Andric     while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_)
634f7ab58eSDimitry Andric         __gate1_.wait(lk);
644f7ab58eSDimitry Andric     unsigned num_readers = (__state_ & __n_readers_) + 1;
654f7ab58eSDimitry Andric     __state_ &= ~__n_readers_;
664f7ab58eSDimitry Andric     __state_ |= num_readers;
674f7ab58eSDimitry Andric }
684f7ab58eSDimitry Andric 
694f7ab58eSDimitry Andric bool
try_lock_shared()70854fa44bSDimitry Andric __shared_mutex_base::try_lock_shared()
714f7ab58eSDimitry Andric {
724f7ab58eSDimitry Andric     unique_lock<mutex> lk(__mut_);
734f7ab58eSDimitry Andric     unsigned num_readers = __state_ & __n_readers_;
744f7ab58eSDimitry Andric     if (!(__state_ & __write_entered_) && num_readers != __n_readers_)
754f7ab58eSDimitry Andric     {
764f7ab58eSDimitry Andric         ++num_readers;
774f7ab58eSDimitry Andric         __state_ &= ~__n_readers_;
784f7ab58eSDimitry Andric         __state_ |= num_readers;
794f7ab58eSDimitry Andric         return true;
804f7ab58eSDimitry Andric     }
814f7ab58eSDimitry Andric     return false;
824f7ab58eSDimitry Andric }
834f7ab58eSDimitry Andric 
844f7ab58eSDimitry Andric void
unlock_shared()85854fa44bSDimitry Andric __shared_mutex_base::unlock_shared()
864f7ab58eSDimitry Andric {
874f7ab58eSDimitry Andric     lock_guard<mutex> _(__mut_);
884f7ab58eSDimitry Andric     unsigned num_readers = (__state_ & __n_readers_) - 1;
894f7ab58eSDimitry Andric     __state_ &= ~__n_readers_;
904f7ab58eSDimitry Andric     __state_ |= num_readers;
914f7ab58eSDimitry Andric     if (__state_ & __write_entered_)
924f7ab58eSDimitry Andric     {
934f7ab58eSDimitry Andric         if (num_readers == 0)
944f7ab58eSDimitry Andric             __gate2_.notify_one();
954f7ab58eSDimitry Andric     }
964f7ab58eSDimitry Andric     else
974f7ab58eSDimitry Andric     {
984f7ab58eSDimitry Andric         if (num_readers == __n_readers_ - 1)
994f7ab58eSDimitry Andric             __gate1_.notify_one();
1004f7ab58eSDimitry Andric     }
1014f7ab58eSDimitry Andric }
1024f7ab58eSDimitry Andric 
1034f7ab58eSDimitry Andric 
104854fa44bSDimitry Andric // Shared Timed Mutex
105854fa44bSDimitry Andric // These routines are here for ABI stability
shared_timed_mutex()106854fa44bSDimitry Andric shared_timed_mutex::shared_timed_mutex() : __base() {}
lock()107854fa44bSDimitry Andric void shared_timed_mutex::lock()     { return __base.lock(); }
try_lock()108854fa44bSDimitry Andric bool shared_timed_mutex::try_lock() { return __base.try_lock(); }
unlock()109854fa44bSDimitry Andric void shared_timed_mutex::unlock()   { return __base.unlock(); }
lock_shared()110854fa44bSDimitry Andric void shared_timed_mutex::lock_shared() { return __base.lock_shared(); }
try_lock_shared()111854fa44bSDimitry Andric bool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); }
unlock_shared()112854fa44bSDimitry Andric void shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); }
113854fa44bSDimitry Andric 
1144f7ab58eSDimitry Andric _LIBCPP_END_NAMESPACE_STD
115d72607e9SDimitry Andric 
116d72607e9SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS
117