143 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#include "DAPSessionManager.h"9#include "DAP.h"10#include "EventHelper.h"11#include "lldb/API/SBBroadcaster.h"12#include "lldb/API/SBEvent.h"13#include "lldb/API/SBTarget.h"14#include "lldb/Host/MainLoopBase.h"15#include "llvm/Support/Threading.h"16#include "llvm/Support/WithColor.h"17 18#include <chrono>19#include <mutex>20 21namespace lldb_dap {22 23ManagedEventThread::ManagedEventThread(lldb::SBBroadcaster broadcaster,24 std::thread t)25 : m_broadcaster(broadcaster), m_event_thread(std::move(t)) {}26 27ManagedEventThread::~ManagedEventThread() {28 if (m_event_thread.joinable()) {29 m_broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);30 m_event_thread.join();31 }32}33 34DAPSessionManager &DAPSessionManager::GetInstance() {35 static std::once_flag initialized;36 static DAPSessionManager *instance =37 nullptr; // NOTE: intentional leak to avoid issues with C++ destructor38 // chain39 40 std::call_once(initialized, []() { instance = new DAPSessionManager(); });41 42 return *instance;43}44 45void DAPSessionManager::RegisterSession(lldb_private::MainLoop *loop,46 DAP *dap) {47 std::lock_guard<std::mutex> lock(m_sessions_mutex);48 m_active_sessions[loop] = dap;49}50 51void DAPSessionManager::UnregisterSession(lldb_private::MainLoop *loop) {52 std::unique_lock<std::mutex> lock(m_sessions_mutex);53 m_active_sessions.erase(loop);54 std::notify_all_at_thread_exit(m_sessions_condition, std::move(lock));55}56 57std::vector<DAP *> DAPSessionManager::GetActiveSessions() {58 std::lock_guard<std::mutex> lock(m_sessions_mutex);59 std::vector<DAP *> sessions;60 for (const auto &[loop, dap] : m_active_sessions)61 if (dap)62 sessions.emplace_back(dap);63 return sessions;64}65 66void DAPSessionManager::DisconnectAllSessions() {67 std::lock_guard<std::mutex> lock(m_sessions_mutex);68 m_client_failed = false;69 for (auto [loop, dap] : m_active_sessions) {70 if (dap) {71 if (llvm::Error error = dap->Disconnect()) {72 m_client_failed = true;73 llvm::WithColor::error() << "DAP client disconnected failed: "74 << llvm::toString(std::move(error)) << "\n";75 }76 loop->AddPendingCallback(77 [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });78 }79 }80}81 82llvm::Error DAPSessionManager::WaitForAllSessionsToDisconnect() {83 std::unique_lock<std::mutex> lock(m_sessions_mutex);84 m_sessions_condition.wait(lock, [this] { return m_active_sessions.empty(); });85 86 // Check if any disconnection failed and return appropriate error.87 if (m_client_failed)88 return llvm::make_error<llvm::StringError>(89 "disconnecting all clients failed", llvm::inconvertibleErrorCode());90 91 return llvm::Error::success();92}93 94std::shared_ptr<ManagedEventThread>95DAPSessionManager::GetEventThreadForDebugger(lldb::SBDebugger debugger,96 DAP *requesting_dap) {97 lldb::user_id_t debugger_id = debugger.GetID();98 std::lock_guard<std::mutex> lock(m_sessions_mutex);99 100 // Try to use shared event thread, if it exists.101 if (auto it = m_debugger_event_threads.find(debugger_id);102 it != m_debugger_event_threads.end()) {103 if (std::shared_ptr<ManagedEventThread> thread_sp = it->second.lock())104 return thread_sp;105 // Our weak pointer has expired.106 m_debugger_event_threads.erase(it);107 }108 109 // Create a new event thread and store it.110 auto new_thread_sp = std::make_shared<ManagedEventThread>(111 requesting_dap->broadcaster,112 std::thread(EventThread, debugger, requesting_dap->broadcaster,113 requesting_dap->m_client_name, requesting_dap->log));114 m_debugger_event_threads[debugger_id] = new_thread_sp;115 return new_thread_sp;116}117 118DAP *DAPSessionManager::FindDAPForTarget(lldb::SBTarget target) {119 std::lock_guard<std::mutex> lock(m_sessions_mutex);120 121 for (const auto &[loop, dap] : m_active_sessions)122 if (dap && dap->target.IsValid() && dap->target == target)123 return dap;124 125 return nullptr;126}127 128void DAPSessionManager::ReleaseExpiredEventThreads() {129 std::lock_guard<std::mutex> lock(m_sessions_mutex);130 for (auto it = m_debugger_event_threads.begin();131 it != m_debugger_event_threads.end();) {132 // Check if the weak_ptr has expired (no DAP instances are using it133 // anymore).134 if (it->second.expired()) {135 it = m_debugger_event_threads.erase(it);136 } else {137 ++it;138 }139 }140}141 142} // namespace lldb_dap143