
This reverts commit 7a242387c950c7060143da6da0e6fb91f36bb458. Even after 175f8a44, the Modules/fmodules-validate-once-per-build-session.c test is not fixed on the clang-armv8-quick build bot. (Failure occurs on line 114.)
114 lines
3.9 KiB
C++
114 lines
3.9 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h"
|
|
|
|
#include "clang/Serialization/InMemoryModuleCache.h"
|
|
#include "llvm/Support/AdvisoryLock.h"
|
|
#include "llvm/Support/Chrono.h"
|
|
|
|
#include <mutex>
|
|
|
|
using namespace clang;
|
|
using namespace tooling;
|
|
using namespace dependencies;
|
|
|
|
namespace {
|
|
class ReaderWriterLock : public llvm::AdvisoryLock {
|
|
// TODO: Consider using std::atomic::{wait,notify_all} when we move to C++20.
|
|
std::unique_lock<std::shared_mutex> OwningLock;
|
|
|
|
public:
|
|
ReaderWriterLock(std::shared_mutex &Mutex)
|
|
: OwningLock(Mutex, std::defer_lock) {}
|
|
|
|
Expected<bool> tryLock() override { return OwningLock.try_lock(); }
|
|
|
|
llvm::WaitForUnlockResult
|
|
waitForUnlockFor(std::chrono::seconds MaxSeconds) override {
|
|
assert(!OwningLock);
|
|
// We do not respect the timeout here. It's very generous for implicit
|
|
// modules, so we'd typically only reach it if the owner crashed (but so did
|
|
// we, since we run in the same process), or encountered deadlock.
|
|
(void)MaxSeconds;
|
|
std::shared_lock<std::shared_mutex> Lock(*OwningLock.mutex());
|
|
return llvm::WaitForUnlockResult::Success;
|
|
}
|
|
|
|
std::error_code unsafeMaybeUnlock() override {
|
|
// Unlocking the mutex here would trigger UB and we don't expect this to be
|
|
// actually called when compiling scanning modules due to the no-timeout
|
|
// guarantee above.
|
|
return {};
|
|
}
|
|
|
|
~ReaderWriterLock() override = default;
|
|
};
|
|
|
|
class InProcessModuleCache : public ModuleCache {
|
|
ModuleCacheEntries &Entries;
|
|
|
|
// TODO: If we changed the InMemoryModuleCache API and relied on strict
|
|
// context hash, we could probably create more efficient thread-safe
|
|
// implementation of the InMemoryModuleCache such that it doesn't need to be
|
|
// recreated for each translation unit.
|
|
InMemoryModuleCache InMemory;
|
|
|
|
public:
|
|
InProcessModuleCache(ModuleCacheEntries &Entries) : Entries(Entries) {}
|
|
|
|
void prepareForGetLock(StringRef Filename) override {}
|
|
|
|
std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename) override {
|
|
auto &CompilationMutex = [&]() -> std::shared_mutex & {
|
|
std::lock_guard<std::mutex> Lock(Entries.Mutex);
|
|
auto &Entry = Entries.Map[Filename];
|
|
if (!Entry)
|
|
Entry = std::make_unique<ModuleCacheEntry>();
|
|
return Entry->CompilationMutex;
|
|
}();
|
|
return std::make_unique<ReaderWriterLock>(CompilationMutex);
|
|
}
|
|
|
|
std::time_t getModuleTimestamp(StringRef Filename) override {
|
|
auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
|
|
std::lock_guard<std::mutex> Lock(Entries.Mutex);
|
|
auto &Entry = Entries.Map[Filename];
|
|
if (!Entry)
|
|
Entry = std::make_unique<ModuleCacheEntry>();
|
|
return Entry->Timestamp;
|
|
}();
|
|
|
|
return Timestamp.load();
|
|
}
|
|
|
|
void updateModuleTimestamp(StringRef Filename) override {
|
|
// Note: This essentially replaces FS contention with mutex contention.
|
|
auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
|
|
std::lock_guard<std::mutex> Lock(Entries.Mutex);
|
|
auto &Entry = Entries.Map[Filename];
|
|
if (!Entry)
|
|
Entry = std::make_unique<ModuleCacheEntry>();
|
|
return Entry->Timestamp;
|
|
}();
|
|
|
|
Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
|
|
}
|
|
|
|
InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }
|
|
const InMemoryModuleCache &getInMemoryModuleCache() const override {
|
|
return InMemory;
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
IntrusiveRefCntPtr<ModuleCache>
|
|
dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {
|
|
return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
|
|
}
|