blob: 4ff44b5e3c8dbce849d05f3d46c9e4b0f538143d [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkInstCnt_DEFINED
#define SkInstCnt_DEFINED
/* To count all instances of T, including all subclasses of T,
* add SK_DECLARE_INST_COUNT(T) to T's class definition.
* If you want to print out counts of leaked instances, set gPrintInstCount to true in main().
*
* E.g.
* struct Base { SK_DECLARE_INST_COUNT(Base) };
* struct A : public Base {};
* struct SubBase : public Base { SK_DECLARE_INST_COUNT(SubBase); }
* struct B : public SubBase {};
*
* If gPrintInstCount is true, at the program exit you will see something like:
* Base: <N> leaked instances
* SubBase: <M> leaked instances
* where N >= M. Leaked instances of A count against Base; leaked instances of B count against
* both SubBase and Base.
*
* If SK_ENABLE_INST_COUNT is not defined or defined to 0, or we're in a shared library build,
* this entire system is compiled away to a noop.
*/
#include "SkTypes.h"
#if SK_ENABLE_INST_COUNT && !defined(SKIA_DLL) // See skia:2058 for why we noop on shared builds.
#include "SkThread.h"
#include <stdlib.h>
#define SK_DECLARE_INST_COUNT(T) \
static const char* InstCountClassName() { return #T; } \
SkInstCount<T, T::InstCountClassName> fInstCnt; \
static int32_t GetInstanceCount() { return SkInstCount<T, InstCountClassName>::Count(); }
extern bool gPrintInstCount;
template <typename T, const char*(Name)()>
class SkInstCount {
public:
SkInstCount() { Inc(); }
SkInstCount(const SkInstCount&) { Inc(); }
~SkInstCount() { sk_atomic_dec(&gCount); }
SkInstCount& operator==(const SkInstCount&) { return *this; } // == can't change the count.
static void Inc() {
// If it's the first time we go from 0 to 1, register to print leaks at process exit.
if (0 == sk_atomic_inc(&gCount) && sk_atomic_cas(&gRegistered, 0, 1)) {
atexit(PrintAtExit);
}
}
static void PrintAtExit() {
int32_t leaks = Count();
if (gPrintInstCount && leaks > 0) {
SkDebugf("Leaked %s: %d\n", Name(), leaks);
}
}
// FIXME: Used publicly by unit tests. Seems like a bad idea in a DM world.
static int32_t Count() { return sk_acquire_load(&gCount); }
private:
static int32_t gCount, gRegistered;
};
// As template values, these will be deduplicated. (No one-definition rule problems.)
template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gCount = 0;
template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gRegistered = 0;
#else
#define SK_DECLARE_INST_COUNT(T)
#endif
void SkInstCountPrintLeaksOnExit();
#endif // SkInstCnt_DEFINED