diff --git a/core/thread/inc/TWin32Mutex.h b/core/thread/inc/TWin32Mutex.h index 29a10a6d08187c63a84b680d50c17092da594c29..64206686096ec85adbe6acdf7b25e67c7bf86c98 100644 --- a/core/thread/inc/TWin32Mutex.h +++ b/core/thread/inc/TWin32Mutex.h @@ -36,6 +36,8 @@ friend class TWin32Condition; private: CRITICAL_SECTION fCritSect; + constexpr static int kIsRecursive = BIT(14); + public: TWin32Mutex(Bool_t recursive=kFALSE); virtual ~TWin32Mutex(); @@ -44,6 +46,9 @@ public: Int_t UnLock(); Int_t TryLock(); + std::unique_ptr<TVirtualMutex::State> Reset(); + void Restore(std::unique_ptr<TVirtualMutex::State> &&); + ClassDef(TWin32Mutex,0) // Win32 mutex lock }; diff --git a/core/thread/src/TWin32Mutex.cxx b/core/thread/src/TWin32Mutex.cxx index 4eb2af63212f8d2eabb041fefe57a87561f5f094..14140756cd40760d640712cf4ba5f7039c7b34de 100644 --- a/core/thread/src/TWin32Mutex.cxx +++ b/core/thread/src/TWin32Mutex.cxx @@ -69,3 +69,55 @@ Int_t TWin32Mutex::UnLock(void) ::LeaveCriticalSection(&fCritSect); return 0; } + +namespace { + struct TWin32MutexState: public TVirtualMutex::State { + int fLockCount = 0; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Reset the mutex state to unlocked. The state before resetting to unlocked is +/// returned and can be passed to `Restore()` later on. This function must only +/// be called while the mutex is locked. + +std::unique_ptr<TVirtualMutex::State> TWin32Mutex::Reset() +{ + std::unique_ptr<TWin32MutexState> pState(new TWin32MutexState); + if (TestBit(kIsRecursive)) { + while (!UnLock()) + ++pState->fLockCount; + return std::move(pState); + } + // Not recursive. Unlocking a non-recursive, non-robust, unlocked mutex has an + // undefined return value - so we cannot *guarantee* that the mutex is locked. + // But we can try. + if (int rc = UnLock()) { + SysError("Reset", "pthread_mutex_unlock failed with %d, " + "but Reset() must be called on locked mutex!", + rc); + return std::move(pState); + } + ++pState->fLockCount; + return std::move(pState); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Restore the mutex state to the state pointed to by `state`. This function +/// must only be called while the mutex is unlocked. + +void TWin32Mutex::Restore(std::unique_ptr<TVirtualMutex::State> &&state) +{ + TWin32MutexState *pState = dynamic_cast<TWin32MutexState *>(state.get()); + if (!pState) { + if (state) { + SysError("Restore", "LOGIC ERROR - invalid state object!"); + return; + } + // No state, do nothing. + return; + } + do { + Lock(); + } while (--pState->fLockCount); +}