Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
213799 views
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
9
#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h"
10
11
#include "clang/Serialization/InMemoryModuleCache.h"
12
#include "llvm/Support/AdvisoryLock.h"
13
#include "llvm/Support/Chrono.h"
14
15
#include <mutex>
16
17
using namespace clang;
18
using namespace tooling;
19
using namespace dependencies;
20
21
namespace {
22
class 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
26
public:
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
53
class 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
62
public:
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
110
IntrusiveRefCntPtr<ModuleCache>
111
dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {
112
return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
113
}
114
115