clang 22.0.0git
InProcessModuleCache.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
12#include "llvm/Support/AdvisoryLock.h"
13#include "llvm/Support/Chrono.h"
14
15#include <mutex>
16
17using namespace clang;
18using namespace tooling;
19using namespace dependencies;
20
21namespace {
22class ReaderWriterLock : public llvm::AdvisoryLock {
23 // TODO: Consider using std::atomic::{wait,notify_all} when we move to C++20.
24 std::unique_lock<std::shared_mutex> OwningLock;
25
26public:
27 ReaderWriterLock(std::shared_mutex &Mutex)
28 : OwningLock(Mutex, std::defer_lock) {}
29
30 Expected<bool> tryLock() override { return OwningLock.try_lock(); }
31
32 llvm::WaitForUnlockResult
33 waitForUnlockFor(std::chrono::seconds MaxSeconds) override {
34 assert(!OwningLock);
35 // We do not respect the timeout here. It's very generous for implicit
36 // modules, so we'd typically only reach it if the owner crashed (but so did
37 // we, since we run in the same process), or encountered deadlock.
38 (void)MaxSeconds;
39 std::shared_lock<std::shared_mutex> Lock(*OwningLock.mutex());
40 return llvm::WaitForUnlockResult::Success;
41 }
42
43 std::error_code unsafeMaybeUnlock() override {
44 // Unlocking the mutex here would trigger UB and we don't expect this to be
45 // actually called when compiling scanning modules due to the no-timeout
46 // guarantee above.
47 return {};
48 }
49
50 ~ReaderWriterLock() override = default;
51};
52
53class InProcessModuleCache : public ModuleCache {
54 ModuleCacheEntries &Entries;
55
56 // TODO: If we changed the InMemoryModuleCache API and relied on strict
57 // context hash, we could probably create more efficient thread-safe
58 // implementation of the InMemoryModuleCache such that it doesn't need to be
59 // recreated for each translation unit.
60 InMemoryModuleCache InMemory;
61
62public:
63 InProcessModuleCache(ModuleCacheEntries &Entries) : Entries(Entries) {}
64
65 void prepareForGetLock(StringRef Filename) override {}
66
67 std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename) override {
68 auto &CompilationMutex = [&]() -> std::shared_mutex & {
69 std::lock_guard<std::mutex> Lock(Entries.Mutex);
70 auto &Entry = Entries.Map[Filename];
71 if (!Entry)
72 Entry = std::make_unique<ModuleCacheEntry>();
73 return Entry->CompilationMutex;
74 }();
75 return std::make_unique<ReaderWriterLock>(CompilationMutex);
76 }
77
78 std::time_t getModuleTimestamp(StringRef Filename) override {
79 auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
80 std::lock_guard<std::mutex> Lock(Entries.Mutex);
81 auto &Entry = Entries.Map[Filename];
82 if (!Entry)
83 Entry = std::make_unique<ModuleCacheEntry>();
84 return Entry->Timestamp;
85 }();
86
87 return Timestamp.load();
88 }
89
90 void updateModuleTimestamp(StringRef Filename) override {
91 // Note: This essentially replaces FS contention with mutex contention.
92 auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
93 std::lock_guard<std::mutex> Lock(Entries.Mutex);
94 auto &Entry = Entries.Map[Filename];
95 if (!Entry)
96 Entry = std::make_unique<ModuleCacheEntry>();
97 return Entry->Timestamp;
98 }();
99
100 Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
101 }
102
103 InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }
104 const InMemoryModuleCache &getInMemoryModuleCache() const override {
105 return InMemory;
106 }
107};
108} // namespace
109
112 return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
113}
StringRef Filename
Definition: Format.cpp:3177
In-memory cache for modules.
The module cache used for compiling modules implicitly.
Definition: ModuleCache.h:26
virtual void prepareForGetLock(StringRef ModuleFilename)=0
May perform any work that only needs to be performed once for multiple calls getLock() with the same ...
virtual std::time_t getModuleTimestamp(StringRef ModuleFilename)=0
Returns the timestamp denoting the last time inputs of the module file were validated.
virtual InMemoryModuleCache & getInMemoryModuleCache()=0
Returns this process's view of the module cache.
virtual void updateModuleTimestamp(StringRef ModuleFilename)=0
Updates the timestamp denoting the last time inputs of the module file were validated.
virtual std::unique_ptr< llvm::AdvisoryLock > getLock(StringRef ModuleFilename)=0
Returns lock for the given module file. The lock is initially unlocked.
IntrusiveRefCntPtr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
The JSON file list parser is used to communicate input to InstallAPI.
llvm::StringMap< std::unique_ptr< ModuleCacheEntry > > Map