1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#ifndef SkInstCnt_DEFINED
10#define SkInstCnt_DEFINED
11
12/*
13 * The instance counting system consists of three macros that create the
14 * instance counting machinery. A class is added to the system by adding:
15 *   SK_DECLARE_INST_COUNT at the top of its declaration for derived classes
16 *   SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class
17 * At the end of an application a call to all the "root" objects'
18 * CheckInstanceCount methods should be made
19 */
20#include "SkTypes.h"
21
22#if SK_ENABLE_INST_COUNT
23// Static variables inside member functions below may be defined multiple times
24// if Skia is being used as a dynamic library. Instance counting should be on
25// only for static builds. See bug skia:2058.
26#if defined(SKIA_DLL)
27#error Instance counting works only when Skia is built as a static library.
28#endif
29
30#include "SkOnce.h"
31#include "SkTArray.h"
32#include "SkThread.h"
33extern bool gPrintInstCount;
34
35// The non-root classes just register themselves with their parent
36#define SK_DECLARE_INST_COUNT(className)                                    \
37    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
38                                   INHERITED::AddInstChild(CheckInstanceCount);)
39
40// The root classes registers a function to print out the memory stats when
41// the app ends
42#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
43    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
44
45#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
46    class SkInstanceCountHelper {                                           \
47    public:                                                                 \
48        SkInstanceCountHelper() {                                           \
49            SK_DECLARE_STATIC_ONCE(once);                                   \
50            SkOnce(&once, init);                                            \
51            sk_atomic_inc(GetInstanceCountPtr());                           \
52        }                                                                   \
53                                                                            \
54        static void init() {                                                \
55            initStep                                                        \
56        }                                                                   \
57                                                                            \
58        SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
59            sk_atomic_inc(GetInstanceCountPtr());                           \
60        }                                                                   \
61                                                                            \
62        ~SkInstanceCountHelper() {                                          \
63            sk_atomic_dec(GetInstanceCountPtr());                           \
64        }                                                                   \
65                                                                            \
66        static int32_t* GetInstanceCountPtr() {                             \
67            static int32_t gInstanceCount;                                  \
68            return &gInstanceCount;                                         \
69        }                                                                   \
70                                                                            \
71        static SkTArray<int (*)(int, bool)>*& GetChildren() {               \
72            static SkTArray<int (*)(int, bool)>* gChildren;                 \
73            return gChildren;                                               \
74        }                                                                   \
75                                                                            \
76        static void create_mutex(SkMutex** mutex) {                         \
77            *mutex = SkNEW(SkMutex);                                        \
78        }                                                                   \
79        static SkBaseMutex& GetChildrenMutex() {                            \
80            static SkMutex* childrenMutex;                                  \
81            SK_DECLARE_STATIC_ONCE(once);                                   \
82            SkOnce(&once, className::SkInstanceCountHelper::create_mutex, &childrenMutex);\
83            return *childrenMutex;                                          \
84        }                                                                   \
85                                                                            \
86    } fInstanceCountHelper;                                                 \
87                                                                            \
88    static int32_t GetInstanceCount() {                                     \
89        return *SkInstanceCountHelper::GetInstanceCountPtr();               \
90    }                                                                       \
91                                                                            \
92    static void exitPrint() {                                               \
93        CheckInstanceCount(0, true);                                        \
94    }                                                                       \
95                                                                            \
96    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
97        if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
98            SkDebugf("%*c Leaked %s: %d\n",                                 \
99                     4*level, ' ', #className,                              \
100                     GetInstanceCount());                                   \
101        }                                                                   \
102        if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
103            return GetInstanceCount();                                      \
104        }                                                                   \
105        SkTArray<int (*)(int, bool)>* children = \
106            SkInstanceCountHelper::GetChildren();                           \
107        int childCount = children->count();                                 \
108        int count = GetInstanceCount();                                     \
109        for (int i = 0; i < childCount; ++i) {                              \
110            count -= (*(*children)[i])(level+1, cleanUp);                   \
111        }                                                                   \
112        SkASSERT(count >= 0);                                               \
113        if (gPrintInstCount && childCount > 0 && count > 0) {               \
114            SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
115        }                                                                   \
116        if (cleanUp) {                                                      \
117            delete children;                                                \
118            SkInstanceCountHelper::GetChildren() = NULL;                    \
119        }                                                                   \
120        return GetInstanceCount();                                          \
121    }                                                                       \
122                                                                            \
123    static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
124        if (CheckInstanceCount != childCheckInstCnt) {                      \
125            SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \
126            if (NULL == SkInstanceCountHelper::GetChildren()) {             \
127                SkInstanceCountHelper::GetChildren() =                      \
128                    new SkTArray<int (*)(int, bool)>;                       \
129            }                                                               \
130            SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
131        }                                                                   \
132    }
133
134#else
135// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
136// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
137// compiling.
138#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
139#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
140#endif
141
142// Following are deprecated. They are defined only for backwards API compatibility.
143#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
144#define SK_DEFINE_INST_COUNT(className)
145#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
146
147#endif // SkInstCnt_DEFINED
148