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>
18static QReadWriteLock leakLock;
19struct LeakInfo
20{
21 LeakInfo() : refCount(0) {}
22 LeakInfo(const QString &n) : name(n), refCount(1) {}
23 QString name;
24 QAtomicInt refCount;
25};
26static 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
74ReferenceCounter::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}
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.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
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.
QAtomicInt m_referenceCount
virtual int IncrRef(void)
Increments reference count.
unsigned int uint
Definition: freesurround.h:24
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39