ThreadSafeRefCounted.h [plain text]
#pragma once
#include <atomic>
#include <wtf/FastMalloc.h>
#include <wtf/MainThread.h>
#include <wtf/Noncopyable.h>
namespace WTF {
#if defined(NDEBUG) && !ENABLE(SECURITY_ASSERTIONS)
#define CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE 0
#else
#define CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE 1
#endif
class ThreadSafeRefCountedBase {
WTF_MAKE_NONCOPYABLE(ThreadSafeRefCountedBase);
WTF_MAKE_FAST_ALLOCATED;
public:
ThreadSafeRefCountedBase() = default;
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
~ThreadSafeRefCountedBase()
{
m_deletionHasBegun = true;
}
#endif
void ref() const
{
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
#endif
++m_refCount;
}
bool hasOneRef() const
{
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
ASSERT(!m_deletionHasBegun);
#endif
return refCount() == 1;
}
unsigned refCount() const
{
return m_refCount;
}
protected:
bool derefBase() const
{
ASSERT(m_refCount);
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
#endif
if (UNLIKELY(!--m_refCount)) {
m_refCount = 1;
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
m_deletionHasBegun = true;
#endif
return true;
}
return false;
}
private:
mutable std::atomic<unsigned> m_refCount { 1 };
#if CHECK_THREAD_SAFE_REF_COUNTED_LIFECYCLE
mutable std::atomic<bool> m_deletionHasBegun { false };
#endif
};
enum class DestructionThread { Any, Main, MainRunLoop };
template<class T, DestructionThread destructionThread = DestructionThread::Any> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
public:
void deref() const
{
if (!derefBase())
return;
auto deleteThis = [this] {
delete static_cast<const T*>(this);
};
switch (destructionThread) {
case DestructionThread::Any:
break;
case DestructionThread::Main:
if (!isMainThread()) {
callOnMainThread(WTFMove(deleteThis));
return;
}
break;
case DestructionThread::MainRunLoop:
if (!isMainRunLoop()) {
callOnMainRunLoop(WTFMove(deleteThis));
return;
}
break;
}
deleteThis();
}
protected:
ThreadSafeRefCounted() = default;
};
}
using WTF::ThreadSafeRefCounted;