https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/140299
This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. >From 59aadc0f2b61a39563269329d10c553f7965c70b Mon Sep 17 00:00:00 2001 From: John Harrison <harj...@google.com> Date: Fri, 16 May 2025 12:03:50 -0700 Subject: [PATCH] [lldb-dap] Adjusting startup flow to better handle async operations. This introduces an `AsyncRequestHandler` and partially reverse the changes from ba29e60f9a2222bd5e883579bb78db13fc5a7588 in that the `launch` and `attach` commands now run when we receive them. We wait to send the reply until we get the `configurationDone` request. --- lldb/tools/lldb-dap/DAP.cpp | 49 ++--- lldb/tools/lldb-dap/DAP.h | 22 ++- lldb/tools/lldb-dap/EventHelper.cpp | 2 +- .../lldb-dap/Handler/AttachRequestHandler.cpp | 69 +++---- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 61 +++---- .../tools/lldb-dap/Handler/RequestHandler.cpp | 31 ++++ lldb/tools/lldb-dap/Handler/RequestHandler.h | 168 +++++++++++------- 7 files changed, 241 insertions(+), 161 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 56a0c38b00037..416661e98c21f 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -120,11 +120,12 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false), + restarting_process_id(LLDB_INVALID_PROCESS_ID), waiting_for_run_in_terminal(false), progress_event_reporter( [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - reverse_request_seq(0), repl_mode(default_repl_mode) { + reverse_request_seq(0), repl_mode(default_repl_mode), + m_configuration_done(false) { configuration.preInitCommands = std::move(pre_init_commands); RegisterRequests(); } @@ -916,20 +917,10 @@ llvm::Error DAP::Loop() { return errWrapper; } - // The launch sequence is special and we need to carefully handle - // packets in the right order. Until we've handled configurationDone, - bool add_to_pending_queue = false; - if (const protocol::Request *req = - std::get_if<protocol::Request>(&*next)) { - llvm::StringRef command = req->command; - if (command == "disconnect") - disconnecting = true; - if (!configuration_done) - add_to_pending_queue = - command != "initialize" && command != "configurationDone" && - command != "disconnect" && !command.ends_with("Breakpoints"); - } + std::get_if<protocol::Request>(&*next); + req && req->command == "disconnect") + disconnecting = true; const std::optional<CancelArguments> cancel_args = getArgumentsIfRequest<CancelArguments>(*next, "cancel"); @@ -956,8 +947,7 @@ llvm::Error DAP::Loop() { { std::lock_guard<std::mutex> guard(m_queue_mutex); - auto &queue = add_to_pending_queue ? m_pending_queue : m_queue; - queue.push_back(std::move(*next)); + m_queue.push_back(std::move(*next)); } m_queue_cv.notify_one(); } @@ -1255,14 +1245,25 @@ void DAP::SetConfiguration(const protocol::Configuration &config, SetThreadFormat(*configuration.customThreadFormat); } +bool DAP::GetConfigurationDone() { + std::lock_guard<std::mutex> guard(m_configuration_done_mutex); + return m_configuration_done; +} + void DAP::SetConfigurationDone() { - { - std::lock_guard<std::mutex> guard(m_queue_mutex); - std::copy(m_pending_queue.begin(), m_pending_queue.end(), - std::front_inserter(m_queue)); - configuration_done = true; - } - m_queue_cv.notify_all(); + std::lock_guard<std::mutex> guard(m_configuration_done_mutex); + m_configuration_done = true; + for (auto &cb : m_configuration_done_callbacks) + cb(); + m_configuration_done_callbacks.clear(); +} + +void DAP::OnConfigurationDone(llvm::unique_function<void()> &&callback) { + std::lock_guard<std::mutex> guard(m_configuration_done_mutex); + if (m_configuration_done) + callback(); + else + m_configuration_done_callbacks.emplace_back(std::move(callback)); } void DAP::SetFrameFormat(llvm::StringRef format) { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index c1a1130b1e59f..4d170ba4ec920 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -187,7 +187,6 @@ struct DAP { // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. lldb::pid_t restarting_process_id; - bool configuration_done; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -257,14 +256,26 @@ struct DAP { /// Configures the debug adapter for launching/attaching. void SetConfiguration(const protocol::Configuration &confing, bool is_attach); + /// Returns true if the debug session has received the `configurationDone` + /// request. + bool GetConfigurationDone(); + + /// Marks that the debug session has received the `configurationDone` request. void SetConfigurationDone(); + /// Registers a callback that is fired after `configurationDone` is received. + /// + /// NOTE: If `configurationDone` has already been received, the callback will + /// be invoked immediately. + void OnConfigurationDone(llvm::unique_function<void()> &&callback); + /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); + /// Send the given message to the client void Send(const protocol::Message &message); @@ -336,7 +347,7 @@ struct DAP { lldb::SBTarget CreateTarget(lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. + /// listening for its breakpoint events. void SetTarget(const lldb::SBTarget target); bool HandleObject(const protocol::Message &M); @@ -377,7 +388,7 @@ struct DAP { }); } - /// The set of capablities supported by this adapter. + /// The set of capabilities supported by this adapter. protocol::Capabilities GetCapabilities(); /// Debuggee will continue from stopped state. @@ -444,13 +455,16 @@ struct DAP { /// Queue for all incoming messages. std::deque<protocol::Message> m_queue; - std::deque<protocol::Message> m_pending_queue; std::mutex m_queue_mutex; std::condition_variable m_queue_cv; std::mutex m_cancelled_requests_mutex; llvm::SmallSet<int64_t, 4> m_cancelled_requests; + std::mutex m_configuration_done_mutex; + bool m_configuration_done; + std::vector<llvm::unique_function<void()>> m_configuration_done_callbacks; + std::mutex m_active_request_mutex; const protocol::Request *m_active_request; }; diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index ed2d8700c26b0..e62f1d61a3d22 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) { // If the focus thread is not set then we haven't reported any thread status // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { + if (!dap.GetConfigurationDone() || dap.focus_tid == LLDB_INVALID_THREAD_ID) { return; } diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 0293ffbd0c922..c4f1ad084b4e7 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -28,21 +28,22 @@ namespace lldb_dap { /// /// Since attaching is debugger/runtime specific, the arguments for this request /// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { +void AttachRequestHandler::Run(const AttachRequestArguments &args, + Reply<AttachResponse> reply) const { // Validate that we have a well formed attach request. if (args.attachCommands.empty() && args.coreFile.empty() && args.configuration.program.empty() && args.pid == LLDB_INVALID_PROCESS_ID && args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error<DAPError>( + return reply(make_error<DAPError>( "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); + "'coreFile' or 'gdb-remote-port' to be specified")); // Check if we have mutually exclusive arguments. if ((args.pid != LLDB_INVALID_PROCESS_ID) && (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error<DAPError>( - "'pid' and 'gdb-remote-port' are mutually exclusive"); + return reply(make_error<DAPError>( + "'pid' and 'gdb-remote-port' are mutually exclusive")); dap.SetConfiguration(args.configuration, /*is_attach=*/true); if (!args.coreFile.empty()) @@ -59,20 +60,20 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Run any initialize LLDB commands the user specified in the launch.json if (llvm::Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if ((args.pid == LLDB_INVALID_PROCESS_ID || args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && @@ -94,14 +95,14 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // user that their command failed or the debugger is in an unexpected // state. if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; + return reply(std::move(err)); dap.target = dap.debugger.GetSelectedTarget(); // Validate the attachCommand results. if (!dap.target.GetProcess().IsValid()) - return make_error<DAPError>( - "attachCommands failed to attach to a process"); + return reply(make_error<DAPError>( + "attachCommands failed to attach to a process")); } else if (!args.coreFile.empty()) { dap.target.LoadCore(args.coreFile.data(), error); } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { @@ -129,35 +130,35 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { // Make sure the process is attached and stopped. error = dap.WaitForProcessToStop(args.configuration.timeout); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error<DAPError>("failed to attach to process"); + return reply(make_error<DAPError>("failed to attach to process")); dap.RunPostRunCommands(); - return Error::success(); -} + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + SendProcessEvent(dap, Attach); -void AttachRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - SendProcessEvent(dap, Attach); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index 22d1a090187d8..d963f62dee4f4 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -21,11 +21,12 @@ using namespace lldb_dap::protocol; namespace lldb_dap { /// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { +void LaunchRequestHandler::Run(const LaunchRequestArguments &arguments, + Reply<LaunchResponse> reply) const { // Validate that we have a well formed launch request. if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error<DAPError>( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); + return reply(make_error<DAPError>( + "'launchCommands' and 'runInTerminal' are mutually exclusive")); dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); dap.last_launch_request = arguments; @@ -43,49 +44,49 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { // This is run before target is created, so commands can't do anything with // the targets - preRunCommands are run with the target. if (Error err = dap.RunInitCommands()) - return err; + return reply(std::move(err)); dap.ConfigureSourceMaps(); lldb::SBError error; lldb::SBTarget target = dap.CreateTarget(error); if (error.Fail()) - return ToError(error); + return reply(ToError(error)); dap.SetTarget(target); // Run any pre run LLDB commands the user specified in the launch.json if (Error err = dap.RunPreRunCommands()) - return err; + return reply(std::move(err)); if (Error err = LaunchProcess(arguments)) - return err; + return reply(std::move(err)); dap.RunPostRunCommands(); - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - if (!dap.target.GetProcess().IsValid()) - return; - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = - GetThreads(dap.target.GetProcess(), dap.thread_format); - - // Attach happens when launching with runInTerminal. - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - dap.target.GetProcess().Continue(); + dap.OnConfigurationDone([&, reply = std::move(reply)]() { + reply(Error::success()); + + if (!dap.target.GetProcess().IsValid()) + return; + + // Clients can request a baseline of currently existing threads after + // we acknowledge the configurationDone request. + // Client requests the baseline of currently existing threads after + // a successful or attach by sending a 'threads' request + // right after receiving the configurationDone response. + // Obtain the list of threads before we resume the process + dap.initial_thread_list = + GetThreads(dap.target.GetProcess(), dap.thread_format); + + // Attach happens when launching with runInTerminal. + SendProcessEvent(dap, dap.is_attach ? Attach : Launch); + + if (dap.stop_at_entry) + SendThreadStoppedEvent(dap); + else + dap.target.GetProcess().Continue(); + }); } } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 93bc80a38e29d..063f613711f61 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -126,6 +126,37 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { error.GetCString()); } +void HandleErrorResponse(llvm::Error err, protocol::Response &response) { + response.success = false; + llvm::handleAllErrors( + std::move(err), + [&](const NotStoppedError &err) { + response.message = lldb_dap::protocol::eResponseMessageNotStopped; + }, + [&](const DAPError &err) { + protocol::ErrorMessage error_message; + error_message.sendTelemetry = false; + error_message.format = err.getMessage(); + error_message.showUser = err.getShowUser(); + error_message.id = err.convertToErrorCode().value(); + error_message.url = err.getURL(); + error_message.urlLabel = err.getURLLabel(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }, + [&](const llvm::ErrorInfoBase &err) { + protocol::ErrorMessage error_message; + error_message.showUser = true; + error_message.sendTelemetry = false; + error_message.format = err.message(); + error_message.id = err.convertToErrorCode().value(); + protocol::ErrorResponseBody body; + body.error = error_message; + response.body = body; + }); +} + void BaseRequestHandler::Run(const Request &request) { // If this request was cancelled, send a cancelled response. if (dap.IsCancelled(request)) { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 383f9e24a729a..f7902592b572b 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -32,6 +32,35 @@ inline constexpr bool is_optional_v = is_optional<T>::value; namespace lldb_dap { struct DAP; +void HandleErrorResponse(llvm::Error err, protocol::Response &response); +template <typename Args> +llvm::Expected<Args> parseArgs(const protocol::Request &request) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + + if (!is_optional_v<Args> && !request.arguments) { + return llvm::make_error<DAPError>( + llvm::formatv("arguments required for command '{0}' " + "but none received", + request.command) + .str()); + } + + Args arguments; + llvm::json::Path::Root root("arguments"); + if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { + std::string parse_failure; + llvm::raw_string_ostream OS(parse_failure); + OS << "invalid arguments for request '" << request.command + << "': " << llvm::toString(root.getError()) << "\n"; + root.printErrorContext(*request.arguments, OS); + return llvm::make_error<DAPError>(parse_failure); + } + + return arguments; +} + /// Base class for request handlers. Do not extend this directly: Extend /// the RequestHandler template subclass instead. class BaseRequestHandler { @@ -102,42 +131,21 @@ class RequestHandler : public BaseRequestHandler { response.request_seq = request.seq; response.command = request.command; - if (!is_optional_v<Args> && !request.arguments) { - DAP_LOG(dap.log, - "({0}) malformed request {1}, expected arguments but got none", - dap.transport.GetClientName(), request.command); - HandleErrorResponse( - llvm::make_error<DAPError>( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()), - response); - dap.Send(response); - return; - } - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - HandleErrorResponse(llvm::make_error<DAPError>(parse_failure), response); + llvm::Expected<Args> arguments = parseArgs<Args>(request); + if (llvm::Error err = arguments.takeError()) { + HandleErrorResponse(std::move(err), response); dap.Send(response); return; } if constexpr (std::is_same_v<Resp, llvm::Error>) { - if (llvm::Error err = Run(arguments)) { + if (llvm::Error err = Run(*arguments)) { HandleErrorResponse(std::move(err), response); } else { response.success = true; } } else { - Resp body = Run(arguments); + Resp body = Run(*arguments); if (llvm::Error err = body.takeError()) { HandleErrorResponse(std::move(err), response); } else { @@ -168,48 +176,73 @@ class RequestHandler : public BaseRequestHandler { /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an /// error. virtual void PostRun() const {}; +}; - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } +/// A Reply<T> is a void function that accepts a reply to an async request. +template <typename T> using Reply = llvm::unique_function<void(T) const>; + +/// Base class for handling DAP requests. Handlers should declare their +/// arguments and response body types like: +/// +/// class MyRequestHandler : public RequestHandler<Arguments, Response> { +/// .... +/// }; +template <typename Args, typename Resp> +class AsyncRequestHandler : public BaseRequestHandler { + using BaseRequestHandler::BaseRequestHandler; + + void operator()(const protocol::Request &request) const override { + llvm::Expected<Args> arguments = parseArgs<Args>(request); + if (llvm::Error err = arguments.takeError()) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + HandleErrorResponse(std::move(err), response); + dap.Send(response); + return; + } + + Run(*arguments, [&, request = std::move(request)](Resp body) { + protocol::Response response; + response.request_seq = request.seq; + response.command = request.command; + if constexpr (std::is_same_v<Resp, llvm::Error>) { + if (body) { + HandleErrorResponse(std::move(body), response); + } else { + response.success = true; + } + } else { + if (llvm::Error err = body.takeError()) { + HandleErrorResponse(std::move(err), response); + } else { + response.success = true; + response.body = std::move(*body); + } + } + + // Mark the request as 'cancelled' if the debugger was interrupted while + // evaluating this handler. + if (dap.debugger.InterruptRequested()) { + response.success = false; + response.message = protocol::eResponseMessageCancelled; + response.body = std::nullopt; + } + dap.Send(response); + }); + }; + + virtual void Run(const Args &, Reply<Resp>) const = 0; }; class AttachRequestHandler - : public RequestHandler<protocol::AttachRequestArguments, - protocol::AttachResponse> { + : public AsyncRequestHandler<protocol::AttachRequestArguments, + protocol::AttachResponse> { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; + void Run(const protocol::AttachRequestArguments &args, + Reply<protocol::AttachResponse> reply) const override; }; class BreakpointLocationsRequestHandler @@ -301,14 +334,13 @@ class InitializeRequestHandler }; class LaunchRequestHandler - : public RequestHandler<protocol::LaunchRequestArguments, - protocol::LaunchResponse> { + : public AsyncRequestHandler<protocol::LaunchRequestArguments, + protocol::LaunchResponse> { public: - using RequestHandler::RequestHandler; + using AsyncRequestHandler::AsyncRequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; + void Run(const protocol::LaunchRequestArguments &arguments, + Reply<protocol::LaunchResponse>) const override; }; class RestartRequestHandler : public LegacyRequestHandler { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits