Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
/// Shared thread pool. Use only with ThreadPoolTaskGroup.
static llvm::ThreadPoolInterface &GetThreadPool();

/// Dedicated symbol thread pool to prevent deadlock with module loading.
/// Use this for symbol indexing operations that might need to access
/// the shared module list while holding module mutexes.
static llvm::ThreadPoolInterface &GetSymbolThreadPool();

/// Report warning events.
///
/// Warning events will be delivered to any debuggers that have listeners
Expand Down
16 changes: 16 additions & 0 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ static std::recursive_mutex *g_debugger_list_mutex_ptr =
static Debugger::DebuggerList *g_debugger_list_ptr =
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
static llvm::DefaultThreadPool *g_thread_pool = nullptr;
static llvm::DefaultThreadPool *g_symbol_thread_pool = nullptr;

static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
{
Expand Down Expand Up @@ -715,6 +716,8 @@ void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {
g_debugger_list_mutex_ptr = new std::recursive_mutex();
g_debugger_list_ptr = new DebuggerList();
g_thread_pool = new llvm::DefaultThreadPool(llvm::optimal_concurrency());
g_symbol_thread_pool =
new llvm::DefaultThreadPool(llvm::optimal_concurrency());
g_load_plugin_callback = load_plugin_callback;
}

Expand All @@ -731,6 +734,13 @@ void Debugger::Terminate() {
if (g_thread_pool) {
// The destructor will wait for all the threads to complete.
delete g_thread_pool;
g_thread_pool = nullptr;
}

if (g_symbol_thread_pool) {
// The destructor will wait for all the threads to complete.
delete g_symbol_thread_pool;
g_symbol_thread_pool = nullptr;
}

if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
Expand Down Expand Up @@ -2383,3 +2393,9 @@ llvm::ThreadPoolInterface &Debugger::GetThreadPool() {
"Debugger::GetThreadPool called before Debugger::Initialize");
return *g_thread_pool;
}

llvm::ThreadPoolInterface &Debugger::GetSymbolThreadPool() {
assert(g_symbol_thread_pool &&
"Debugger::GetSymbolThreadPool called before Debugger::Initialize");
return *g_symbol_thread_pool;
}
6 changes: 4 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,12 @@ void ManualDWARFIndex::Index() {
total_progress, /*debugger=*/nullptr,
Progress::kDefaultHighFrequencyReportTime);

// Use separate symbol thread pool to avoid deadlock with module loading
// Share one thread pool across operations to avoid the overhead of
// recreating the threads.
llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();
llvm::ThreadPoolTaskGroup task_group(Debugger::GetSymbolThreadPool());
const size_t num_threads =
Debugger::GetSymbolThreadPool().getMaxConcurrency();

// Run a function for each compile unit in parallel using as many threads as
// are available. This is significantly faster than submiting a new task for
Expand Down
Loading