1b81877880
1 Remove atExit feature: clients can do it just as well as SkOnce can. 2 Remove support for functors: no one but the unit test did that. 3 Remove support for unused non-static SkOnceFlag (no SK_ONCE_INIT). 4 Add SkOnce variants for no-arg functions so we're not forced to pass dummy values all the time. 5 Merge SkSpinlock and SkOnceFlag, making all members private. 6 More notes about memory barriers, adding an acquire load after acquiring the spinlock. BUG=skia: R=bungeman@google.com, mtklein@google.com, reed@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/302083003
143 lines
8.5 KiB
C++
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); \
|
|
sk_atomic_inc(GetInstanceCountPtr()); \
|
|
} \
|
|
\
|
|
static void init() { \
|
|
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
|