mutex.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "mutex.h"
  2. #include <util/generic/yexception.h>
  3. #include <errno.h>
  4. #if defined(_win_)
  5. #include "winint.h"
  6. #else
  7. #include <pthread.h>
  8. #endif
  9. class TMutex::TImpl {
  10. public:
  11. inline TImpl() {
  12. #if defined(_win_)
  13. InitializeCriticalSection(&Obj);
  14. #else
  15. struct T {
  16. pthread_mutexattr_t Attr;
  17. inline T() {
  18. int result;
  19. memset(&Attr, 0, sizeof(Attr));
  20. result = pthread_mutexattr_init(&Attr);
  21. if (result != 0) {
  22. ythrow yexception() << "mutexattr init failed(" << LastSystemErrorText(result) << ")";
  23. }
  24. result = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
  25. if (result != 0) {
  26. ythrow yexception() << "mutexattr set type failed(" << LastSystemErrorText(result) << ")";
  27. }
  28. }
  29. inline ~T() {
  30. int result = pthread_mutexattr_destroy(&Attr);
  31. Y_ABORT_UNLESS(result == 0, "mutexattr destroy(%s)", LastSystemErrorText(result));
  32. }
  33. } pma;
  34. int result = pthread_mutex_init(&Obj, &pma.Attr);
  35. if (result != 0) {
  36. ythrow yexception() << "mutex init failed(" << LastSystemErrorText(result) << ")";
  37. }
  38. #endif
  39. }
  40. inline ~TImpl() {
  41. #if defined(_win_)
  42. DeleteCriticalSection(&Obj);
  43. #else
  44. int result = pthread_mutex_destroy(&Obj);
  45. Y_ABORT_UNLESS(result == 0, "mutex destroy failure (%s)", LastSystemErrorText(result));
  46. #endif
  47. }
  48. inline void Acquire() noexcept {
  49. #if defined(_win_)
  50. EnterCriticalSection(&Obj);
  51. #else
  52. int result = pthread_mutex_lock(&Obj);
  53. Y_ABORT_UNLESS(result == 0, "mutex lock failure (%s)", LastSystemErrorText(result));
  54. #endif
  55. }
  56. #if defined(_win_)
  57. static bool TryEnterCriticalSectionInt(CRITICAL_SECTION* obj) {
  58. #if (_WIN32_WINNT < 0x0400)
  59. if (-1L == ::InterlockedCompareExchange(&obj->LockCount, 0, -1)) {
  60. obj->OwningThread = (HANDLE)(DWORD_PTR)::GetCurrentThreadId();
  61. obj->RecursionCount = 1;
  62. return true;
  63. }
  64. if (obj->OwningThread == (HANDLE)(DWORD_PTR)::GetCurrentThreadId()) {
  65. ::InterlockedIncrement(&obj->LockCount);
  66. ++obj->RecursionCount;
  67. return true;
  68. }
  69. return false;
  70. #else // _WIN32_WINNT < 0x0400
  71. return TryEnterCriticalSection(obj);
  72. #endif // _WIN32_WINNT < 0x0400
  73. }
  74. #endif // _win_
  75. inline bool TryAcquire() noexcept {
  76. #if defined(_win_)
  77. return TryEnterCriticalSectionInt(&Obj);
  78. #else
  79. int result = pthread_mutex_trylock(&Obj);
  80. if (result == 0 || result == EBUSY) {
  81. return result == 0;
  82. }
  83. Y_ABORT("mutex trylock failure (%s)", LastSystemErrorText(result));
  84. #endif
  85. }
  86. inline void Release() noexcept {
  87. #if defined(_win_)
  88. LeaveCriticalSection(&Obj);
  89. #else
  90. int result = pthread_mutex_unlock(&Obj);
  91. Y_ABORT_UNLESS(result == 0, "mutex unlock failure (%s)", LastSystemErrorText(result));
  92. #endif
  93. }
  94. inline void* Handle() const noexcept {
  95. return (void*)&Obj;
  96. }
  97. private:
  98. #ifdef _win_
  99. CRITICAL_SECTION Obj;
  100. #else
  101. pthread_mutex_t Obj;
  102. #endif
  103. };
  104. TMutex::TMutex()
  105. : Impl_(new TImpl())
  106. {
  107. }
  108. TMutex::TMutex(TMutex&&) noexcept = default;
  109. TMutex::~TMutex() = default;
  110. void TMutex::Acquire() noexcept {
  111. Impl_->Acquire();
  112. }
  113. bool TMutex::TryAcquire() noexcept {
  114. return Impl_->TryAcquire();
  115. }
  116. void TMutex::Release() noexcept {
  117. Impl_->Release();
  118. }
  119. void* TMutex::Handle() const noexcept {
  120. return Impl_->Handle();
  121. }