clang 22.0.0git
InProcessModuleCache.cpp
Go to the documentation of this file.
1//===- InProcessModuleCache.cpp - Implicit Module Cache ---------*- C++ -*-===//
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 dependencies;
19
20namespace {
21class ReaderWriterLock : public llvm::AdvisoryLock {
22 // TODO: Consider using std::atomic::{wait,notify_all} when we move to C++20.
23 std::unique_lock<std::shared_mutex> OwningLock;
24
25public:
26 ReaderWriterLock(std::shared_mutex &Mutex)
27 : OwningLock(Mutex, std::defer_lock) {}
28
29 Expected<bool> tryLock() override { return OwningLock.try_lock(); }
30
31 llvm::WaitForUnlockResult
32 waitForUnlockFor(std::chrono::seconds MaxSeconds) override {
33 assert(!OwningLock);
34 // We do not respect the timeout here. It's very generous for implicit
35 // modules, so we'd typically only reach it if the owner crashed (but so did
36 // we, since we run in the same process), or encountered deadlock.
37 (void)MaxSeconds;
38 std::shared_lock<std::shared_mutex> Lock(*OwningLock.mutex());
39 return llvm::WaitForUnlockResult::Success;
40 }
41
42 std::error_code unsafeMaybeUnlock() override {
43 // Unlocking the mutex here would trigger UB and we don't expect this to be
44 // actually called when compiling scanning modules due to the no-timeout
45 // guarantee above.
46 return {};
47 }
48
49 ~ReaderWriterLock() override = default;
50};
51
52class InProcessModuleCache : public ModuleCache {
53 ModuleCacheEntries &Entries;
54
55 // TODO: If we changed the InMemoryModuleCache API and relied on strict
56 // context hash, we could probably create more efficient thread-safe
57 // implementation of the InMemoryModuleCache such that it doesn't need to be
58 // recreated for each translation unit.
59 InMemoryModuleCache InMemory;
60
61public:
62 InProcessModuleCache(ModuleCacheEntries &Entries) : Entries(Entries) {}
63
64 void prepareForGetLock(StringRef Filename) override {}
65
66 std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename) override {
67 auto &CompilationMutex = [&]() -> std::shared_mutex & {
68 std::lock_guard<std::mutex> Lock(Entries.Mutex);
69 auto &Entry = Entries.Map[Filename];
70 if (!Entry)
71 Entry = std::make_unique<ModuleCacheEntry>();
72 return Entry->CompilationMutex;
73 }();
74 return std::make_unique<ReaderWriterLock>(CompilationMutex);
75 }
76
77 std::time_t getModuleTimestamp(StringRef Filename) override {
78 auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
79 std::lock_guard<std::mutex> Lock(Entries.Mutex);
80 auto &Entry = Entries.Map[Filename];
81 if (!Entry)
82 Entry = std::make_unique<ModuleCacheEntry>();
83 return Entry->Timestamp;
84 }();
85
86 return Timestamp.load();
87 }
88
89 void updateModuleTimestamp(StringRef Filename) override {
90 // Note: This essentially replaces FS contention with mutex contention.
91 auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
92 std::lock_guard<std::mutex> Lock(Entries.Mutex);
93 auto &Entry = Entries.Map[Filename];
94 if (!Entry)
95 Entry = std::make_unique<ModuleCacheEntry>();
96 return Entry->Timestamp;
97 }();
98
99 Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
100 }
101
102 void maybePrune(StringRef Path, time_t PruneInterval,
103 time_t PruneAfter) override {
104 // FIXME: This only needs to be ran once per build, not in every
105 // compilation. Call it once per service.
106 maybePruneImpl(Path, PruneInterval, PruneAfter);
107 }
108
109 InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }
110 const InMemoryModuleCache &getInMemoryModuleCache() const override {
111 return InMemory;
112 }
113};
114} // namespace
115
118 return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
119}
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:26
IntrusiveRefCntPtr< ModuleCache > makeInProcessModuleCache(ModuleCacheEntries &Entries)
The JSON file list parser is used to communicate input to InstallAPI.
void maybePruneImpl(StringRef Path, time_t PruneInterval, time_t PruneAfter)
Shared implementation of ModuleCache::maybePrune().