https://github.com/ashgti updated 
https://github.com/llvm/llvm-project/pull/140299

>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

Reply via email to