mirror of
https://github.com/hyprwm/hyprutils.git
synced 2025-12-20 08:10:10 +01:00
memory: fix CAtomicSharedPointer mutex unlock and lifetime issues (#68)
This commit is contained in:
parent
bcabcbada9
commit
b074d4abc7
1 changed files with 61 additions and 29 deletions
|
|
@ -35,6 +35,11 @@ namespace Hyprutils::Memory {
|
||||||
std::lock_guard<std::recursive_mutex> lockGuard() {
|
std::lock_guard<std::recursive_mutex> lockGuard() {
|
||||||
return std::lock_guard<std::recursive_mutex>(m_mutex);
|
return std::lock_guard<std::recursive_mutex>(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed when unlock order or mutex lifetime matters.
|
||||||
|
std::recursive_mutex& getMutex() {
|
||||||
|
return m_mutex;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,19 +92,12 @@ namespace Hyprutils::Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
~CAtomicSharedPointer() {
|
~CAtomicSharedPointer() {
|
||||||
if (!m_ptr.impl_)
|
reset();
|
||||||
return;
|
|
||||||
|
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
validHierarchy<const CAtomicSharedPointer<U>&> operator=(const CAtomicSharedPointer<U>& rhs) {
|
validHierarchy<const CAtomicSharedPointer<U>&> operator=(const CAtomicSharedPointer<U>& rhs) {
|
||||||
if (m_ptr.impl_) {
|
reset();
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rhs.m_ptr.impl_)
|
if (!rhs.m_ptr.impl_)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -113,10 +111,7 @@ namespace Hyprutils::Memory {
|
||||||
if (this == &rhs)
|
if (this == &rhs)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (m_ptr.impl_) {
|
reset();
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rhs.m_ptr.impl_)
|
if (!rhs.m_ptr.impl_)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -144,8 +139,43 @@ namespace Hyprutils::Memory {
|
||||||
if (!m_ptr.impl_)
|
if (!m_ptr.impl_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto lg = implLockGuard();
|
// last ref and last wref?
|
||||||
m_ptr.reset();
|
// -> must unlock BEFORE reset
|
||||||
|
// not last ref?
|
||||||
|
// -> must unlock AFTER reset
|
||||||
|
auto& mutex = ((Atomic_::impl<T>*)m_ptr.impl_)->getMutex();
|
||||||
|
mutex.lock();
|
||||||
|
|
||||||
|
if (m_ptr.impl_->ref() > 1) {
|
||||||
|
m_ptr.reset();
|
||||||
|
mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ptr.impl_->wref() == 0) {
|
||||||
|
mutex.unlock(); // Don't hold the mutex when destroying it
|
||||||
|
m_ptr.reset();
|
||||||
|
// mutex invalid
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// When the control block gets destroyed, the mutex is destroyed with it.
|
||||||
|
// Thus we must avoid attempting an unlock after impl_ has been destroyed.
|
||||||
|
// Without the workaround 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) {
|
||||||
|
mutex.unlock();
|
||||||
|
return; // ~guard destroys impl_ and mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
guard.reset();
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator*() const {
|
T& operator*() const {
|
||||||
|
|
@ -241,19 +271,12 @@ namespace Hyprutils::Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
~CAtomicWeakPointer() {
|
~CAtomicWeakPointer() {
|
||||||
if (!m_ptr.impl_)
|
reset();
|
||||||
return;
|
|
||||||
|
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
validHierarchy<const CAtomicWeakPointer<U>&> operator=(const CAtomicWeakPointer<U>& rhs) {
|
validHierarchy<const CAtomicWeakPointer<U>&> operator=(const CAtomicWeakPointer<U>& rhs) {
|
||||||
if (m_ptr.impl_) {
|
reset();
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lg = rhs.implLockGuard();
|
auto lg = rhs.implLockGuard();
|
||||||
m_ptr = rhs.m_ptr;
|
m_ptr = rhs.m_ptr;
|
||||||
|
|
@ -264,10 +287,7 @@ namespace Hyprutils::Memory {
|
||||||
if (this == &rhs)
|
if (this == &rhs)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
if (m_ptr.impl_) {
|
reset();
|
||||||
auto lg = implLockGuard();
|
|
||||||
m_ptr.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lg = rhs.implLockGuard();
|
auto lg = rhs.implLockGuard();
|
||||||
m_ptr = rhs.m_ptr;
|
m_ptr = rhs.m_ptr;
|
||||||
|
|
@ -292,8 +312,20 @@ namespace Hyprutils::Memory {
|
||||||
if (!m_ptr.impl_)
|
if (!m_ptr.impl_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto lg = implLockGuard();
|
// last ref and last wref?
|
||||||
|
// -> must unlock BEFORE reset
|
||||||
|
// not last ref?
|
||||||
|
// -> must unlock AFTER reset
|
||||||
|
auto& mutex = ((Atomic_::impl<T>*)m_ptr.impl_)->getMutex();
|
||||||
|
if (m_ptr.impl_->ref() == 0 && m_ptr.impl_->wref() == 1) {
|
||||||
|
mutex.unlock();
|
||||||
|
m_ptr.reset();
|
||||||
|
// mutex invalid
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_ptr.reset();
|
m_ptr.reset();
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator*() const {
|
T& operator*() const {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue