Commit 3c7257e5 authored by Igor Kushnir's avatar Igor Kushnir
Browse files

Make all DUChainReferenceCounting globals thread_local

Move the variables into a simple new DUChainReferenceCounting class to
avoid the repetition of the `thread_local` keyword.

Reorder the declarations and initializations of two variables -
refCountingHasAdditionalRanges and refCountingRanges - to minimize
sizeof(DUChainReferenceCounting) while preserving the logic of the
variable ordering and grouping within the class.

Eliminate the mutex and the redundant dependency between threads.

This should work perfectly if the reference counting of each object is
confined to a single thread. This will break code that calls
DUChainReferenceCounting functions on the same object from multiple
threads. Hopefully such code does not exist.

This change does not break any kdevelop or kdev-python tests.
parent db67d592
......@@ -20,6 +20,8 @@
#include <QString>
#include <QFileInfo>
#include <QMutex>
#include <QMutexLocker>
#include <serialization/indexedstring.h>
#include "modificationrevisionset.h"
......
......@@ -24,6 +24,8 @@
#include <QIcon>
#include <QMimeDatabase>
#include <QMimeType>
#include <QMutex>
#include <QMutexLocker>
#include <kio_version.h>
#include <KIO/StatJob>
......
......@@ -20,30 +20,25 @@
*/
#include "referencecounting.h"
#include <QMutex>
#include <QMap>
#include <QAtomicInt>
#include "serialization/itemrepository.h"
namespace KDevelop {
thread_local bool doReferenceCounting = false;
//Protects the reference-counting data through a spin-lock
QMutex refCountingLock;
QMap<void*, QPair<uint, uint>>* refCountingRanges = new QMap<void*, QPair<uint, uint>>(); //ptr, <size, count>, leaked intentionally!
bool refCountingHasAdditionalRanges = false; //Whether 'refCountingRanges' is non-empty
//Speedup: In most cases there is only exactly one reference-counted range active,
//so the first reference-counting range can be marked here.
void* refCountingFirstRangeStart = nullptr;
QPair<uint, uint> refCountingFirstRangeExtent = qMakePair(0u, 0u);
DUChainReferenceCounting::DUChainReferenceCounting()
: doReferenceCounting{false}
, refCountingHasAdditionalRanges{false} //Whether 'refCountingRanges' is non-empty
, refCountingRanges{new QMap<void*, QPair<uint, uint>>} //ptr, <size, count>, leaked intentionally!
//Speedup: In most cases there is only exactly one reference-counted range active,
//so the first reference-counting range can be marked here.
, refCountingFirstRangeStart{nullptr}
, refCountingFirstRangeExtent{0u, 0u}
{
}
void KDevelop::disableDUChainReferenceCounting(void* start)
void DUChainReferenceCounting::disableDUChainReferenceCounting(void* start)
{
QMutexLocker lock(&refCountingLock);
if (refCountingFirstRangeStart &&
reinterpret_cast<char*>(refCountingFirstRangeStart) <= reinterpret_cast<char*>(start) &&
reinterpret_cast<char*>(start) < reinterpret_cast<char*>(refCountingFirstRangeStart) + refCountingFirstRangeExtent.first) {
......@@ -77,10 +72,8 @@ void KDevelop::disableDUChainReferenceCounting(void* start)
doReferenceCounting = false;
}
void KDevelop::enableDUChainReferenceCounting(void* start, unsigned int size)
void DUChainReferenceCounting::enableDUChainReferenceCounting(void* start, unsigned int size)
{
QMutexLocker lock(&refCountingLock);
doReferenceCounting = true;
if (refCountingFirstRangeStart &&
......@@ -138,6 +131,19 @@ void KDevelop::enableDUChainReferenceCounting(void* start, unsigned int size)
#endif
}
thread_local DUChainReferenceCounting duchainReferenceCounting;
void enableDUChainReferenceCounting(void* start, unsigned int size)
{
duchainReferenceCounting.enableDUChainReferenceCounting(start, size);
}
void disableDUChainReferenceCounting(void* start)
{
duchainReferenceCounting.disableDUChainReferenceCounting(start);
}
}
#ifdef TEST_REFERENCE_COUNTING
QAtomicInt& id()
......
......@@ -25,7 +25,6 @@
#include <QMap>
#include <QPair>
#include <QMutexLocker>
#include <utility>
......@@ -36,18 +35,35 @@
namespace KDevelop {
///Since shouldDoDUChainReferenceCounting is called extremely often, we export some internals into the header here,
///so the reference-counting code can be inlined.
class KDEVPLATFORMSERIALIZATION_EXPORT DUChainReferenceCounting
{
Q_DISABLE_COPY(DUChainReferenceCounting)
public:
DUChainReferenceCounting();
bool shouldDoDUChainReferenceCounting(void* item) const;
void enableDUChainReferenceCounting(void* start, unsigned int size);
void disableDUChainReferenceCounting(void* start);
private:
bool shouldDoDUChainReferenceCountingInternal(void* item) const;
bool doReferenceCounting;
bool refCountingHasAdditionalRanges;
QMap<void*, QPair<uint, uint>>* const refCountingRanges;
void* refCountingFirstRangeStart;
QPair<uint, uint> refCountingFirstRangeExtent;
};
KDEVPLATFORMSERIALIZATION_EXPORT extern thread_local bool doReferenceCounting;
KDEVPLATFORMSERIALIZATION_EXPORT extern QMutex refCountingLock;
KDEVPLATFORMSERIALIZATION_EXPORT extern QMap<void*, QPair<uint, uint>>* refCountingRanges;
KDEVPLATFORMSERIALIZATION_EXPORT extern bool refCountingHasAdditionalRanges;
KDEVPLATFORMSERIALIZATION_EXPORT extern void* refCountingFirstRangeStart;
KDEVPLATFORMSERIALIZATION_EXPORT extern QPair<uint, uint> refCountingFirstRangeExtent;
KDEVPLATFORMSERIALIZATION_EXPORT extern thread_local DUChainReferenceCounting duchainReferenceCounting;
KDEVPLATFORMSERIALIZATION_EXPORT void initReferenceCounting();
///@internal The spin-lock ,must already be locked
inline bool shouldDoDUChainReferenceCountingInternal(void* item)
inline bool shouldDoDUChainReferenceCounting(void* item)
{
return duchainReferenceCounting.shouldDoDUChainReferenceCounting(item);
}
inline bool DUChainReferenceCounting::shouldDoDUChainReferenceCountingInternal(void* item) const
{
auto it = std::as_const(*refCountingRanges).upperBound(item);
if (it != refCountingRanges->constBegin()) {
......@@ -60,13 +76,11 @@ inline bool shouldDoDUChainReferenceCountingInternal(void* item)
}
///This is used by indexed items to decide whether they should do reference-counting
inline bool shouldDoDUChainReferenceCounting(void* item)
inline bool DUChainReferenceCounting::shouldDoDUChainReferenceCounting(void* item) const
{
if (!doReferenceCounting) //Fast path, no place has been marked for reference counting, 99% of cases
return false;
QMutexLocker lock(&refCountingLock);
if (refCountingFirstRangeStart &&
(reinterpret_cast<char*>(refCountingFirstRangeStart) <= reinterpret_cast<char*>(item)) &&
(reinterpret_cast<char*>(item) < reinterpret_cast<char*>(refCountingFirstRangeStart) + refCountingFirstRangeExtent.first))
......
......@@ -30,6 +30,8 @@
#include <QDir>
#include <QFileInfo>
#include <QMutex>
#include <QMutexLocker>
#include <QRegularExpression>
#include <QRegExp>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment