/* * 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: leaked instances * SubBase: 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 #define SK_DECLARE_INST_COUNT(T) \ static const char* InstCountClassName() { return #T; } \ SkInstCount fInstCnt; \ static int32_t GetInstanceCount() { return SkInstCount::Count(); } extern bool gPrintInstCount; template 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 int32_t SkInstCount::gCount = 0; template int32_t SkInstCount::gRegistered = 0; #else #define SK_DECLARE_INST_COUNT(T) #endif void SkInstCountPrintLeaksOnExit(); #endif // SkInstCnt_DEFINED