[libclang] Implement ConcurrencyCheck using a recursive mutex to allow re-entrancy in the same thread.

The checks are performed only in DEBUG, it becomes no-op in release mode.

llvm-svn: 141582
This commit is contained in:
Argyrios Kyrtzidis
2011-10-10 21:57:12 +00:00
parent 7989460a1f
commit ebf0136956
2 changed files with 50 additions and 18 deletions

View File

@@ -151,16 +151,6 @@ private:
/// destroyed.
SmallVector<llvm::sys::Path, 4> TemporaryFiles;
/// \brief Simple hack to allow us to assert that ASTUnit is not being
/// used concurrently, which is not supported.
///
/// Clients should create instances of the ConcurrencyCheck class whenever
/// using the ASTUnit in a way that isn't intended to be concurrent, which is
/// just about any usage.
unsigned int ConcurrencyCheckValue;
static const unsigned int CheckLocked = 28573289;
static const unsigned int CheckUnlocked = 9803453;
/// \brief Counter that determines when we want to try building a
/// precompiled preamble.
///
@@ -406,21 +396,37 @@ private:
unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
/// \brief Allows us to assert that ASTUnit is not being used concurrently,
/// which is not supported.
///
/// Clients should create instances of the ConcurrencyCheck class whenever
/// using the ASTUnit in a way that isn't intended to be concurrent, which is
/// just about any usage.
/// Becomes a noop in release mode; only useful for debug mode checking.
class ConcurrencyState {
void *Mutex; // a llvm::sys::MutexImpl in debug;
public:
ConcurrencyState();
~ConcurrencyState();
void start();
void finish();
};
ConcurrencyState ConcurrencyCheckValue;
public:
class ConcurrencyCheck {
volatile ASTUnit &Self;
ASTUnit &Self;
public:
explicit ConcurrencyCheck(ASTUnit &Self)
: Self(Self)
{
assert(Self.ConcurrencyCheckValue == CheckUnlocked &&
"Concurrent access to ASTUnit!");
Self.ConcurrencyCheckValue = CheckLocked;
Self.ConcurrencyCheckValue.start();
}
~ConcurrencyCheck() {
Self.ConcurrencyCheckValue = CheckUnlocked;
Self.ConcurrencyCheckValue.finish();
}
};
friend class ConcurrencyCheck;

View File

@@ -45,6 +45,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdlib>
#include <cstdio>
@@ -99,7 +100,6 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
NestedMacroExpansions(true),
@@ -114,7 +114,6 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
}
ASTUnit::~ASTUnit() {
ConcurrencyCheckValue = CheckLocked;
CleanTemporaryFiles();
if (!PreambleFile.empty())
llvm::sys::Path(PreambleFile).eraseFromDisk();
@@ -2414,3 +2413,30 @@ void ASTUnit::PreambleData::countLines() const {
if (Buffer.back() != '\n')
++NumLines;
}
#ifndef NDEBUG
ASTUnit::ConcurrencyState::ConcurrencyState() {
Mutex = new llvm::sys::MutexImpl(/*recursive=*/true);
}
ASTUnit::ConcurrencyState::~ConcurrencyState() {
delete static_cast<llvm::sys::MutexImpl *>(Mutex);
}
void ASTUnit::ConcurrencyState::start() {
bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire();
assert(acquired && "Concurrent access to ASTUnit!");
}
void ASTUnit::ConcurrencyState::finish() {
static_cast<llvm::sys::MutexImpl *>(Mutex)->release();
}
#else // NDEBUG
ASTUnit::ConcurrencyState::ConcurrencyState() {}
ASTUnit::ConcurrencyState::~ConcurrencyState() {}
void ASTUnit::ConcurrencyState::start() {}
void ASTUnit::ConcurrencyState::finish() {}
#endif