summaryrefslogtreecommitdiffstats
path: root/util/system/mutex.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/mutex.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/mutex.cpp')
-rw-r--r--util/system/mutex.cpp146
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();
+}