MythTV  master
referencecounter.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 #include <QString>
4 
5 #include "referencecounter.h"
6 #include "mythlogging.h"
7 
8 #ifdef EXTRA_DEBUG
9 // Uncomment this to see missing DecrRefs()
10 #define LEAK_DEBUG
11 // Uncoment this to see extra DecrRefs(), no memory will ever be freed..
12 //#define NO_DELETE_DEBUG
13 #endif
14 
15 #ifdef LEAK_DEBUG
16 #include <QReadWriteLock>
17 #include <QMap>
18 #include "../libmythui/mythimage.h"
19 static QReadWriteLock leakLock;
20 struct LeakInfo
21 {
22  LeakInfo() : refCount(0) {}
23  LeakInfo(const QString &n) : name(n), refCount(1) {}
24  QString name;
25  QAtomicInt refCount;
26 };
27 static QMap<ReferenceCounter*,LeakInfo> leakMap;
29 {
30  QReadLocker locker(&leakLock);
31  QList<uint64_t> logType;
32  QStringList logLines;
33 
34  uint cnt = 0;
35  QMap<ReferenceCounter*,LeakInfo>::iterator it = leakMap.begin();
36  for (; it != leakMap.end(); ++it)
37  {
38  if ((*it).refCount.fetchAndAddOrdered(0) == 0)
39  continue;
40  if ((*it).name.startsWith("CommandLineArg"))
41  continue;
42  if (!it.key()->m_logDebug)
43  continue;
44  cnt += 1;
45  }
46  logType += (cnt) ? VB_GENERAL : VB_REFCOUNT;
47  logLines += QString("Leaked %1 reference counted objects").arg(cnt);
48 
49  for (it = leakMap.begin(); it != leakMap.end(); ++it)
50  {
51  if ((*it).refCount.fetchAndAddOrdered(0) == 0)
52  continue;
53  if ((*it).name.startsWith("CommandLineArg"))
54  continue;
55  if (!it.key()->m_logDebug)
56  continue;
57 
58  logType += VB_REFCOUNT;
59  logLines +=
60  QString(" Leaked %1(0x%2) reference count %3")
61  .arg((*it).name)
62  .arg(reinterpret_cast<intptr_t>(it.key()),0,16)
63  .arg((*it).refCount);
64  }
65 
66  locker.unlock();
67 
68  for (uint i = 0; i < (uint)logType.size() && i < (uint)logLines.size(); i++)
69  LOG(logType[i], LOG_INFO, logLines[i]);
70 }
71 #else
73 #endif
74 
75 ReferenceCounter::ReferenceCounter(const QString &debugName, bool logDebug) :
76 #ifdef EXTRA_DEBUG
77  m_debugName(debugName),
78 #endif
79  m_logDebug(logDebug),
80  m_referenceCount(1)
81 {
82  (void) debugName;
83 #ifdef LEAK_DEBUG
84  QWriteLocker locker(&leakLock);
85  leakMap[this] = LeakInfo(debugName);
86 #endif
87 }
88 
90 {
91  if (m_referenceCount.fetchAndAddRelaxed(0) > 1)
92  {
93  LOG(VB_GENERAL, LOG_ERR,
94  "Object deleted with non-zero or one reference count!");
95  }
96 #ifdef LEAK_DEBUG
97  QWriteLocker locker(&leakLock);
98  leakMap.erase(leakMap.find(this));
99 #endif
100 }
101 
103 {
104  int val = m_referenceCount.fetchAndAddRelease(1) + 1;
105 
106  if (m_logDebug)
107  {
108 #ifdef EXTRA_DEBUG
109  LOG(VB_REFCOUNT, LOG_INFO, QString("%1(0x%2)::IncrRef() -> %3")
110  .arg(m_debugName).arg(reinterpret_cast<intptr_t>(this),0,16)
111  .arg(val));
112 #else
113  LOG(VB_REFCOUNT, LOG_INFO, QString("(0x%2)::IncrRef() -> %3")
114  .arg(reinterpret_cast<intptr_t>(this),0,16).arg(val));
115 #endif
116  }
117 
118 #ifdef LEAK_DEBUG
119  QReadLocker locker(&leakLock);
120  leakMap[this].refCount.fetchAndAddOrdered(1);
121 #endif
122 
123  return val;
124 }
125 
127 {
128  int val = m_referenceCount.fetchAndAddRelaxed(-1) - 1;
129 
130 #ifdef LEAK_DEBUG
131  {
132  QReadLocker locker(&leakLock);
133  leakMap[this].refCount.fetchAndAddOrdered(-1);
134  }
135 #endif
136 
137  if (m_logDebug)
138  {
139 #ifdef EXTRA_DEBUG
140  LOG(VB_REFCOUNT, LOG_INFO, QString("%1(0x%2)::DecrRef() -> %3")
141  .arg(m_debugName).arg(reinterpret_cast<intptr_t>(this),0,16)
142  .arg(val));
143 #else
144  LOG(VB_REFCOUNT, LOG_INFO, QString("(0x%2)::DecrRef() -> %3")
145  .arg(reinterpret_cast<intptr_t>(this),0,16).arg(val));
146 #endif
147  }
148 
149 #ifdef NO_DELETE_DEBUG
150  if (val < 0)
151  {
152  LOG(VB_REFCOUNT, LOG_ERR, QString("(0x%2)::DecrRef() -> %3 !!!")
153  .arg(reinterpret_cast<intptr_t>(this),0,16).arg(val));
154  }
155 #else
156  if (0 == val)
157  {
158  delete this;
159  return val;
160  }
161 #endif
162 
163  return val;
164 }
QAtomicInt m_referenceCount
unsigned int uint
Definition: compat.h:140
virtual int IncrRef(void)
Increments reference count.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
const char * name
Definition: ParseText.cpp:339
static void PrintDebug(void)
Print out any leaks if that level of debugging is enabled.
ReferenceCounter(const QString &debugName, bool logDebug=true)
Creates reference counter with an initial value of 1.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool m_logDebug
This is used to suppress creating LoggingItem classes for LoggingItem reference count changes.
virtual ~ReferenceCounter(void)
Called on destruction, will warn if object deleted with references in place.