JDevlieghere created this revision.
JDevlieghere added reviewers: bulbazord, clayborg, jingham, jasonmolenda.
Herald added a project: All.
JDevlieghere requested review of this revision.

We recently saw an uptick in internal reports complaining that LLDB is slow 
when source on NFS are inaccessible. I looked at the SourceManger and its cache 
and I think there’s some room for improvement in terms of reducing file system 
accesses:

1. We always resolve the path.
2. We always check the timestamp.
3. We always recheck the file system for negative cache hits.

D153726 <https://reviews.llvm.org/D153726> fixes (1) but (2) and (3) are 
necessary because of the cache’s current design. Source files are cached at the 
debugger level which means that the source file cache can span multiple targets 
and processes. It wouldn't be correct to not reload a modified or new file from 
disk.

We can however significantly reduce the number of file system accesses by using 
a two level cache design: one cache at the debugger level and one at the 
process level.

- The cache at the debugger level works the way it does today. There is no 
negative cache: if we can't find the file on disk, we'll try again next time 
the cache is queried. If a cached file's timestamp changes or if its path 
remapping changes, the cached file is evicted and we reload it from disk.
- The cache at the process level is design to avoid accessing the file system. 
It doesn't check the file's modification time. It caches negative results, so 
if a file didn't exist, it doesn't try to reread it from disk. Checking if the 
path remapping changed is cheap (doesn't involve checking the file system) so 
this is the only way for a file to get evicted from the process cache.

The result of this patch is that LLDB will not show you new content if a file 
is modified or created while a process is running. I would argue that this is 
what most people would expect, but it is a change from how LLDB behaves today.

For an average stop, we query the cache four times. With the current 
implementation, that's 4 stats to get the modification time, If the file 
doesn't exist on disk, that's another 4 stats. Before D153726 
<https://reviews.llvm.org/D153726>, if the path starts with a `~` there are 
another additional 4 calls to realpath. When debugging sources on a slow 
(network) filesystem, this quickly adds up.

In addition to the two level caching, this patch also adds a `source` logging 
channel and synchronization to the source file cache. The logging was helpful 
during development and hopefully will help us triage issues in the future. The 
synchronization isn't a new requirement: as the cache is shared across targets, 
there is no guarantees that it can't be accessed concurrently.


https://reviews.llvm.org/D153834

Files:
  lldb/include/lldb/Core/SourceManager.h
  lldb/include/lldb/Target/Process.h
  lldb/include/lldb/Utility/LLDBLog.h
  lldb/source/Commands/CommandObjectSource.cpp
  lldb/source/Core/SourceManager.cpp
  lldb/source/Utility/LLDBLog.cpp
  lldb/test/API/source-manager/TestSourceManager.py
  lldb/unittests/Core/SourceManagerTest.cpp

Index: lldb/unittests/Core/SourceManagerTest.cpp
===================================================================
--- lldb/unittests/Core/SourceManagerTest.cpp
+++ lldb/unittests/Core/SourceManagerTest.cpp
@@ -30,7 +30,7 @@
   // Insert: foo
   FileSpec foo_file_spec("foo");
   auto foo_file_sp =
-      std::make_shared<SourceManager::File>(foo_file_spec, nullptr);
+      std::make_shared<SourceManager::File>(foo_file_spec, lldb::DebuggerSP());
   cache.AddSourceFile(foo_file_spec, foo_file_sp);
 
   // Query: foo, expect found.
@@ -44,7 +44,7 @@
   // Insert: foo
   FileSpec foo_file_spec("foo");
   auto foo_file_sp =
-      std::make_shared<SourceManager::File>(foo_file_spec, nullptr);
+      std::make_shared<SourceManager::File>(foo_file_spec, lldb::DebuggerSP());
   cache.AddSourceFile(foo_file_spec, foo_file_sp);
 
   // Query: bar, expect not found.
@@ -62,8 +62,8 @@
   FileSystem::Instance().Resolve(resolved_foo_file_spec);
 
   // Create the file with the resolved file spec.
-  auto foo_file_sp =
-      std::make_shared<SourceManager::File>(resolved_foo_file_spec, nullptr);
+  auto foo_file_sp = std::make_shared<SourceManager::File>(
+      resolved_foo_file_spec, lldb::DebuggerSP());
 
   // Cache the result with the unresolved file spec.
   cache.AddSourceFile(foo_file_spec, foo_file_sp);
Index: lldb/test/API/source-manager/TestSourceManager.py
===================================================================
--- lldb/test/API/source-manager/TestSourceManager.py
+++ lldb/test/API/source-manager/TestSourceManager.py
@@ -10,6 +10,7 @@
 """
 
 import os
+import io
 import stat
 
 import lldb
@@ -37,6 +38,33 @@
         self.file = self.getBuildArtifact("main-copy.c")
         self.line = line_number("main.c", "// Set break point at this line.")
 
+    def modify_content(self):
+
+        # Read the main.c file content.
+        with io.open(self.file, "r", newline="\n") as f:
+            original_content = f.read()
+            if self.TraceOn():
+                print("original content:", original_content)
+
+        # Modify the in-memory copy of the original source code.
+        new_content = original_content.replace("Hello world", "Hello lldb", 1)
+
+        # Modify the source code file.
+        # If the source was read only, the copy will also be read only.
+        # Run "chmod u+w" on it first so we can modify it.
+        statinfo = os.stat(self.file)
+        os.chmod(self.file, statinfo.st_mode | stat.S_IWUSR)
+
+        with io.open(self.file, "w", newline="\n") as f:
+            time.sleep(1)
+            f.write(new_content)
+            if self.TraceOn():
+                print("new content:", new_content)
+                print(
+                    "os.path.getmtime() after writing new content:",
+                    os.path.getmtime(self.file),
+                )
+
     def get_expected_stop_column_number(self):
         """Return the 1-based column number of the first non-whitespace
         character in the breakpoint source line."""
@@ -234,32 +262,20 @@
             self.fail("Fail to display source level breakpoints")
         self.assertTrue(int(m.group(1)) > 0)
 
-        # Read the main.c file content.
-        with io.open(self.file, "r", newline="\n") as f:
-            original_content = f.read()
-            if self.TraceOn():
-                print("original content:", original_content)
-
-        # Modify the in-memory copy of the original source code.
-        new_content = original_content.replace("Hello world", "Hello lldb", 1)
+        # Modify content
+        self.modify_content()
 
-        # Modify the source code file.
-        # If the source was read only, the copy will also be read only.
-        # Run "chmod u+w" on it first so we can modify it.
-        statinfo = os.stat(self.file)
-        os.chmod(self.file, statinfo.st_mode | stat.S_IWUSR)
+        # Display the source code again. We should not see the updated line.
+        self.expect(
+            "source list -f main-copy.c -l %d" % self.line,
+            SOURCE_DISPLAYED_CORRECTLY,
+            substrs=["Hello world"],
+        )
 
-        with io.open(self.file, "w", newline="\n") as f:
-            time.sleep(1)
-            f.write(new_content)
-            if self.TraceOn():
-                print("new content:", new_content)
-                print(
-                    "os.path.getmtime() after writing new content:",
-                    os.path.getmtime(self.file),
-                )
+        # clear the source cache.
+        self.runCmd("source cache clear")
 
-        # Display the source code again.  We should see the updated line.
+        # Display the source code again. Now we should see the updated line.
         self.expect(
             "source list -f main-copy.c -l %d" % self.line,
             SOURCE_DISPLAYED_CORRECTLY,
@@ -338,3 +354,45 @@
 
         # Make sure the main source file is no longer in the source cache.
         self.expect("source cache dump", matching=False, substrs=[self.file])
+
+    def test_source_cache_interactions(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        # Create a first target.
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        lldbutil.run_break_set_by_symbol(
+            self, "main", num_expected_locations=1
+        )
+        self.expect("run", RUN_SUCCEEDED, substrs=["Hello world"])
+
+        # Create a second target.
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        lldbutil.run_break_set_by_symbol(
+            self, "main", num_expected_locations=1
+        )
+        self.expect("run", RUN_SUCCEEDED, substrs=["Hello world"])
+
+        # Modify the source file content.
+        self.modify_content()
+
+        # Clear the source cache. This will wipe the debugger and the process
+        # cache for the second process.
+        self.runCmd("source cache clear")
+
+        # Make sure we're seeing the new content from the clean process cache.
+        self.expect("next",
+            SOURCE_DISPLAYED_CORRECTLY,
+            substrs=["Hello lldb"],
+        )
+
+        # Switch back to the first target.
+        self.runCmd("target select 0")
+
+        # Make sure we're seeing the old content from the first target's
+        # process cache.
+        self.expect("next",
+            SOURCE_DISPLAYED_CORRECTLY,
+            substrs=["Hello world"],
+        )
+
Index: lldb/source/Utility/LLDBLog.cpp
===================================================================
--- lldb/source/Utility/LLDBLog.cpp
+++ lldb/source/Utility/LLDBLog.cpp
@@ -63,6 +63,7 @@
     {{"on-demand"},
      {"log symbol on-demand related activities"},
      LLDBLog::OnDemand},
+    {{"source"}, {"log source related activities"}, LLDBLog::Source},
 };
 
 static Log::Channel g_log_channel(g_categories,
Index: lldb/source/Core/SourceManager.cpp
===================================================================
--- lldb/source/Core/SourceManager.cpp
+++ lldb/source/Core/SourceManager.cpp
@@ -21,10 +21,13 @@
 #include "lldb/Symbol/LineEntry.h"
 #include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Target/PathMappingList.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/AnsiTerminal.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegularExpression.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/lldb-enumerations.h"
@@ -73,36 +76,89 @@
 
 SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
   if (!file_spec)
-    return nullptr;
+    return {};
 
-  DebuggerSP debugger_sp(m_debugger_wp.lock());
-  FileSP file_sp;
-  if (debugger_sp && debugger_sp->GetUseSourceCache())
-    file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
+  Log *log = GetLog(LLDBLog::Source);
 
+  DebuggerSP debugger_sp(m_debugger_wp.lock());
   TargetSP target_sp(m_target_wp.lock());
 
-  // It the target source path map has been updated, get this file again so we
-  // can successfully remap the source file
-  if (target_sp && file_sp &&
-      file_sp->GetSourceMapModificationID() !=
-          target_sp->GetSourcePathMap().GetModificationID())
-    file_sp.reset();
+  if (!debugger_sp && debugger_sp->GetUseSourceCache()) {
+    LLDB_LOG(log, "Source file caching disabled: creating new source file: {0}",
+             file_spec);
+    if (target_sp)
+      return std::make_shared<File>(file_spec, target_sp);
+    return std::make_shared<File>(file_spec, debugger_sp);
+  }
+
+  ProcessSP process_sp = target_sp ? target_sp->GetProcessSP() : ProcessSP();
+
+  // Check the process source cache first. This is the fast path which avoids
+  // touching the file system unless the path remapping has changed.
+  if (process_sp) {
+    if (FileSP file_sp =
+            process_sp->GetSourceFileCache().FindSourceFile(file_spec)) {
+      LLDB_LOG(log, "Found source file in the process cache: {0}", file_spec);
+      if (file_sp->PathRemappingIsStale()) {
+        LLDB_LOG(log, "Path remapping is stale: removing file from caches: {0}",
+                 file_spec);
+
+        // Remove the file from the debugger and process cache. Otherwise we'll
+        // hit the same issue again below when querying the debugger cache.
+        debugger_sp->GetSourceFileCache().RemoveSourceFile(file_sp);
+        process_sp->GetSourceFileCache().RemoveSourceFile(file_sp);
+
+        file_sp.reset();
+      } else {
+        return file_sp;
+      }
+    }
+  }
 
-  // Update the file contents if needed if we found a file
+  // Cache miss in the process cache. Check the debugger source cache.
+  FileSP file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
+
+  // We found the file in the debugger cache. Check if anything invalidated our
+  // cache result.
   if (file_sp)
-    file_sp->UpdateIfNeeded();
+    LLDB_LOG(log, "Found source file in the debugger cache: {0}", file_spec);
+
+  // Check if the path remapping has changed.
+  if (file_sp && file_sp->PathRemappingIsStale()) {
+    LLDB_LOG(log, "Path remapping is stale: {0}", file_spec);
+    file_sp.reset();
+  }
+
+  // Check if the modification time has changed.
+  if (file_sp && file_sp->ModificationTimeIsStale()) {
+    LLDB_LOG(log, "Modification time is stale: {0}", file_spec);
+    file_sp.reset();
+  }
+
+  // Check if the file exists on disk.
+  if (file_sp && !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
+    LLDB_LOG(log, "File doesn't exist on disk: {0}", file_spec);
+    file_sp.reset();
+  }
 
-  // If file_sp is no good or it points to a non-existent file, reset it.
-  if (!file_sp || !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
+  // If at this point we don't have a valid file, it means we either didn't find
+  // it in the debugger cache or something caused it to be invalidated.
+  if (!file_sp) {
+    LLDB_LOG(log, "Creating and caching new source file: {0}", file_spec);
+
+    // (Re)create the file.
     if (target_sp)
-      file_sp = std::make_shared<File>(file_spec, target_sp.get());
+      file_sp = std::make_shared<File>(file_spec, target_sp);
     else
       file_sp = std::make_shared<File>(file_spec, debugger_sp);
 
-    if (debugger_sp && debugger_sp->GetUseSourceCache())
-      debugger_sp->GetSourceFileCache().AddSourceFile(file_spec, file_sp);
+    // Add the file to the debugger and process cache. If the file was
+    // invalidated, this will overwrite it.
+    debugger_sp->GetSourceFileCache().AddSourceFile(file_spec, file_sp);
+    if (process_sp)
+      process_sp->GetSourceFileCache().AddSourceFile(file_spec, file_sp);
   }
+
   return file_sp;
 }
 
@@ -391,33 +447,36 @@
 SourceManager::File::File(const FileSpec &file_spec,
                           lldb::DebuggerSP debugger_sp)
     : m_file_spec_orig(file_spec), m_file_spec(), m_mod_time(),
-      m_debugger_wp(debugger_sp) {
-  CommonInitializer(file_spec, nullptr);
+      m_debugger_wp(debugger_sp), m_target_wp(TargetSP()) {
+  CommonInitializer(file_spec, {});
 }
 
-SourceManager::File::File(const FileSpec &file_spec, Target *target)
+SourceManager::File::File(const FileSpec &file_spec, TargetSP target_sp)
     : m_file_spec_orig(file_spec), m_file_spec(), m_mod_time(),
-      m_debugger_wp(target ? target->GetDebugger().shared_from_this()
-                           : DebuggerSP()) {
-  CommonInitializer(file_spec, target);
+      m_debugger_wp(target_sp ? target_sp->GetDebugger().shared_from_this()
+                              : DebuggerSP()),
+      m_target_wp(target_sp) {
+  CommonInitializer(file_spec, target_sp);
 }
 
 void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
-                                            Target *target) {
+                                            TargetSP target_sp) {
   // Set the file and update the modification time.
   SetFileSpec(file_spec);
 
+  // Always update the source map modification ID if we have a target.
+  if (target_sp)
+    m_source_map_mod_id = target_sp->GetSourcePathMap().GetModificationID();
+
   // File doesn't exist.
   if (m_mod_time == llvm::sys::TimePoint<>()) {
-    if (target) {
-      m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
-
+    if (target_sp) {
       // If this is just a file name, try finding it in the target.
       if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
         bool check_inlines = false;
         SymbolContextList sc_list;
         size_t num_matches =
-            target->GetImages().ResolveSymbolContextForFilePath(
+            target_sp->GetImages().ResolveSymbolContextForFilePath(
                 file_spec.GetFilename().AsCString(), 0, check_inlines,
                 SymbolContextItem(eSymbolContextModule |
                                   eSymbolContextCompUnit),
@@ -451,10 +510,10 @@
         // Check target specific source remappings (i.e., the
         // target.source-map setting), then fall back to the module
         // specific remapping (i.e., the .dSYM remapping dictionary).
-        auto remapped = target->GetSourcePathMap().FindFile(m_file_spec);
+        auto remapped = target_sp->GetSourcePathMap().FindFile(m_file_spec);
         if (!remapped) {
           FileSpec new_spec;
-          if (target->GetImages().FindSourceFile(m_file_spec, new_spec))
+          if (target_sp->GetImages().FindSourceFile(m_file_spec, new_spec))
             remapped = new_spec;
         }
         if (remapped)
@@ -540,18 +599,20 @@
   return false;
 }
 
-void SourceManager::File::UpdateIfNeeded() {
+bool SourceManager::File::ModificationTimeIsStale() const {
   // TODO: use host API to sign up for file modifications to anything in our
   // source cache and only update when we determine a file has been updated.
   // For now we check each time we want to display info for the file.
   auto curr_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
+  return curr_mod_time != llvm::sys::TimePoint<>() &&
+         m_mod_time != curr_mod_time;
+}
 
-  if (curr_mod_time != llvm::sys::TimePoint<>() &&
-      m_mod_time != curr_mod_time) {
-    m_mod_time = curr_mod_time;
-    m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec);
-    m_offsets.clear();
-  }
+bool SourceManager::File::PathRemappingIsStale() const {
+  if (TargetSP target_sp = m_target_wp.lock())
+    return GetSourceMapModificationID() !=
+           target_sp->GetSourcePathMap().GetModificationID();
+  return false;
 }
 
 size_t SourceManager::File::DisplaySourceLines(uint32_t line,
@@ -712,6 +773,8 @@
 
 void SourceManager::SourceFileCache::AddSourceFile(const FileSpec &file_spec,
                                                    FileSP file_sp) {
+  llvm::sys::ScopedWriter guard(m_mutex);
+
   assert(file_sp && "invalid FileSP");
 
   AddSourceFileImpl(file_spec, file_sp);
@@ -720,6 +783,22 @@
     AddSourceFileImpl(file_sp->GetFileSpec(), file_sp);
 }
 
+void SourceManager::SourceFileCache::RemoveSourceFile(const FileSP &file_sp) {
+  llvm::sys::ScopedWriter guard(m_mutex);
+
+  assert(file_sp && "invalid FileSP");
+
+  // Iterate over all the elements in the cache.
+  // This is expensive but a relatively uncommon operation.
+  auto it = m_file_cache.begin();
+  while (it != m_file_cache.end()) {
+    if (it->second == file_sp)
+      it = m_file_cache.erase(it);
+    else
+      it++;
+  }
+}
+
 void SourceManager::SourceFileCache::AddSourceFileImpl(
     const FileSpec &file_spec, FileSP file_sp) {
   FileCache::iterator pos = m_file_cache.find(file_spec);
@@ -733,11 +812,12 @@
 
 SourceManager::FileSP SourceManager::SourceFileCache::FindSourceFile(
     const FileSpec &file_spec) const {
-  FileSP file_sp;
+  llvm::sys::ScopedReader guard(m_mutex);
+
   FileCache::const_iterator pos = m_file_cache.find(file_spec);
   if (pos != m_file_cache.end())
-    file_sp = pos->second;
-  return file_sp;
+    return pos->second;
+  return {};
 }
 
 void SourceManager::SourceFileCache::Dump(Stream &stream) const {
Index: lldb/source/Commands/CommandObjectSource.cpp
===================================================================
--- lldb/source/Commands/CommandObjectSource.cpp
+++ lldb/source/Commands/CommandObjectSource.cpp
@@ -22,6 +22,7 @@
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Utility/FileSpec.h"
@@ -1213,8 +1214,19 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
+    // Dump the debugger source cache.
+    result.GetOutputStream() << "Debugger Source File Cache\n";
     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
     cache.Dump(result.GetOutputStream());
+
+    // Dump the process source cache.
+    ProcessSP process_sp = m_exe_ctx.GetProcessSP();
+    if (process_sp) {
+      result.GetOutputStream() << "\nProcess Source File Cache\n";
+      SourceManager::SourceFileCache &cache = process_sp->GetSourceFileCache();
+      cache.Dump(result.GetOutputStream());
+    }
+
     result.SetStatus(eReturnStatusSuccessFinishResult);
     return result.Succeeded();
   }
@@ -1230,8 +1242,15 @@
 
 protected:
   bool DoExecute(Args &command, CommandReturnObject &result) override {
+    // Clear the debugger cache.
     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
     cache.Clear();
+
+    // Clear the process cache.
+    ProcessSP process_sp = m_exe_ctx.GetProcessSP();
+    if (process_sp)
+      process_sp->GetSourceFileCache().Clear();
+
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     return result.Succeeded();
   }
Index: lldb/include/lldb/Utility/LLDBLog.h
===================================================================
--- lldb/include/lldb/Utility/LLDBLog.h
+++ lldb/include/lldb/Utility/LLDBLog.h
@@ -48,6 +48,7 @@
   Unwind = Log::ChannelFlag<29>,
   Watchpoints = Log::ChannelFlag<30>,
   OnDemand = Log::ChannelFlag<31>,
+  Source = Log::ChannelFlag<32>,
   LLVM_MARK_AS_BITMASK_ENUM(OnDemand),
 };
 
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -25,6 +25,7 @@
 #include "lldb/Breakpoint/BreakpointSiteList.h"
 #include "lldb/Core/LoadedModuleInfoList.h"
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/SourceManager.h"
 #include "lldb/Core/ThreadSafeValue.h"
 #include "lldb/Core/ThreadedCommunication.h"
 #include "lldb/Core/UserSettingsController.h"
@@ -2573,6 +2574,10 @@
 
   virtual void ForceScriptedState(lldb::StateType state) {}
 
+  SourceManager::SourceFileCache &GetSourceFileCache() {
+    return m_source_file_cache;
+  }
+
 protected:
   friend class Trace;
 
@@ -3043,6 +3048,9 @@
   std::unique_ptr<UtilityFunction> m_dlopen_utility_func_up;
   llvm::once_flag m_dlopen_utility_func_flag_once;
 
+  /// Per process source file cache.
+  SourceManager::SourceFileCache m_source_file_cache;
+
   size_t RemoveBreakpointOpcodesFromBuffer(lldb::addr_t addr, size_t size,
                                            uint8_t *buf) const;
 
Index: lldb/include/lldb/Core/SourceManager.h
===================================================================
--- lldb/include/lldb/Core/SourceManager.h
+++ lldb/include/lldb/Core/SourceManager.h
@@ -14,6 +14,7 @@
 #include "lldb/lldb-forward.h"
 
 #include "llvm/Support/Chrono.h"
+#include "llvm/Support/RWMutex.h"
 
 #include <cstddef>
 #include <cstdint>
@@ -36,11 +37,11 @@
                            const SourceManager::File &rhs);
 
   public:
-    File(const FileSpec &file_spec, Target *target);
+    File(const FileSpec &file_spec, lldb::TargetSP target_sp);
     File(const FileSpec &file_spec, lldb::DebuggerSP debugger_sp);
-    ~File() = default;
 
-    void UpdateIfNeeded();
+    bool ModificationTimeIsStale() const;
+    bool PathRemappingIsStale() const;
 
     size_t DisplaySourceLines(uint32_t line, std::optional<size_t> column,
                               uint32_t context_before, uint32_t context_after,
@@ -89,9 +90,10 @@
     typedef std::vector<uint32_t> LineOffsets;
     LineOffsets m_offsets;
     lldb::DebuggerWP m_debugger_wp;
+    lldb::TargetWP m_target_wp;
 
   private:
-    void CommonInitializer(const FileSpec &file_spec, Target *target);
+    void CommonInitializer(const FileSpec &file_spec, lldb::TargetSP target_sp);
   };
 
   typedef std::shared_ptr<File> FileSP;
@@ -105,6 +107,8 @@
     ~SourceFileCache() = default;
 
     void AddSourceFile(const FileSpec &file_spec, FileSP file_sp);
+    void RemoveSourceFile(const FileSP &file_sp);
+
     FileSP FindSourceFile(const FileSpec &file_spec) const;
 
     // Removes all elements from the cache.
@@ -117,6 +121,8 @@
 
     typedef std::map<FileSpec, FileSP> FileCache;
     FileCache m_file_cache;
+
+    mutable llvm::sys::RWMutex m_mutex;
   };
 
   // Constructors and Destructors
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to