diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/mutex.cpp |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/mutex.cpp')
-rw-r--r-- | util/system/mutex.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/util/system/mutex.cpp b/util/system/mutex.cpp new file mode 100644 index 00000000000..4041402db9a --- /dev/null +++ b/util/system/mutex.cpp @@ -0,0 +1,146 @@ +#include "mutex.h" + +#include <util/generic/yexception.h> +#include <errno.h> + +#if defined(_win_) + #include "winint.h" +#else + #include <pthread.h> +#endif + +class TMutex::TImpl { +public: + inline TImpl() { +#if defined(_win_) + InitializeCriticalSection(&Obj); +#else + struct T { + pthread_mutexattr_t Attr; + + inline T() { + int result; + + memset(&Attr, 0, sizeof(Attr)); + result = pthread_mutexattr_init(&Attr); + if (result != 0) { + ythrow yexception() << "mutexattr init failed(" << LastSystemErrorText(result) << ")"; + } + + result = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE); + if (result != 0) { + ythrow yexception() << "mutexattr set type failed(" << LastSystemErrorText(result) << ")"; + } + } + + inline ~T() { + int result = pthread_mutexattr_destroy(&Attr); + Y_VERIFY(result == 0, "mutexattr destroy(%s)", LastSystemErrorText(result)); + } + } pma; + + int result = pthread_mutex_init(&Obj, &pma.Attr); + if (result != 0) { + ythrow yexception() << "mutex init failed(" << LastSystemErrorText(result) << ")"; + } +#endif + } + + inline ~TImpl() { +#if defined(_win_) + DeleteCriticalSection(&Obj); +#else + int result = pthread_mutex_destroy(&Obj); + Y_VERIFY(result == 0, "mutex destroy failure (%s)", LastSystemErrorText(result)); +#endif + } + + inline void Acquire() noexcept { +#if defined(_win_) + EnterCriticalSection(&Obj); +#else + int result = pthread_mutex_lock(&Obj); + Y_VERIFY(result == 0, "mutex lock failure (%s)", LastSystemErrorText(result)); +#endif + } + +#if defined(_win_) + static bool TryEnterCriticalSectionInt(CRITICAL_SECTION* obj) { + #if (_WIN32_WINNT < 0x0400) + if (-1L == ::InterlockedCompareExchange(&obj->LockCount, 0, -1)) { + obj->OwningThread = (HANDLE)(DWORD_PTR)::GetCurrentThreadId(); + obj->RecursionCount = 1; + + return true; + } + + if (obj->OwningThread == (HANDLE)(DWORD_PTR)::GetCurrentThreadId()) { + ::InterlockedIncrement(&obj->LockCount); + ++obj->RecursionCount; + return true; + } + + return false; + #else // _WIN32_WINNT < 0x0400 + return TryEnterCriticalSection(obj); + #endif // _WIN32_WINNT < 0x0400 + } +#endif // _win_ + + inline bool TryAcquire() noexcept { +#if defined(_win_) + return TryEnterCriticalSectionInt(&Obj); +#else + int result = pthread_mutex_trylock(&Obj); + if (result == 0 || result == EBUSY) { + return result == 0; + } + Y_FAIL("mutex trylock failure (%s)", LastSystemErrorText(result)); +#endif + } + + inline void Release() noexcept { +#if defined(_win_) + LeaveCriticalSection(&Obj); +#else + int result = pthread_mutex_unlock(&Obj); + Y_VERIFY(result == 0, "mutex unlock failure (%s)", LastSystemErrorText(result)); +#endif + } + + inline void* Handle() const noexcept { + return (void*)&Obj; + } + +private: +#ifdef _win_ + CRITICAL_SECTION Obj; +#else + pthread_mutex_t Obj; +#endif +}; + +TMutex::TMutex() + : Impl_(new TImpl()) +{ +} + +TMutex::TMutex(TMutex&&) = default; + +TMutex::~TMutex() = default; + +void TMutex::Acquire() noexcept { + Impl_->Acquire(); +} + +bool TMutex::TryAcquire() noexcept { + return Impl_->TryAcquire(); +} + +void TMutex::Release() noexcept { + Impl_->Release(); +} + +void* TMutex::Handle() const noexcept { + return Impl_->Handle(); +} |