1*0b57cec5SDimitry Andric //===---------------------- shared_mutex.cpp ------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "__config" 10*0b57cec5SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric #include "shared_mutex" 13*0b57cec5SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB) 14*0b57cec5SDimitry Andric #pragma comment(lib, "pthread") 15*0b57cec5SDimitry Andric #endif 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric // Shared Mutex Base __shared_mutex_base()20*0b57cec5SDimitry Andric__shared_mutex_base::__shared_mutex_base() 21*0b57cec5SDimitry Andric : __state_(0) 22*0b57cec5SDimitry Andric { 23*0b57cec5SDimitry Andric } 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric // Exclusive ownership 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric void lock()28*0b57cec5SDimitry Andric__shared_mutex_base::lock() 29*0b57cec5SDimitry Andric { 30*0b57cec5SDimitry Andric unique_lock<mutex> lk(__mut_); 31*0b57cec5SDimitry Andric while (__state_ & __write_entered_) 32*0b57cec5SDimitry Andric __gate1_.wait(lk); 33*0b57cec5SDimitry Andric __state_ |= __write_entered_; 34*0b57cec5SDimitry Andric while (__state_ & __n_readers_) 35*0b57cec5SDimitry Andric __gate2_.wait(lk); 36*0b57cec5SDimitry Andric } 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric bool try_lock()39*0b57cec5SDimitry Andric__shared_mutex_base::try_lock() 40*0b57cec5SDimitry Andric { 41*0b57cec5SDimitry Andric unique_lock<mutex> lk(__mut_); 42*0b57cec5SDimitry Andric if (__state_ == 0) 43*0b57cec5SDimitry Andric { 44*0b57cec5SDimitry Andric __state_ = __write_entered_; 45*0b57cec5SDimitry Andric return true; 46*0b57cec5SDimitry Andric } 47*0b57cec5SDimitry Andric return false; 48*0b57cec5SDimitry Andric } 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric void unlock()51*0b57cec5SDimitry Andric__shared_mutex_base::unlock() 52*0b57cec5SDimitry Andric { 53*0b57cec5SDimitry Andric lock_guard<mutex> _(__mut_); 54*0b57cec5SDimitry Andric __state_ = 0; 55*0b57cec5SDimitry Andric __gate1_.notify_all(); 56*0b57cec5SDimitry Andric } 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric // Shared ownership 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric void lock_shared()61*0b57cec5SDimitry Andric__shared_mutex_base::lock_shared() 62*0b57cec5SDimitry Andric { 63*0b57cec5SDimitry Andric unique_lock<mutex> lk(__mut_); 64*0b57cec5SDimitry Andric while ((__state_ & __write_entered_) || (__state_ & __n_readers_) == __n_readers_) 65*0b57cec5SDimitry Andric __gate1_.wait(lk); 66*0b57cec5SDimitry Andric unsigned num_readers = (__state_ & __n_readers_) + 1; 67*0b57cec5SDimitry Andric __state_ &= ~__n_readers_; 68*0b57cec5SDimitry Andric __state_ |= num_readers; 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric bool try_lock_shared()72*0b57cec5SDimitry Andric__shared_mutex_base::try_lock_shared() 73*0b57cec5SDimitry Andric { 74*0b57cec5SDimitry Andric unique_lock<mutex> lk(__mut_); 75*0b57cec5SDimitry Andric unsigned num_readers = __state_ & __n_readers_; 76*0b57cec5SDimitry Andric if (!(__state_ & __write_entered_) && num_readers != __n_readers_) 77*0b57cec5SDimitry Andric { 78*0b57cec5SDimitry Andric ++num_readers; 79*0b57cec5SDimitry Andric __state_ &= ~__n_readers_; 80*0b57cec5SDimitry Andric __state_ |= num_readers; 81*0b57cec5SDimitry Andric return true; 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric return false; 84*0b57cec5SDimitry Andric } 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric void unlock_shared()87*0b57cec5SDimitry Andric__shared_mutex_base::unlock_shared() 88*0b57cec5SDimitry Andric { 89*0b57cec5SDimitry Andric lock_guard<mutex> _(__mut_); 90*0b57cec5SDimitry Andric unsigned num_readers = (__state_ & __n_readers_) - 1; 91*0b57cec5SDimitry Andric __state_ &= ~__n_readers_; 92*0b57cec5SDimitry Andric __state_ |= num_readers; 93*0b57cec5SDimitry Andric if (__state_ & __write_entered_) 94*0b57cec5SDimitry Andric { 95*0b57cec5SDimitry Andric if (num_readers == 0) 96*0b57cec5SDimitry Andric __gate2_.notify_one(); 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric else 99*0b57cec5SDimitry Andric { 100*0b57cec5SDimitry Andric if (num_readers == __n_readers_ - 1) 101*0b57cec5SDimitry Andric __gate1_.notify_one(); 102*0b57cec5SDimitry Andric } 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric // Shared Timed Mutex 107*0b57cec5SDimitry Andric // These routines are here for ABI stability shared_timed_mutex()108*0b57cec5SDimitry Andricshared_timed_mutex::shared_timed_mutex() : __base() {} lock()109*0b57cec5SDimitry Andricvoid shared_timed_mutex::lock() { return __base.lock(); } try_lock()110*0b57cec5SDimitry Andricbool shared_timed_mutex::try_lock() { return __base.try_lock(); } unlock()111*0b57cec5SDimitry Andricvoid shared_timed_mutex::unlock() { return __base.unlock(); } lock_shared()112*0b57cec5SDimitry Andricvoid shared_timed_mutex::lock_shared() { return __base.lock_shared(); } try_lock_shared()113*0b57cec5SDimitry Andricbool shared_timed_mutex::try_lock_shared() { return __base.try_lock_shared(); } unlock_shared()114*0b57cec5SDimitry Andricvoid shared_timed_mutex::unlock_shared() { return __base.unlock_shared(); } 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 119