================
@@ -9,26 +9,34 @@
 #include "lldb/Core/Progress.h"
 
 #include "lldb/Core/Debugger.h"
-#include "lldb/Utility/StreamString.h"
 
 #include <optional>
 
 using namespace lldb;
 using namespace lldb_private;
 
 std::atomic<uint64_t> Progress::g_id(0);
+std::atomic<uint64_t> Progress::g_refcount(1);
+std::unordered_map<std::string, uint64_t> Progress::g_map = {};
----------------
clayborg wrote:

When something isn't just an integer, like the map here, we can run into issues 
with this in a multi-threaded environment. Why? These variables are part of the 
global C++ constructor / destructor chain. If any thread uses these after the 
main thread shuts down it can cause a crash. So for global objects we typically 
will create a pointer to one and leak it with a note. See 
`lldb/source/Core/Debugger.cpp` and look for `g_debugger_list_mutex_ptr` and 
other variables right next to them and then see `Debugger::Initialize()`. 

This map also need to be threadsafe, so it needs a mutex. Might be a good idea 
to create a class to contain these and use an accessor to provide access to it. 
The solution below will make something that is thread safe _and_ also something 
that will survive the global destructor chain being called and letting other 
threads still be able to use Progress objects without crashing the process:
```
namespace {
class ProgressCategoryMap {
  std::mutex m_mutex;
  std::unordered_map<std::string, uint64_t> m_map;

  void Increment(std::string title) {
    std::lock_guard<std::mutex> lock(m_mutex);
    auto pair = g_map.emplace(title, 1); // No need to use g_refcount as it is 
just a constant 1
    // pair.first will be true if insertion happened.
    if (pair.first == false)
      ++pair.second; // Key already in map, increment the ref count.
  }
  void Decrement(std::string title) {
    std::lock_guard<std::mutex> lock(m_mutex);
    auto pos = g_map.find(title);
    if (pos == g_map.end())
      return;
    if (--pos->second == 0)
      g_map.erase(pos->second); // Decremented to zero
  }
};
// Now make a global accessor to get a threadsafe copy of ProgressCategoryMap
ProgressCategoryMap *GetProgressCategoryMap() {
  static std::once_flag g_once;
  static ProgressCategoryMap *g_category_map_ptr = nullptr;
  std::call_once(g_once, []{
    // NOTE: intentional leak to avoid issues with C++ destructor chain
    g_category_map_ptr = new ProgressCategoryMap();
  });
  return g_category_map_ptr;
}
} // anonymous namespace
```

https://github.com/llvm/llvm-project/pull/81026
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to