aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp113
1 files changed, 113 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
new file mode 100644
index 000000000000..80db2d47d940
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// 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);
+}