Browse Source

Unify leak checkers

Michael Hansen 10 years ago
parent
commit
d283872da6
  1. 76
      Sources/Plasma/CoreLib/hsRefCnt.cpp
  2. 18
      Sources/Plasma/CoreLib/hsRefCnt.h

76
Sources/Plasma/CoreLib/hsRefCnt.cpp

@ -56,12 +56,18 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include <unordered_set> #include <unordered_set>
#include <mutex> #include <mutex>
#include "plFormat.h" #include "plFormat.h"
#include "hsWindows.h"
template <class _RefType> // hsDebugMessage can get overridden to dump to a file :(
#ifdef _MSC_VER
# include "hsWindows.h"
# define _LeakDebug(message) OutputDebugString(message)
#else
# define _LeakDebug(message) fputs(message, stderr)
#endif
struct _RefCountLeakCheck struct _RefCountLeakCheck
{ {
std::unordered_set<_RefType *> m_refs; std::unordered_set<_hsRefCnt_Base *> m_refs;
unsigned m_added, m_removed; unsigned m_added, m_removed;
std::mutex m_mutex; std::mutex m_mutex;
@ -69,47 +75,53 @@ struct _RefCountLeakCheck
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
OutputDebugString(plFormat("Refs tracked: {} created, {} destroyed\n", _LeakDebug(plFormat("Refs tracked: {} created, {} destroyed\n",
m_added, m_removed).c_str()); m_added, m_removed).c_str());
if (m_refs.empty()) if (m_refs.empty())
return; return;
OutputDebugString(plFormat(" {} objects leaked...\n", m_refs.size()).c_str()); _LeakDebug(plFormat(" {} objects leaked...\n", m_refs.size()).c_str());
for (_RefType *ref : m_refs) { for (_hsRefCnt_Base *ref : m_refs) {
OutputDebugString(plFormat(" 0x{_08x} {}: {} refs remain\n", _LeakDebug(plFormat(" 0x{_08x} {}: {} refs remain\n",
(uintptr_t)ref, typeid(*ref).name(), ref->RefCnt()).c_str()); (uintptr_t)ref, typeid(*ref).name(), ref->RefCnt()).c_str());
} }
} }
static _RefCountLeakCheck<_RefType> *_instance() static _RefCountLeakCheck *_instance()
{ {
static _RefCountLeakCheck<_RefType> s_instance; static _RefCountLeakCheck s_instance;
return &s_instance; return &s_instance;
} }
static void add(_RefType *node) static void add(_hsRefCnt_Base *ref)
{ {
_RefCountLeakCheck<_RefType> *p = _instance(); _RefCountLeakCheck *this_p = _instance();
std::lock_guard<std::mutex> lock(p->m_mutex); std::lock_guard<std::mutex> lock(this_p->m_mutex);
++p->m_added; ++this_p->m_added;
p->m_refs.insert(node); this_p->m_refs.insert(ref);
} }
static void del(_RefType *node) static void del(_hsRefCnt_Base *ref)
{ {
_RefCountLeakCheck<_RefType> *p = _instance(); _RefCountLeakCheck *this_p = _instance();
std::lock_guard<std::mutex> lock(p->m_mutex); std::lock_guard<std::mutex> lock(this_p->m_mutex);
++p->m_removed; ++this_p->m_removed;
p->m_refs.erase(node); this_p->m_refs.erase(ref);
} }
}; };
#endif #endif
hsRefCnt::hsRefCnt(int initRefs) _hsRefCnt_Base::_hsRefCnt_Base(int)
: fRefCnt(initRefs)
{ {
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL) #if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
_RefCountLeakCheck<hsRefCnt>::add(this); _RefCountLeakCheck::add(this);
#endif
}
_hsRefCnt_Base::~_hsRefCnt_Base()
{
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
_RefCountLeakCheck::del(this);
#endif #endif
} }
@ -118,10 +130,6 @@ hsRefCnt::~hsRefCnt()
#ifdef HS_DEBUGGING #ifdef HS_DEBUGGING
hsThrowIfFalse(fRefCnt == 1); hsThrowIfFalse(fRefCnt == 1);
#endif #endif
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
_RefCountLeakCheck<hsRefCnt>::del(this);
#endif
} }
void hsRefCnt::UnRef() void hsRefCnt::UnRef()
@ -136,23 +144,11 @@ void hsRefCnt::UnRef()
--fRefCnt; --fRefCnt;
} }
hsAtomicRefCnt::hsAtomicRefCnt(int initRefs)
: fRefCnt(initRefs)
{
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
_RefCountLeakCheck<hsAtomicRefCnt>::add(this);
#endif
}
hsAtomicRefCnt::~hsAtomicRefCnt() hsAtomicRefCnt::~hsAtomicRefCnt()
{ {
#ifdef HS_DEBUGGING #ifdef HS_DEBUGGING
hsThrowIfFalse(fRefCnt == 1); hsThrowIfFalse(fRefCnt == 1);
#endif #endif
#if (REFCOUNT_DEBUGGING == REFCOUNT_DBG_LEAKS) || (REFCOUNT_DEBUGGING == REFCOUNT_DBG_ALL)
_RefCountLeakCheck<hsAtomicRefCnt>::del(this);
#endif
} }
void hsAtomicRefCnt::UnRef(const char* tag) void hsAtomicRefCnt::UnRef(const char* tag)

18
Sources/Plasma/CoreLib/hsRefCnt.h

@ -44,12 +44,22 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include <atomic> #include <atomic>
class hsRefCnt { // For easier debugging
class _hsRefCnt_Base
{
public:
_hsRefCnt_Base(int initRefs = 1);
virtual ~_hsRefCnt_Base();
virtual int RefCnt() const = 0;
};
class hsRefCnt : public _hsRefCnt_Base {
private: private:
int fRefCnt; int fRefCnt;
public: public:
hsRefCnt(int initRefs = 1); hsRefCnt(int initRefs = 1) : fRefCnt(initRefs) { }
virtual ~hsRefCnt(); virtual ~hsRefCnt();
inline int RefCnt() const { return fRefCnt; } inline int RefCnt() const { return fRefCnt; }
@ -70,13 +80,13 @@ public:
// Thread-safe version. TODO: Evaluate whether this is fast enough to // Thread-safe version. TODO: Evaluate whether this is fast enough to
// merge with hsRefCnt above. // merge with hsRefCnt above.
class hsAtomicRefCnt class hsAtomicRefCnt : public _hsRefCnt_Base
{ {
private: private:
std::atomic<int> fRefCnt; std::atomic<int> fRefCnt;
public: public:
hsAtomicRefCnt(int initRefs = 1); hsAtomicRefCnt(int initRefs = 1) : fRefCnt(initRefs) { }
virtual ~hsAtomicRefCnt(); virtual ~hsAtomicRefCnt();
inline int RefCnt() const { return fRefCnt; } inline int RefCnt() const { return fRefCnt; }

Loading…
Cancel
Save