skia2/include/core/SkInstCnt.h
commit-bot@chromium.org 2ab1ba0555 Make leak counters thread-safe and turn them on by default for Debug
Make leak counters implemented with SK_DECLARE_INST_COUNT thread-safe.
Enable the leak counting for Debug builds when Skia is built as a
static library. Having SK_DECLARE_INST_COUNT without
SK_DEFINE_INST_COUNT relies on static variables in member functions
declared in the header files. These might be duplicated in the clients
of the library when Skia is built as a dynamic library, producing
incorrect operation.

Protect the instance counter initialization step (initStep) by
using SkOnce.

Makes SkOnce.h part of the public API, since SkInstCnt is public.

Protect the per-class child list shared variable with a per-class mutex.

Changes the behavior in the way that if the child list has been
"cleaned up", it will still try to create subsequent child lists.

BUG=skia:1219
R=robertphillips@google.com, mtklein@google.com, bsalomon@google.com, bungeman@google.com, djsollen@google.com

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/99483003

git-svn-id: http://skia.googlecode.com/svn/trunk@13120 2bbb7eff-a529-9590-31e7-b0007b416f81
2014-01-17 17:55:02 +00:00

143 lines
8.5 KiB
C++

/*
* 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<int (*)(int, bool)>*& GetChildren() { \
static SkTArray<int (*)(int, bool)>* 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<int (*)(int, bool)>* 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<int (*)(int, bool)>; \
} \
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