rwlock.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include "rwlock.h"
  2. #include <util/generic/yexception.h>
  3. #if defined(_unix_)
  4. #include <errno.h>
  5. #include <pthread.h>
  6. #endif
  7. #if defined(_win_) || defined(_darwin_)
  8. #include "mutex.h"
  9. #include "condvar.h"
  10. // darwin rwlocks not recursive
  11. class TRWMutex::TImpl {
  12. public:
  13. TImpl();
  14. ~TImpl();
  15. void AcquireRead() noexcept;
  16. bool TryAcquireRead() noexcept;
  17. void ReleaseRead() noexcept;
  18. void AcquireWrite() noexcept;
  19. bool TryAcquireWrite() noexcept;
  20. void ReleaseWrite() noexcept;
  21. void Release() noexcept;
  22. private:
  23. TMutex Lock_;
  24. int State_;
  25. TCondVar ReadCond_;
  26. TCondVar WriteCond_;
  27. int BlockedWriters_;
  28. };
  29. TRWMutex::TImpl::TImpl()
  30. : State_(0)
  31. , BlockedWriters_(0)
  32. {
  33. }
  34. TRWMutex::TImpl::~TImpl() {
  35. Y_ABORT_UNLESS(State_ == 0, "failure, State_ != 0");
  36. Y_ABORT_UNLESS(BlockedWriters_ == 0, "failure, BlockedWriters_ != 0");
  37. }
  38. void TRWMutex::TImpl::AcquireRead() noexcept {
  39. with_lock (Lock_) {
  40. while (BlockedWriters_ || State_ < 0) {
  41. ReadCond_.Wait(Lock_);
  42. }
  43. ++State_;
  44. }
  45. ReadCond_.Signal();
  46. }
  47. bool TRWMutex::TImpl::TryAcquireRead() noexcept {
  48. with_lock (Lock_) {
  49. if (BlockedWriters_ || State_ < 0) {
  50. return false;
  51. }
  52. ++State_;
  53. }
  54. return true;
  55. }
  56. void TRWMutex::TImpl::ReleaseRead() noexcept {
  57. Lock_.Acquire();
  58. if (--State_ > 0) {
  59. Lock_.Release();
  60. } else if (BlockedWriters_) {
  61. Lock_.Release();
  62. WriteCond_.Signal();
  63. } else {
  64. Lock_.Release();
  65. }
  66. }
  67. void TRWMutex::TImpl::AcquireWrite() noexcept {
  68. with_lock (Lock_) {
  69. while (State_ != 0) {
  70. ++BlockedWriters_;
  71. WriteCond_.Wait(Lock_);
  72. --BlockedWriters_;
  73. }
  74. State_ = -1;
  75. }
  76. }
  77. bool TRWMutex::TImpl::TryAcquireWrite() noexcept {
  78. with_lock (Lock_) {
  79. if (State_ != 0) {
  80. return false;
  81. }
  82. State_ = -1;
  83. }
  84. return true;
  85. }
  86. void TRWMutex::TImpl::ReleaseWrite() noexcept {
  87. Lock_.Acquire();
  88. State_ = 0;
  89. if (BlockedWriters_) {
  90. Lock_.Release();
  91. WriteCond_.Signal();
  92. } else {
  93. Lock_.Release();
  94. ReadCond_.Signal();
  95. }
  96. }
  97. void TRWMutex::TImpl::Release() noexcept {
  98. Lock_.Acquire();
  99. if (State_ > 0) {
  100. if (--State_ > 0) {
  101. Lock_.Release();
  102. } else if (BlockedWriters_) {
  103. Lock_.Release();
  104. WriteCond_.Signal();
  105. }
  106. } else {
  107. State_ = 0;
  108. if (BlockedWriters_) {
  109. Lock_.Release();
  110. WriteCond_.Signal();
  111. } else {
  112. Lock_.Release();
  113. ReadCond_.Signal();
  114. }
  115. }
  116. }
  117. #else /* POSIX threads */
  118. class TRWMutex::TImpl {
  119. public:
  120. TImpl();
  121. ~TImpl();
  122. void AcquireRead() noexcept;
  123. bool TryAcquireRead() noexcept;
  124. void ReleaseRead() noexcept;
  125. void AcquireWrite() noexcept;
  126. bool TryAcquireWrite() noexcept;
  127. void ReleaseWrite() noexcept;
  128. void Release() noexcept;
  129. private:
  130. pthread_rwlock_t Lock_;
  131. };
  132. TRWMutex::TImpl::TImpl() {
  133. int result = pthread_rwlock_init(&Lock_, nullptr);
  134. if (result != 0) {
  135. ythrow yexception() << "rwlock init failed (" << LastSystemErrorText(result) << ")";
  136. }
  137. }
  138. TRWMutex::TImpl::~TImpl() {
  139. const int result = pthread_rwlock_destroy(&Lock_);
  140. Y_ABORT_UNLESS(result == 0, "rwlock destroy failed (%s)", LastSystemErrorText(result));
  141. }
  142. void TRWMutex::TImpl::AcquireRead() noexcept {
  143. const int result = pthread_rwlock_rdlock(&Lock_);
  144. Y_ABORT_UNLESS(result == 0, "rwlock rdlock failed (%s)", LastSystemErrorText(result));
  145. }
  146. bool TRWMutex::TImpl::TryAcquireRead() noexcept {
  147. const int result = pthread_rwlock_tryrdlock(&Lock_);
  148. Y_ABORT_UNLESS(result == 0 || result == EBUSY, "rwlock tryrdlock failed (%s)", LastSystemErrorText(result));
  149. return result == 0;
  150. }
  151. void TRWMutex::TImpl::ReleaseRead() noexcept {
  152. const int result = pthread_rwlock_unlock(&Lock_);
  153. Y_ABORT_UNLESS(result == 0, "rwlock (read) unlock failed (%s)", LastSystemErrorText(result));
  154. }
  155. void TRWMutex::TImpl::AcquireWrite() noexcept {
  156. const int result = pthread_rwlock_wrlock(&Lock_);
  157. Y_ABORT_UNLESS(result == 0, "rwlock wrlock failed (%s)", LastSystemErrorText(result));
  158. }
  159. bool TRWMutex::TImpl::TryAcquireWrite() noexcept {
  160. const int result = pthread_rwlock_trywrlock(&Lock_);
  161. Y_ABORT_UNLESS(result == 0 || result == EBUSY, "rwlock trywrlock failed (%s)", LastSystemErrorText(result));
  162. return result == 0;
  163. }
  164. void TRWMutex::TImpl::ReleaseWrite() noexcept {
  165. const int result = pthread_rwlock_unlock(&Lock_);
  166. Y_ABORT_UNLESS(result == 0, "rwlock (write) unlock failed (%s)", LastSystemErrorText(result));
  167. }
  168. void TRWMutex::TImpl::Release() noexcept {
  169. const int result = pthread_rwlock_unlock(&Lock_);
  170. Y_ABORT_UNLESS(result == 0, "rwlock unlock failed (%s)", LastSystemErrorText(result));
  171. }
  172. #endif
  173. TRWMutex::TRWMutex()
  174. : Impl_(new TImpl())
  175. {
  176. }
  177. TRWMutex::~TRWMutex() = default;
  178. void TRWMutex::AcquireRead() noexcept {
  179. Impl_->AcquireRead();
  180. }
  181. bool TRWMutex::TryAcquireRead() noexcept {
  182. return Impl_->TryAcquireRead();
  183. }
  184. void TRWMutex::ReleaseRead() noexcept {
  185. Impl_->ReleaseRead();
  186. }
  187. void TRWMutex::AcquireWrite() noexcept {
  188. Impl_->AcquireWrite();
  189. }
  190. bool TRWMutex::TryAcquireWrite() noexcept {
  191. return Impl_->TryAcquireWrite();
  192. }
  193. void TRWMutex::ReleaseWrite() noexcept {
  194. Impl_->ReleaseWrite();
  195. }
  196. void TRWMutex::Release() noexcept {
  197. Impl_->Release();
  198. }