/* * 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 /* * The instance counting system consists of three macros that create the * instance counting machinery. A class is added to the system by adding: * SK_DECLARE_INST_COUNT at the top of its declaration for derived classes * SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class * At the end of an application a call to all the "root" objects' * CheckInstanceCount methods should be made */ #include "SkTypes.h" #if SK_ENABLE_INST_COUNT // Static variables inside member functions below may be defined multiple times // if Skia is being used as a dynamic library. Instance counting should be on // only for static builds. See bug skia:2058. #if defined(SKIA_DLL) #error Instance counting works only when Skia is built as a static library. #endif #include "SkOnce.h" #include "SkTArray.h" #include "SkThread.h" extern bool gPrintInstCount; // The non-root classes just register themselves with their parent #define SK_DECLARE_INST_COUNT(className) \ SK_DECLARE_INST_COUNT_INTERNAL(className, \ INHERITED::AddInstChild(CheckInstanceCount);) // The root classes registers a function to print out the memory stats when // the app ends #define SK_DECLARE_INST_COUNT_ROOT(className) \ SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);) #define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep) \ class SkInstanceCountHelper { \ public: \ SkInstanceCountHelper() { \ SK_DECLARE_STATIC_ONCE(once); \ SkOnce(&once, init, 0); \ sk_atomic_inc(GetInstanceCountPtr()); \ } \ \ static void init(int) { \ initStep \ } \ \ SkInstanceCountHelper(const SkInstanceCountHelper&) { \ sk_atomic_inc(GetInstanceCountPtr()); \ } \ \ ~SkInstanceCountHelper() { \ sk_atomic_dec(GetInstanceCountPtr()); \ } \ \ static int32_t* GetInstanceCountPtr() { \ static int32_t gInstanceCount; \ return &gInstanceCount; \ } \ \ static SkTArray*& GetChildren() { \ static SkTArray* gChildren; \ return gChildren; \ } \ \ static SkBaseMutex& GetChildrenMutex() { \ SK_DECLARE_STATIC_MUTEX(childrenMutex); \ return childrenMutex; \ } \ \ } fInstanceCountHelper; \ \ static int32_t GetInstanceCount() { \ return *SkInstanceCountHelper::GetInstanceCountPtr(); \ } \ \ static void exitPrint() { \ CheckInstanceCount(0, true); \ } \ \ static int CheckInstanceCount(int level = 0, bool cleanUp = false) { \ if (gPrintInstCount && 0 != GetInstanceCount()) { \ SkDebugf("%*c Leaked %s: %d\n", \ 4*level, ' ', #className, \ GetInstanceCount()); \ } \ if (NULL == SkInstanceCountHelper::GetChildren()) { \ return GetInstanceCount(); \ } \ SkTArray* children = \ SkInstanceCountHelper::GetChildren(); \ int childCount = children->count(); \ int count = GetInstanceCount(); \ for (int i = 0; i < childCount; ++i) { \ count -= (*(*children)[i])(level+1, cleanUp); \ } \ SkASSERT(count >= 0); \ if (gPrintInstCount && childCount > 0 && count > 0) { \ SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count); \ } \ if (cleanUp) { \ delete children; \ SkInstanceCountHelper::GetChildren() = NULL; \ } \ return GetInstanceCount(); \ } \ \ static void AddInstChild(int (*childCheckInstCnt)(int, bool)) { \ if (CheckInstanceCount != childCheckInstCnt) { \ SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \ if (NULL == SkInstanceCountHelper::GetChildren()) { \ SkInstanceCountHelper::GetChildren() = \ new SkTArray; \ } \ SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \ } \ } #else // Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by // causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays // compiling. #define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); } #define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { } #endif // Following are deprecated. They are defined only for backwards API compatibility. #define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className) #define SK_DEFINE_INST_COUNT(className) #define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) #endif // SkInstCnt_DEFINED