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#ifndef SkInstCnt_DEFINED
9#define SkInstCnt_DEFINED
10
11/* To count all instances of T, including all subclasses of T,
12 * add SK_DECLARE_INST_COUNT(T) to T's class definition.
13 * If you want to print out counts of leaked instances, set gPrintInstCount to true in main().
14 *
15 * E.g.
16 *   struct Base { SK_DECLARE_INST_COUNT(Base) };
17 *   struct A : public Base {};
18 *   struct SubBase : public Base { SK_DECLARE_INST_COUNT(SubBase); }
19 *   struct B : public SubBase {};
20 *
21 * If gPrintInstCount is true, at the program exit you will see something like:
22 *   Base: <N> leaked instances
23 *   SubBase: <M> leaked instances
24 * where N >= M.  Leaked instances of A count against Base; leaked instances of B count against
25 * both SubBase and Base.
26 *
27 * If SK_ENABLE_INST_COUNT is not defined or defined to 0, or we're in a shared library build,
28 * this entire system is compiled away to a noop.
29 */
30
31#include "SkTypes.h"
32
33#if SK_ENABLE_INST_COUNT && !defined(SKIA_DLL) // See skia:2058 for why we noop on shared builds.
34    #include "SkThread.h"
35    #include <stdlib.h>
36
37    #define SK_DECLARE_INST_COUNT(T)                           \
38        static const char* InstCountClassName() { return #T; } \
39        SkInstCount<T, T::InstCountClassName> fInstCnt;        \
40        static int32_t GetInstanceCount() { return SkInstCount<T, InstCountClassName>::Count(); }
41
42    extern bool gPrintInstCount;
43
44    template <typename T, const char*(Name)()>
45    class SkInstCount {
46    public:
47        SkInstCount()                   { Inc(); }
48        SkInstCount(const SkInstCount&) { Inc(); }
49        ~SkInstCount()                  { sk_atomic_dec(&gCount); }
50
51        SkInstCount& operator==(const SkInstCount&) { return *this; } // == can't change the count.
52
53        static void Inc() {
54            // If it's the first time we go from 0 to 1, register to print leaks at process exit.
55            if (0 == sk_atomic_inc(&gCount) && sk_atomic_cas(&gRegistered, 0, 1)) {
56                atexit(PrintAtExit);
57            }
58        }
59
60        static void PrintAtExit() {
61            int32_t leaks = Count();
62            if (gPrintInstCount && leaks > 0) {
63                SkDebugf("Leaked %s: %d\n", Name(), leaks);
64            }
65        }
66
67        // FIXME: Used publicly by unit tests.  Seems like a bad idea in a DM world.
68        static int32_t Count() { return sk_acquire_load(&gCount); }
69
70    private:
71        static int32_t gCount, gRegistered;
72    };
73    // As template values, these will be deduplicated.  (No one-definition rule problems.)
74    template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gCount      = 0;
75    template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gRegistered = 0;
76#else
77    #define SK_DECLARE_INST_COUNT(T)
78#endif
79
80void SkInstCountPrintLeaksOnExit();
81
82#endif // SkInstCnt_DEFINED
83