mirror of
https://github.com/hyprwm/hyprutils.git
synced 2025-12-24 18:20:03 +01:00
memory: fix CAtomicSharedPointer mutex unlock and lifetime issues
This commit is contained in:
parent
bcabcbada9
commit
11bad76c40
1 changed files with 59 additions and 30 deletions
|
|
@ -23,6 +23,27 @@
|
|||
|
||||
namespace Hyprutils::Memory {
|
||||
namespace Atomic_ {
|
||||
// Lock guard with the option to unlock early
|
||||
class CCLockGuard {
|
||||
std::recursive_mutex* m_mutex;
|
||||
|
||||
public:
|
||||
CCLockGuard(std::recursive_mutex* mutex) : m_mutex(mutex) {
|
||||
m_mutex->lock();
|
||||
}
|
||||
|
||||
~CCLockGuard() {
|
||||
unlockDrop();
|
||||
};
|
||||
|
||||
void unlockDrop() {
|
||||
if (m_mutex)
|
||||
m_mutex->unlock();
|
||||
|
||||
m_mutex = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class impl : public Impl_::impl<T> {
|
||||
std::recursive_mutex m_mutex;
|
||||
|
|
@ -32,8 +53,8 @@ namespace Hyprutils::Memory {
|
|||
;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lockGuard() {
|
||||
return std::lock_guard<std::recursive_mutex>(m_mutex);
|
||||
CCLockGuard lockGuard() {
|
||||
return CCLockGuard(&m_mutex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -87,19 +108,12 @@ namespace Hyprutils::Memory {
|
|||
}
|
||||
|
||||
~CAtomicSharedPointer() {
|
||||
if (!m_ptr.impl_)
|
||||
return;
|
||||
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
reset();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
validHierarchy<const CAtomicSharedPointer<U>&> operator=(const CAtomicSharedPointer<U>& rhs) {
|
||||
if (m_ptr.impl_) {
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
}
|
||||
reset();
|
||||
|
||||
if (!rhs.m_ptr.impl_)
|
||||
return *this;
|
||||
|
|
@ -113,10 +127,7 @@ namespace Hyprutils::Memory {
|
|||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
if (m_ptr.impl_) {
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
}
|
||||
reset();
|
||||
|
||||
if (!rhs.m_ptr.impl_)
|
||||
return *this;
|
||||
|
|
@ -145,7 +156,32 @@ namespace Hyprutils::Memory {
|
|||
return;
|
||||
|
||||
auto lg = implLockGuard();
|
||||
if (m_ptr.impl_->ref() > 1) {
|
||||
m_ptr.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ptr.impl_->wref() == 0) {
|
||||
lg.unlockDrop(); // Don't hold the mutex when destroying it
|
||||
|
||||
m_ptr.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// When the control block gets destroyed, the mutex is destroyed with it.
|
||||
// Thus we must avoid attempting an unlock after impl_ has been destroyed.
|
||||
// There is no safe way of checking whether it has been destroyed or not.
|
||||
//
|
||||
// To avoid this altogether, keep a weak pointer here.
|
||||
// This guarantees that impl_ is still valid after the reset.
|
||||
CWeakPointer<T> guard = m_ptr;
|
||||
m_ptr.reset();
|
||||
|
||||
// Now we can safely check if guard is the last wref.
|
||||
if (guard.impl_->wref() == 1)
|
||||
lg.unlockDrop();
|
||||
|
||||
// guard.reset()
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
|
|
@ -177,7 +213,7 @@ namespace Hyprutils::Memory {
|
|||
}
|
||||
|
||||
private:
|
||||
std::lock_guard<std::recursive_mutex> implLockGuard() const {
|
||||
Atomic_::CCLockGuard implLockGuard() const {
|
||||
return ((Atomic_::impl<T>*)m_ptr.impl_)->lockGuard();
|
||||
}
|
||||
|
||||
|
|
@ -241,19 +277,12 @@ namespace Hyprutils::Memory {
|
|||
}
|
||||
|
||||
~CAtomicWeakPointer() {
|
||||
if (!m_ptr.impl_)
|
||||
return;
|
||||
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
reset();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
validHierarchy<const CAtomicWeakPointer<U>&> operator=(const CAtomicWeakPointer<U>& rhs) {
|
||||
if (m_ptr.impl_) {
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
}
|
||||
reset();
|
||||
|
||||
auto lg = rhs.implLockGuard();
|
||||
m_ptr = rhs.m_ptr;
|
||||
|
|
@ -264,10 +293,7 @@ namespace Hyprutils::Memory {
|
|||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
if (m_ptr.impl_) {
|
||||
auto lg = implLockGuard();
|
||||
m_ptr.reset();
|
||||
}
|
||||
reset();
|
||||
|
||||
auto lg = rhs.implLockGuard();
|
||||
m_ptr = rhs.m_ptr;
|
||||
|
|
@ -293,6 +319,9 @@ namespace Hyprutils::Memory {
|
|||
return;
|
||||
|
||||
auto lg = implLockGuard();
|
||||
if (m_ptr.impl_->ref() == 0 && m_ptr.impl_->wref() == 1)
|
||||
lg.unlockDrop();
|
||||
|
||||
m_ptr.reset();
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +374,7 @@ namespace Hyprutils::Memory {
|
|||
}
|
||||
|
||||
private:
|
||||
std::lock_guard<std::recursive_mutex> implLockGuard() const {
|
||||
Atomic_::CCLockGuard implLockGuard() const {
|
||||
return ((Atomic_::impl<T>*)m_ptr.impl_)->lockGuard();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue