CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
158 lines
5.5 KiB
C++
158 lines
5.5 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "DAPSessionManager.h"
|
|
#include "DAP.h"
|
|
#include "EventHelper.h"
|
|
#include "lldb/API/SBBroadcaster.h"
|
|
#include "lldb/API/SBEvent.h"
|
|
#include "lldb/API/SBListener.h"
|
|
#include "lldb/API/SBTarget.h"
|
|
#include "lldb/Host/MainLoopBase.h"
|
|
#include "llvm/Support/Threading.h"
|
|
#include "llvm/Support/WithColor.h"
|
|
|
|
#include <chrono>
|
|
#include <mutex>
|
|
|
|
namespace lldb_dap {
|
|
|
|
ManagedEventThread::ManagedEventThread(lldb::SBBroadcaster broadcaster,
|
|
std::thread t)
|
|
: m_broadcaster(broadcaster), m_event_thread(std::move(t)) {}
|
|
|
|
ManagedEventThread::~ManagedEventThread() {
|
|
if (m_event_thread.joinable()) {
|
|
m_broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
|
|
m_event_thread.join();
|
|
}
|
|
}
|
|
|
|
DAPSessionManager &DAPSessionManager::GetInstance() {
|
|
static std::once_flag initialized;
|
|
static DAPSessionManager *instance =
|
|
nullptr; // NOTE: intentional leak to avoid issues with C++ destructor
|
|
// chain
|
|
|
|
std::call_once(initialized, []() { instance = new DAPSessionManager(); });
|
|
|
|
return *instance;
|
|
}
|
|
|
|
void DAPSessionManager::RegisterSession(lldb_private::MainLoop *loop,
|
|
DAP *dap) {
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
m_active_sessions[loop] = dap;
|
|
}
|
|
|
|
void DAPSessionManager::UnregisterSession(lldb_private::MainLoop *loop) {
|
|
std::unique_lock<std::mutex> lock(m_sessions_mutex);
|
|
m_active_sessions.erase(loop);
|
|
std::notify_all_at_thread_exit(m_sessions_condition, std::move(lock));
|
|
}
|
|
|
|
std::vector<DAP *> DAPSessionManager::GetActiveSessions() {
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
std::vector<DAP *> sessions;
|
|
for (const auto &[loop, dap] : m_active_sessions)
|
|
if (dap)
|
|
sessions.emplace_back(dap);
|
|
return sessions;
|
|
}
|
|
|
|
void DAPSessionManager::DisconnectAllSessions() {
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
m_client_failed = false;
|
|
for (auto [loop, dap] : m_active_sessions) {
|
|
if (dap) {
|
|
if (llvm::Error error = dap->Disconnect()) {
|
|
m_client_failed = true;
|
|
llvm::WithColor::error() << "DAP client disconnected failed: "
|
|
<< llvm::toString(std::move(error)) << "\n";
|
|
}
|
|
loop->AddPendingCallback(
|
|
[](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
|
|
}
|
|
}
|
|
}
|
|
|
|
llvm::Error DAPSessionManager::WaitForAllSessionsToDisconnect() {
|
|
std::unique_lock<std::mutex> lock(m_sessions_mutex);
|
|
m_sessions_condition.wait(lock, [this] { return m_active_sessions.empty(); });
|
|
|
|
// Check if any disconnection failed and return appropriate error.
|
|
if (m_client_failed)
|
|
return llvm::createStringError("disconnecting all clients failed");
|
|
|
|
return llvm::Error::success();
|
|
}
|
|
|
|
std::shared_ptr<ManagedEventThread>
|
|
DAPSessionManager::GetEventThreadForDebugger(lldb::SBDebugger debugger,
|
|
DAP *requesting_dap) {
|
|
lldb::user_id_t debugger_id = debugger.GetID();
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
|
|
// Try to use shared event thread, if it exists.
|
|
if (auto it = m_debugger_event_threads.find(debugger_id);
|
|
it != m_debugger_event_threads.end()) {
|
|
if (std::shared_ptr<ManagedEventThread> thread_sp = it->second.lock())
|
|
return thread_sp;
|
|
// Our weak pointer has expired.
|
|
m_debugger_event_threads.erase(it);
|
|
}
|
|
|
|
// Add the listener for the 'StopEventThread' event before starting the
|
|
// event thread to prevent a race condition. Under heavy load, a stop event
|
|
// could be sent immediately after the thread starts. If the listener isn't
|
|
// registered first, the event is missed, leading to a deadlock.
|
|
lldb::SBListener listener = debugger.GetListener();
|
|
requesting_dap->broadcaster.AddListener(listener,
|
|
eBroadcastBitStopEventThread);
|
|
debugger.GetBroadcaster().AddListener(
|
|
listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning);
|
|
// listen for thread events.
|
|
listener.StartListeningForEventClass(
|
|
debugger, lldb::SBThread::GetBroadcasterClassName(),
|
|
lldb::SBThread::eBroadcastBitStackChanged);
|
|
|
|
// Create a new event thread and store it.
|
|
auto new_thread_sp = std::make_shared<ManagedEventThread>(
|
|
requesting_dap->broadcaster,
|
|
std::thread(EventThread, debugger, requesting_dap->broadcaster,
|
|
requesting_dap->m_client_name,
|
|
std::ref(requesting_dap->log)));
|
|
m_debugger_event_threads[debugger_id] = new_thread_sp;
|
|
return new_thread_sp;
|
|
}
|
|
|
|
DAP *DAPSessionManager::FindDAPForTarget(lldb::SBTarget target) {
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
|
|
for (const auto &[loop, dap] : m_active_sessions)
|
|
if (dap && dap->target.IsValid() && dap->target == target)
|
|
return dap;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void DAPSessionManager::ReleaseExpiredEventThreads() {
|
|
std::lock_guard<std::mutex> lock(m_sessions_mutex);
|
|
for (auto it = m_debugger_event_threads.begin();
|
|
it != m_debugger_event_threads.end();) {
|
|
// Check if the weak_ptr has expired (no DAP instances are using it
|
|
// anymore).
|
|
if (it->second.expired()) {
|
|
it = m_debugger_event_threads.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace lldb_dap
|