1414#include " LLDBUtils.h"
1515#include " OutputRedirector.h"
1616#include " Protocol/ProtocolBase.h"
17+ #include " Protocol/ProtocolRequests.h"
1718#include " Protocol/ProtocolTypes.h"
1819#include " Transport.h"
1920#include " lldb/API/SBBreakpoint.h"
4041#include < algorithm>
4142#include < cassert>
4243#include < chrono>
44+ #include < condition_variable>
4345#include < cstdarg>
4446#include < cstdio>
4547#include < fstream>
48+ #include < future>
4649#include < memory>
4750#include < mutex>
51+ #include < optional>
4852#include < string>
4953#include < utility>
54+ #include < variant>
5055
5156#if defined(_WIN32)
5257#define NOMINMAX
5863#endif
5964
6065using namespace lldb_dap ;
66+ using namespace lldb_dap ::protocol;
6167
6268namespace {
6369#ifdef _WIN32
@@ -230,7 +236,7 @@ void DAP::StopEventHandlers() {
230236void DAP::SendJSON (const llvm::json::Value &json) {
231237 // FIXME: Instead of parsing the output message from JSON, pass the `Message`
232238 // as parameter to `SendJSON`.
233- protocol:: Message message;
239+ Message message;
234240 llvm::json::Path::Root root;
235241 if (!fromJSON (json, message, root)) {
236242 DAP_LOG_ERROR (log, root.getError (), " ({1}) encoding failed: {0}" ,
@@ -240,7 +246,27 @@ void DAP::SendJSON(const llvm::json::Value &json) {
240246 Send (message);
241247}
242248
243- void DAP::Send (const protocol::Message &message) {
249+ void DAP::Send (const Message &message) {
250+ // FIXME: After all the requests have migrated from LegacyRequestHandler >
251+ // RequestHandler<> this should be handled in RequestHandler<>::operator().
252+ if (auto *resp = std::get_if<Response>(&message);
253+ resp && debugger.InterruptRequested ()) {
254+ // Clear the interrupt request.
255+ debugger.CancelInterruptRequest ();
256+
257+ // If the debugger was interrupted, convert this response into a 'cancelled'
258+ // response because we might have a partial result.
259+ Response cancelled{/* request_seq=*/ resp->request_seq ,
260+ /* command=*/ resp->command ,
261+ /* success=*/ false ,
262+ /* message=*/ eResponseMessageCancelled,
263+ /* body=*/ std::nullopt };
264+ if (llvm::Error err = transport.Write (cancelled))
265+ DAP_LOG_ERROR (log, std::move (err), " ({1}) write failed: {0}" ,
266+ transport.GetClientName ());
267+ return ;
268+ }
269+
244270 if (llvm::Error err = transport.Write (message))
245271 DAP_LOG_ERROR (log, std::move (err), " ({1}) write failed: {0}" ,
246272 transport.GetClientName ());
@@ -675,11 +701,25 @@ void DAP::SetTarget(const lldb::SBTarget target) {
675701 }
676702}
677703
678- bool DAP::HandleObject (const protocol::Message &M) {
679- if (const auto *req = std::get_if<protocol::Request>(&M)) {
704+ bool DAP::HandleObject (const Message &M) {
705+ if (const auto *req = std::get_if<Request>(&M)) {
706+ {
707+ std::lock_guard<std::mutex> guard (m_active_request_mutex);
708+ m_active_request = req;
709+
710+ // Clear the interrupt request prior to invoking a handler.
711+ if (debugger.InterruptRequested ())
712+ debugger.CancelInterruptRequest ();
713+ }
714+
715+ auto cleanup = llvm::make_scope_exit ([&]() {
716+ std::scoped_lock<std::mutex> active_request_lock (m_active_request_mutex);
717+ m_active_request = nullptr ;
718+ });
719+
680720 auto handler_pos = request_handlers.find (req->command );
681721 if (handler_pos != request_handlers.end ()) {
682- (* handler_pos->second ) (*req);
722+ handler_pos->second -> Run (*req);
683723 return true ; // Success
684724 }
685725
@@ -688,10 +728,10 @@ bool DAP::HandleObject(const protocol::Message &M) {
688728 return false ; // Fail
689729 }
690730
691- if (const auto *resp = std::get_if<protocol:: Response>(&M)) {
731+ if (const auto *resp = std::get_if<Response>(&M)) {
692732 std::unique_ptr<ResponseHandler> response_handler;
693733 {
694- std::lock_guard<std::mutex> locker (call_mutex);
734+ std::lock_guard<std::mutex> guard (call_mutex);
695735 auto inflight = inflight_reverse_requests.find (resp->request_seq );
696736 if (inflight != inflight_reverse_requests.end ()) {
697737 response_handler = std::move (inflight->second );
@@ -782,28 +822,121 @@ llvm::Error DAP::Disconnect(bool terminateDebuggee) {
782822 return ToError (error);
783823}
784824
825+ bool DAP::IsCancelled (const protocol::Request &req) {
826+ std::lock_guard<std::mutex> guard (m_cancelled_requests_mutex);
827+ return m_cancelled_requests.contains (req.seq );
828+ }
829+
830+ void DAP::ClearCancelRequest (const CancelArguments &args) {
831+ std::lock_guard<std::mutex> guard (m_cancelled_requests_mutex);
832+ if (args.requestId )
833+ m_cancelled_requests.erase (*args.requestId );
834+ }
835+
836+ template <typename T>
837+ static std::optional<T> getArgumentsIfRequest (const Message &pm,
838+ llvm::StringLiteral command) {
839+ auto *const req = std::get_if<Request>(&pm);
840+ if (!req || req->command != command)
841+ return std::nullopt ;
842+
843+ T args;
844+ llvm::json::Path::Root root;
845+ if (!fromJSON (req->arguments , args, root)) {
846+ return std::nullopt ;
847+ }
848+
849+ return std::move (args);
850+ }
851+
785852llvm::Error DAP::Loop () {
786- auto cleanup = llvm::make_scope_exit ([this ]() {
853+ std::future<llvm::Error> queue_reader =
854+ std::async (std::launch::async, [&]() -> llvm::Error {
855+ llvm::set_thread_name (transport.GetClientName () + " .transport_handler" );
856+ auto cleanup = llvm::make_scope_exit ([&]() {
857+ // Ensure we're marked as disconnecting when the reader exits.
858+ disconnecting = true ;
859+ m_queue_cv.notify_all ();
860+ });
861+
862+ while (!disconnecting) {
863+ llvm::Expected<Message> next =
864+ transport.Read (std::chrono::seconds (1 ));
865+ if (next.errorIsA <EndOfFileError>()) {
866+ consumeError (next.takeError ());
867+ break ;
868+ }
869+
870+ // If the read timed out, continue to check if we should disconnect.
871+ if (next.errorIsA <TimeoutError>()) {
872+ consumeError (next.takeError ());
873+ continue ;
874+ }
875+
876+ if (llvm::Error err = next.takeError ())
877+ return err;
878+
879+ if (const protocol::Request *req =
880+ std::get_if<protocol::Request>(&*next);
881+ req && req->command == " disconnect" ) {
882+ disconnecting = true ;
883+ }
884+
885+ const std::optional<CancelArguments> cancel_args =
886+ getArgumentsIfRequest<CancelArguments>(*next, " cancel" );
887+ if (cancel_args) {
888+ {
889+ std::lock_guard<std::mutex> guard (m_cancelled_requests_mutex);
890+ if (cancel_args->requestId )
891+ m_cancelled_requests.insert (*cancel_args->requestId );
892+ }
893+
894+ // If a cancel is requested for the active request, make a best
895+ // effort attempt to interrupt.
896+ std::lock_guard<std::mutex> guard (m_active_request_mutex);
897+ if (m_active_request &&
898+ cancel_args->requestId == m_active_request->seq ) {
899+ DAP_LOG (
900+ log,
901+ " ({0}) interrupting inflight request (command={1} seq={2})" ,
902+ transport.GetClientName (), m_active_request->command ,
903+ m_active_request->seq );
904+ debugger.RequestInterrupt ();
905+ }
906+ }
907+
908+ {
909+ std::lock_guard<std::mutex> guard (m_queue_mutex);
910+ m_queue.push_back (std::move (*next));
911+ }
912+ m_queue_cv.notify_one ();
913+ }
914+
915+ return llvm::Error::success ();
916+ });
917+
918+ auto cleanup = llvm::make_scope_exit ([&]() {
787919 out.Stop ();
788920 err.Stop ();
789921 StopEventHandlers ();
790922 });
923+
791924 while (!disconnecting) {
792- llvm::Expected<std::optional<protocol::Message>> next = transport.Read ();
793- if (!next)
794- return next.takeError ();
925+ std::unique_lock<std::mutex> lock (m_queue_mutex);
926+ m_queue_cv.wait (lock, [&] { return disconnecting || !m_queue.empty (); });
795927
796- // nullopt on EOF
797- if (!*next)
928+ if (m_queue.empty ())
798929 break ;
799930
800- if (!HandleObject (**next)) {
931+ Message next = m_queue.front ();
932+ m_queue.pop_front ();
933+
934+ if (!HandleObject (next))
801935 return llvm::createStringError (llvm::inconvertibleErrorCode (),
802936 " unhandled packet" );
803- }
804937 }
805938
806- return llvm::Error::success ();
939+ return queue_reader. get ();
807940}
808941
809942lldb::SBError DAP::WaitForProcessToStop (uint32_t seconds) {
@@ -1128,8 +1261,8 @@ lldb::SBValue Variables::FindVariable(uint64_t variablesReference,
11281261 }
11291262 }
11301263 } else {
1131- // This is not under the globals or locals scope, so there are no duplicated
1132- // names.
1264+ // This is not under the globals or locals scope, so there are no
1265+ // duplicated names.
11331266
11341267 // We have a named item within an actual variable so we need to find it
11351268 // withing the container variable by name.
0 commit comments