Path: blob/main/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h"910#include "clang/Serialization/InMemoryModuleCache.h"11#include "llvm/Support/AdvisoryLock.h"12#include "llvm/Support/Chrono.h"1314#include <mutex>1516using namespace clang;17using namespace tooling;18using namespace dependencies;1920namespace {21class ReaderWriterLock : public llvm::AdvisoryLock {22// TODO: Consider using std::atomic::{wait,notify_all} when we move to C++20.23std::unique_lock<std::shared_mutex> OwningLock;2425public:26ReaderWriterLock(std::shared_mutex &Mutex)27: OwningLock(Mutex, std::defer_lock) {}2829Expected<bool> tryLock() override { return OwningLock.try_lock(); }3031llvm::WaitForUnlockResult32waitForUnlockFor(std::chrono::seconds MaxSeconds) override {33assert(!OwningLock);34// We do not respect the timeout here. It's very generous for implicit35// modules, so we'd typically only reach it if the owner crashed (but so did36// we, since we run in the same process), or encountered deadlock.37(void)MaxSeconds;38std::shared_lock<std::shared_mutex> Lock(*OwningLock.mutex());39return llvm::WaitForUnlockResult::Success;40}4142std::error_code unsafeMaybeUnlock() override {43// Unlocking the mutex here would trigger UB and we don't expect this to be44// actually called when compiling scanning modules due to the no-timeout45// guarantee above.46return {};47}4849~ReaderWriterLock() override = default;50};5152class InProcessModuleCache : public ModuleCache {53ModuleCacheEntries &Entries;5455// TODO: If we changed the InMemoryModuleCache API and relied on strict56// context hash, we could probably create more efficient thread-safe57// implementation of the InMemoryModuleCache such that it doesn't need to be58// recreated for each translation unit.59InMemoryModuleCache InMemory;6061public:62InProcessModuleCache(ModuleCacheEntries &Entries) : Entries(Entries) {}6364void prepareForGetLock(StringRef Filename) override {}6566std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename) override {67auto &CompilationMutex = [&]() -> std::shared_mutex & {68std::lock_guard<std::mutex> Lock(Entries.Mutex);69auto &Entry = Entries.Map[Filename];70if (!Entry)71Entry = std::make_unique<ModuleCacheEntry>();72return Entry->CompilationMutex;73}();74return std::make_unique<ReaderWriterLock>(CompilationMutex);75}7677std::time_t getModuleTimestamp(StringRef Filename) override {78auto &Timestamp = [&]() -> std::atomic<std::time_t> & {79std::lock_guard<std::mutex> Lock(Entries.Mutex);80auto &Entry = Entries.Map[Filename];81if (!Entry)82Entry = std::make_unique<ModuleCacheEntry>();83return Entry->Timestamp;84}();8586return Timestamp.load();87}8889void updateModuleTimestamp(StringRef Filename) override {90// Note: This essentially replaces FS contention with mutex contention.91auto &Timestamp = [&]() -> std::atomic<std::time_t> & {92std::lock_guard<std::mutex> Lock(Entries.Mutex);93auto &Entry = Entries.Map[Filename];94if (!Entry)95Entry = std::make_unique<ModuleCacheEntry>();96return Entry->Timestamp;97}();9899Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));100}101102InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }103const InMemoryModuleCache &getInMemoryModuleCache() const override {104return InMemory;105}106};107} // namespace108109IntrusiveRefCntPtr<ModuleCache>110dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {111return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);112}113114115