brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.2 KiB · d1e543b Raw
121 lines · cpp
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-exception6//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 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::WaitForUnlockResult33  waitForUnlockFor(std::chrono::seconds MaxSeconds) override {34    assert(!OwningLock);35    // We do not respect the timeout here. It's very generous for implicit36    // modules, so we'd typically only reach it if the owner crashed (but so did37    // 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 be45    // actually called when compiling scanning modules due to the no-timeout46    // 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 strict57  // context hash, we could probably create more efficient thread-safe58  // implementation of the InMemoryModuleCache such that it doesn't need to be59  // 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  void maybePrune(StringRef Path, time_t PruneInterval,104                  time_t PruneAfter) override {105    // FIXME: This only needs to be ran once per build, not in every106    // compilation. Call it once per service.107    maybePruneImpl(Path, PruneInterval, PruneAfter);108  }109 110  InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }111  const InMemoryModuleCache &getInMemoryModuleCache() const override {112    return InMemory;113  }114};115} // namespace116 117IntrusiveRefCntPtr<ModuleCache>118dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {119  return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);120}121