llvm-project/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
John Harrison 69878f9fa1
[lldb] Refactor JSONTransport own MainLoop read handle. (#179564)
When working with a MainLoop, if the file reaches the EOF it will
immediately fire the read handle callback. We cannot readily determine
if the file is at EOF or if the file is pointing to a socket/pipe that
has consumed all the current data in the buffer but the remote end has
not yet hung up. This is causing JSONTransport to continuously fire the
OnRead callback trigging repeated calls to the
`MessageHandler::OnClose`.

Since MainLoop does not perform the actual read, we need to adjust the
behavior of JSONTransport to fully own the read handle.

This change moves the ownership of the `MainLoop::ReadHandleUP` and
additionally own a reference to the `MainLoop` itself to ensure the loop
outlives the JSONTransport object.

This allows us to remove the handle immediately when we detect an EOF /
hang up has occurred.
2026-02-06 10:07:09 -08:00

76 lines
2.1 KiB
C++

//===- ProtocolServerMCP.h ------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
#define LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
#include "lldb/Core/ProtocolServer.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/Socket.h"
#include "lldb/Protocol/MCP/Server.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <cstddef>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>
namespace lldb_private::mcp {
class ProtocolServerMCP : public ProtocolServer {
using ServerUP = std::unique_ptr<lldb_protocol::mcp::Server>;
using ReadHandleUP = MainLoop::ReadHandleUP;
public:
ProtocolServerMCP();
~ProtocolServerMCP() override;
llvm::Error Start(ProtocolServer::Connection connection) override;
llvm::Error Stop() override;
static void Initialize();
static void Terminate();
static llvm::StringRef GetPluginNameStatic() { return "MCP"; }
static llvm::StringRef GetPluginDescriptionStatic();
static lldb::ProtocolServerUP CreateInstance();
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
Socket *GetSocket() const override { return m_listener.get(); }
protected:
// This adds tools and resource providers that
// are specific to this server. Overridable by the unit tests.
virtual void Extend(lldb_protocol::mcp::Server &server) const;
private:
void AcceptCallback(std::unique_ptr<Socket> socket);
bool m_running = false;
lldb_private::MainLoop m_loop;
std::thread m_loop_thread;
std::mutex m_mutex;
size_t m_client_count = 0;
std::unique_ptr<Socket> m_listener;
std::vector<ReadHandleUP> m_accept_handles;
ServerUP m_server;
lldb_protocol::mcp::ServerInfoHandle m_server_info_handle;
};
} // namespace lldb_private::mcp
#endif