123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- #include "rwlock.h"
- #include <util/generic/yexception.h>
- #if defined(_unix_)
- #include <errno.h>
- #include <pthread.h>
- #endif
- #if defined(_win_) || defined(_darwin_)
- #include "mutex.h"
- #include "condvar.h"
- // darwin rwlocks not recursive
- class TRWMutex::TImpl {
- public:
- TImpl();
- ~TImpl();
- void AcquireRead() noexcept;
- bool TryAcquireRead() noexcept;
- void ReleaseRead() noexcept;
- void AcquireWrite() noexcept;
- bool TryAcquireWrite() noexcept;
- void ReleaseWrite() noexcept;
- void Release() noexcept;
- private:
- TMutex Lock_;
- int State_;
- TCondVar ReadCond_;
- TCondVar WriteCond_;
- int BlockedWriters_;
- };
- TRWMutex::TImpl::TImpl()
- : State_(0)
- , BlockedWriters_(0)
- {
- }
- TRWMutex::TImpl::~TImpl() {
- Y_ABORT_UNLESS(State_ == 0, "failure, State_ != 0");
- Y_ABORT_UNLESS(BlockedWriters_ == 0, "failure, BlockedWriters_ != 0");
- }
- void TRWMutex::TImpl::AcquireRead() noexcept {
- with_lock (Lock_) {
- while (BlockedWriters_ || State_ < 0) {
- ReadCond_.Wait(Lock_);
- }
- ++State_;
- }
- ReadCond_.Signal();
- }
- bool TRWMutex::TImpl::TryAcquireRead() noexcept {
- with_lock (Lock_) {
- if (BlockedWriters_ || State_ < 0) {
- return false;
- }
- ++State_;
- }
- return true;
- }
- void TRWMutex::TImpl::ReleaseRead() noexcept {
- Lock_.Acquire();
- if (--State_ > 0) {
- Lock_.Release();
- } else if (BlockedWriters_) {
- Lock_.Release();
- WriteCond_.Signal();
- } else {
- Lock_.Release();
- }
- }
- void TRWMutex::TImpl::AcquireWrite() noexcept {
- with_lock (Lock_) {
- while (State_ != 0) {
- ++BlockedWriters_;
- WriteCond_.Wait(Lock_);
- --BlockedWriters_;
- }
- State_ = -1;
- }
- }
- bool TRWMutex::TImpl::TryAcquireWrite() noexcept {
- with_lock (Lock_) {
- if (State_ != 0) {
- return false;
- }
- State_ = -1;
- }
- return true;
- }
- void TRWMutex::TImpl::ReleaseWrite() noexcept {
- Lock_.Acquire();
- State_ = 0;
- if (BlockedWriters_) {
- Lock_.Release();
- WriteCond_.Signal();
- } else {
- Lock_.Release();
- ReadCond_.Signal();
- }
- }
- void TRWMutex::TImpl::Release() noexcept {
- Lock_.Acquire();
- if (State_ > 0) {
- if (--State_ > 0) {
- Lock_.Release();
- } else if (BlockedWriters_) {
- Lock_.Release();
- WriteCond_.Signal();
- }
- } else {
- State_ = 0;
- if (BlockedWriters_) {
- Lock_.Release();
- WriteCond_.Signal();
- } else {
- Lock_.Release();
- ReadCond_.Signal();
- }
- }
- }
- #else /* POSIX threads */
- class TRWMutex::TImpl {
- public:
- TImpl();
- ~TImpl();
- void AcquireRead() noexcept;
- bool TryAcquireRead() noexcept;
- void ReleaseRead() noexcept;
- void AcquireWrite() noexcept;
- bool TryAcquireWrite() noexcept;
- void ReleaseWrite() noexcept;
- void Release() noexcept;
- private:
- pthread_rwlock_t Lock_;
- };
- TRWMutex::TImpl::TImpl() {
- int result = pthread_rwlock_init(&Lock_, nullptr);
- if (result != 0) {
- ythrow yexception() << "rwlock init failed (" << LastSystemErrorText(result) << ")";
- }
- }
- TRWMutex::TImpl::~TImpl() {
- const int result = pthread_rwlock_destroy(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock destroy failed (%s)", LastSystemErrorText(result));
- }
- void TRWMutex::TImpl::AcquireRead() noexcept {
- const int result = pthread_rwlock_rdlock(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock rdlock failed (%s)", LastSystemErrorText(result));
- }
- bool TRWMutex::TImpl::TryAcquireRead() noexcept {
- const int result = pthread_rwlock_tryrdlock(&Lock_);
- Y_ABORT_UNLESS(result == 0 || result == EBUSY, "rwlock tryrdlock failed (%s)", LastSystemErrorText(result));
- return result == 0;
- }
- void TRWMutex::TImpl::ReleaseRead() noexcept {
- const int result = pthread_rwlock_unlock(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock (read) unlock failed (%s)", LastSystemErrorText(result));
- }
- void TRWMutex::TImpl::AcquireWrite() noexcept {
- const int result = pthread_rwlock_wrlock(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock wrlock failed (%s)", LastSystemErrorText(result));
- }
- bool TRWMutex::TImpl::TryAcquireWrite() noexcept {
- const int result = pthread_rwlock_trywrlock(&Lock_);
- Y_ABORT_UNLESS(result == 0 || result == EBUSY, "rwlock trywrlock failed (%s)", LastSystemErrorText(result));
- return result == 0;
- }
- void TRWMutex::TImpl::ReleaseWrite() noexcept {
- const int result = pthread_rwlock_unlock(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock (write) unlock failed (%s)", LastSystemErrorText(result));
- }
- void TRWMutex::TImpl::Release() noexcept {
- const int result = pthread_rwlock_unlock(&Lock_);
- Y_ABORT_UNLESS(result == 0, "rwlock unlock failed (%s)", LastSystemErrorText(result));
- }
- #endif
- TRWMutex::TRWMutex()
- : Impl_(new TImpl())
- {
- }
- TRWMutex::~TRWMutex() = default;
- void TRWMutex::AcquireRead() noexcept {
- Impl_->AcquireRead();
- }
- bool TRWMutex::TryAcquireRead() noexcept {
- return Impl_->TryAcquireRead();
- }
- void TRWMutex::ReleaseRead() noexcept {
- Impl_->ReleaseRead();
- }
- void TRWMutex::AcquireWrite() noexcept {
- Impl_->AcquireWrite();
- }
- bool TRWMutex::TryAcquireWrite() noexcept {
- return Impl_->TryAcquireWrite();
- }
- void TRWMutex::ReleaseWrite() noexcept {
- Impl_->ReleaseWrite();
- }
- void TRWMutex::Release() noexcept {
- Impl_->Release();
- }
|