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