File workaround-hang-on-exit.patch of Package kdevelop5
diff --git a/kdevplatform/language/duchain/duchain.cpp b/kdevplatform/language/duchain/duchain.cpp
index d9d1700ddf8dd2cd18b838a48c5b0a9841acf69c..d92bdf2ed0000e3e468a7d462389ae5c6941eada 100644
--- a/kdevplatform/language/duchain/duchain.cpp
+++ b/kdevplatform/language/duchain/duchain.cpp
@@ -433,7 +433,18 @@ public:
// qCDebug(LANGUAGE) << "duchain: removing document" << context->url().str();
Q_ASSERT(hasChainForIndex(index));
+ if (!hasChainForIndex(index)) {
+ qCCritical(LANGUAGE) << Q_FUNC_INFO << "index" << index << "has no chain";
+ return;
+ }
Q_ASSERT(m_chainsByUrl.contains(context->url(), context));
+ if (!m_chainsByUrl.contains(context->url(), context)) {
+ qCCritical(LANGUAGE) << Q_FUNC_INFO << "Context" << context << "has no registered chainByUrl";
+ if (context) {
+ qCritical() << "\t" << "url=" << context->url();
+ }
+ return;
+ }
m_chainsByUrl.remove(context->url(), context);
@@ -446,6 +457,10 @@ public:
l.relock();
Q_ASSERT(hasChainForIndex(index));
+ if (!hasChainForIndex(index)) {
+ qCCritical(LANGUAGE) << Q_FUNC_INFO << "index" << index << "has no chain";
+ return;
+ }
QMutexLocker lock(&DUChain::chainsByIndexLock);
DUChain::chainsByIndex[index] = nullptr;
@@ -768,7 +783,7 @@ public:
//Here we wait for all parsing-threads to stop their processing
for (const auto language : qAsConst(languages)) {
if (lockFlag == TryLock) {
- if (!language->parseLock()->tryLockForWrite()) {
+ if (!language->parseLock() || !language->parseLock()->tryLockForWrite()) {
qCDebug(LANGUAGE) << "Aborting cleanup because language plugin is still parsing:" <<
language->name();
// some language is still parsing, don't interfere with the cleanup
@@ -1587,8 +1602,9 @@ void DUChain::documentClosed(IDocument* document)
const auto currentDocumentContexts = sdDUChainPrivate->m_openDocumentContexts;
for (const ReferencedTopDUContext& top : currentDocumentContexts) {
- if (top->url() == url)
+ if (!top || (sdDUChainPrivate->m_referenceCounts[top] == 0 || top->url() == url)) {
sdDUChainPrivate->m_openDocumentContexts.remove(top);
+ }
}
}
@@ -1688,11 +1704,16 @@ static void finalCleanup()
qCDebug(LANGUAGE) << "doing final cleanup";
int cleaned = 0;
+ int passes = 0;
while ((cleaned = globalItemRepositoryRegistry().finalCleanup())) {
+ passes += 1;
qCDebug(LANGUAGE) << "cleaned" << cleaned << "B";
if (cleaned < 1000) {
qCDebug(LANGUAGE) << "cleaned enough";
break;
+ } else if (passes >= 100) {
+ qCWarning(LANGUAGE) << "cleaned" << passes << "passes, last was" << cleaned << "B; that's enough";
+ break;
}
}
qCDebug(LANGUAGE) << "final cleanup ready";
diff --git a/kdevplatform/serialization/itemrepository.h b/kdevplatform/serialization/itemrepository.h
index f8c2c58307..8a6179bbd4 100644
--- a/kdevplatform/serialization/itemrepository.h
+++ b/kdevplatform/serialization/itemrepository.h
@@ -508,7 +508,7 @@ class Bucket {
}
template <class Repository>
- void deleteItem(unsigned short index, unsigned int hash, Repository& repository)
+ bool deleteItem(unsigned short index, unsigned int hash, Repository& repository)
{
ifDebugLostSpace(Q_ASSERT(!lostSpace()); )
@@ -527,8 +527,23 @@ class Bucket {
currentIndex = followerIndex(currentIndex);
//If this assertion triggers, the deleted item was not registered under the given hash
Q_ASSERT(currentIndex);
+ if (!currentIndex) {
+ qWarning() << QStringLiteral("Bucket::deleteItem(%1,%2,%3)").arg(index).arg(hash).arg(repository.repositoryName())
+ << ": early return because currentIndex==0";
+ return false;
+ } else if (currentIndex == previousIndex) {
+ qWarning() << QStringLiteral("Bucket::deleteItem(%1,%2,%3)").arg(index).arg(hash).arg(repository.repositoryName())
+ << "early return because currentIndex==previousIndex==" << currentIndex;
+ return false;
+ }
}
Q_ASSERT(currentIndex == index);
+ if (currentIndex != index) {
+ qWarning() << QStringLiteral("Bucket::deleteItem(%1,%2,%3)").arg(index).arg(hash).arg(repository.repositoryName())
+ << "early return because currentIndex != index ("
+ << currentIndex << "!=" << index;
+ return false;
+ }
if (!previousIndex)
//The item was directly in the object map
@@ -594,6 +609,7 @@ class Bucket {
}
#endif
// Q_ASSERT(canAllocateItem(size));
+ return true;
}
///@warning The returned item may be in write-protected memory, so never try doing a const_cast and changing some data
@@ -655,9 +671,10 @@ class Bucket {
int finalCleanup(Repository& repository)
{
int changed = 0;
+ bool dirty = m_dirty;
- while (m_dirty) {
- m_dirty = false;
+ while (dirty) {
+ dirty = false;
for (uint a = 0; a < ObjectMapSize; ++a) {
uint currentIndex = m_objectMap[a];
@@ -669,15 +686,24 @@ class Bucket {
if (!ItemRequest::persistent(item)) {
changed += item->itemSize();
- deleteItem(currentIndex, item->hash(), repository);
- m_dirty = true; //Set to dirty so we re-iterate
- break;
+ if (deleteItem(currentIndex, item->hash(), repository)) {
+ dirty = true; //Set to dirty so we re-iterate
+ break;
+ } else {
+ qWarning() << "\tdidn't delete item of size" << item->itemSize();
+ }
}
+ uint prevIndex = currentIndex;
currentIndex = followerIndex(currentIndex);
+ if (currentIndex == prevIndex) {
+ qWarning() << Q_FUNC_INFO << "avoided deadloop in repository" << repository.repositoryName();
+ currentIndex = 0;
+ }
}
}
}
+ m_dirty = dirty;
return changed;
}
@@ -947,14 +973,23 @@ class Bucket {
/// @param index the index of an item @return The index of the next item in the chain of items with a same local hash, or zero
inline unsigned short followerIndex(unsigned short index) const
{
- Q_ASSERT(index >= 2);
- return *reinterpret_cast<unsigned short*>(m_data + (index - 2));
+// Q_ASSERT(index >= 2);
+ if (index >= 2) {
+ return *reinterpret_cast<unsigned short*>(m_data + (index - 2));
+ } else {
+ qWarning() << Q_FUNC_INFO << "index=" << index << "; returning 0";
+ return 0;
+ }
}
void setFollowerIndex(unsigned short index, unsigned short follower)
{
- Q_ASSERT(index >= 2);
- *reinterpret_cast<unsigned short*>(m_data + (index - 2)) = follower;
+// Q_ASSERT(index >= 2);
+ if (index >= 2) {
+ *reinterpret_cast<unsigned short*>(m_data + (index - 2)) = follower;
+ } else {
+ qWarning() << Q_FUNC_INFO << "index=" << index << "; follower set to 0 instead of" << follower;
+ }
}
// Only returns the current value if the item is actually free
inline unsigned short freeSize(unsigned short index) const
@@ -1404,6 +1439,16 @@ class ItemRepository : public AbstractItemRepository {
//Make sure the index was reachable through the hash chain
Q_ASSERT(bucketPtr);
+ if (!bucketPtr) {
+ qWarning() << Q_FUNC_INFO << "index" << index
+ << "not reachable through hash chain; previous bucket="
+ << previousBucketPtr << "next="
+ << (previousBucketPtr ? previousBucketPtr->nextBucketForHash(hash) : 0);
+ if (previousBucketPtr) {
+ previousBucketPtr->setNextBucketForHash(hash, 0);
+ }
+ return;
+ }
--m_statItemCount;