xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
10b57cec5SDimitry Andric //===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "GDBRemoteClientBase.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "lldb/Target/UnixSignals.h"
140b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "ProcessGDBRemoteLog.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace lldb;
190b57cec5SDimitry Andric using namespace lldb_private;
200b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote;
210b57cec5SDimitry Andric using namespace std::chrono;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric static const seconds kInterruptTimeout(5);
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric /////////////////////////
260b57cec5SDimitry Andric // GDBRemoteClientBase //
270b57cec5SDimitry Andric /////////////////////////
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name,
320b57cec5SDimitry Andric                                          const char *listener_name)
330b57cec5SDimitry Andric     : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0),
340b57cec5SDimitry Andric       m_is_running(false), m_should_stop(false) {}
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
370b57cec5SDimitry Andric     ContinueDelegate &delegate, const UnixSignals &signals,
380b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response) {
390b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
400b57cec5SDimitry Andric   response.Clear();
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   {
430b57cec5SDimitry Andric     std::lock_guard<std::mutex> lock(m_mutex);
440b57cec5SDimitry Andric     m_continue_packet = payload;
450b57cec5SDimitry Andric     m_should_stop = false;
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric   ContinueLock cont_lock(*this);
480b57cec5SDimitry Andric   if (!cont_lock)
490b57cec5SDimitry Andric     return eStateInvalid;
500b57cec5SDimitry Andric   OnRunPacketSent(true);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   for (;;) {
530b57cec5SDimitry Andric     PacketResult read_result = ReadPacket(response, kInterruptTimeout, false);
540b57cec5SDimitry Andric     switch (read_result) {
550b57cec5SDimitry Andric     case PacketResult::ErrorReplyTimeout: {
560b57cec5SDimitry Andric       std::lock_guard<std::mutex> lock(m_mutex);
570b57cec5SDimitry Andric       if (m_async_count == 0)
580b57cec5SDimitry Andric         continue;
590b57cec5SDimitry Andric       if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout)
600b57cec5SDimitry Andric         return eStateInvalid;
610b57cec5SDimitry Andric       break;
620b57cec5SDimitry Andric     }
630b57cec5SDimitry Andric     case PacketResult::Success:
640b57cec5SDimitry Andric       break;
650b57cec5SDimitry Andric     default:
66*9dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
670b57cec5SDimitry Andric                 __FUNCTION__);
680b57cec5SDimitry Andric       return eStateInvalid;
690b57cec5SDimitry Andric     }
700b57cec5SDimitry Andric     if (response.Empty())
710b57cec5SDimitry Andric       return eStateInvalid;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric     const char stop_type = response.GetChar();
74*9dba64beSDimitry Andric     LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
75*9dba64beSDimitry Andric               response.GetStringRef().data());
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric     switch (stop_type) {
780b57cec5SDimitry Andric     case 'W':
790b57cec5SDimitry Andric     case 'X':
800b57cec5SDimitry Andric       return eStateExited;
810b57cec5SDimitry Andric     case 'E':
820b57cec5SDimitry Andric       // ERROR
830b57cec5SDimitry Andric       return eStateInvalid;
840b57cec5SDimitry Andric     default:
85*9dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
860b57cec5SDimitry Andric                 __FUNCTION__);
870b57cec5SDimitry Andric       return eStateInvalid;
880b57cec5SDimitry Andric     case 'O': {
890b57cec5SDimitry Andric       std::string inferior_stdout;
900b57cec5SDimitry Andric       response.GetHexByteString(inferior_stdout);
910b57cec5SDimitry Andric       delegate.HandleAsyncStdout(inferior_stdout);
920b57cec5SDimitry Andric       break;
930b57cec5SDimitry Andric     }
940b57cec5SDimitry Andric     case 'A':
950b57cec5SDimitry Andric       delegate.HandleAsyncMisc(
960b57cec5SDimitry Andric           llvm::StringRef(response.GetStringRef()).substr(1));
970b57cec5SDimitry Andric       break;
980b57cec5SDimitry Andric     case 'J':
990b57cec5SDimitry Andric       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
1000b57cec5SDimitry Andric       break;
1010b57cec5SDimitry Andric     case 'T':
1020b57cec5SDimitry Andric     case 'S':
1030b57cec5SDimitry Andric       // Do this with the continue lock held.
1040b57cec5SDimitry Andric       const bool should_stop = ShouldStop(signals, response);
1050b57cec5SDimitry Andric       response.SetFilePos(0);
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric       // The packet we should resume with. In the future we should check our
1080b57cec5SDimitry Andric       // thread list and "do the right thing" for new threads that show up
1090b57cec5SDimitry Andric       // while we stop and run async packets. Setting the packet to 'c' to
1100b57cec5SDimitry Andric       // continue all threads is the right thing to do 99.99% of the time
1110b57cec5SDimitry Andric       // because if a thread was single stepping, and we sent an interrupt, we
1120b57cec5SDimitry Andric       // will notice above that we didn't stop due to an interrupt but stopped
1130b57cec5SDimitry Andric       // due to stepping and we would _not_ continue. This packet may get
1140b57cec5SDimitry Andric       // modified by the async actions (e.g. to send a signal).
1150b57cec5SDimitry Andric       m_continue_packet = 'c';
1160b57cec5SDimitry Andric       cont_lock.unlock();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric       delegate.HandleStopReply();
1190b57cec5SDimitry Andric       if (should_stop)
1200b57cec5SDimitry Andric         return eStateStopped;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric       switch (cont_lock.lock()) {
1230b57cec5SDimitry Andric       case ContinueLock::LockResult::Success:
1240b57cec5SDimitry Andric         break;
1250b57cec5SDimitry Andric       case ContinueLock::LockResult::Failed:
1260b57cec5SDimitry Andric         return eStateInvalid;
1270b57cec5SDimitry Andric       case ContinueLock::LockResult::Cancelled:
1280b57cec5SDimitry Andric         return eStateStopped;
1290b57cec5SDimitry Andric       }
1300b57cec5SDimitry Andric       OnRunPacketSent(false);
1310b57cec5SDimitry Andric       break;
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric bool GDBRemoteClientBase::SendAsyncSignal(int signo) {
1370b57cec5SDimitry Andric   Lock lock(*this, true);
1380b57cec5SDimitry Andric   if (!lock || !lock.DidInterrupt())
1390b57cec5SDimitry Andric     return false;
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   m_continue_packet = 'C';
1420b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
1430b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit(signo % 16);
1440b57cec5SDimitry Andric   return true;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric bool GDBRemoteClientBase::Interrupt() {
1480b57cec5SDimitry Andric   Lock lock(*this, true);
1490b57cec5SDimitry Andric   if (!lock.DidInterrupt())
1500b57cec5SDimitry Andric     return false;
1510b57cec5SDimitry Andric   m_should_stop = true;
1520b57cec5SDimitry Andric   return true;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
1550b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponse(
1560b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
1570b57cec5SDimitry Andric     bool send_async) {
1580b57cec5SDimitry Andric   Lock lock(*this, send_async);
1590b57cec5SDimitry Andric   if (!lock) {
1600b57cec5SDimitry Andric     if (Log *log =
1610b57cec5SDimitry Andric             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
162*9dba64beSDimitry Andric       LLDB_LOGF(log,
163*9dba64beSDimitry Andric                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
1640b57cec5SDimitry Andric                 "packet '%.*s' (send_async=%d)",
165*9dba64beSDimitry Andric                 __FUNCTION__, int(payload.size()), payload.data(), send_async);
1660b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   return SendPacketAndWaitForResponseNoLock(payload, response);
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
1730b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
1740b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
1750b57cec5SDimitry Andric     bool send_async,
1760b57cec5SDimitry Andric     llvm::function_ref<void(llvm::StringRef)> output_callback) {
1770b57cec5SDimitry Andric   Lock lock(*this, send_async);
1780b57cec5SDimitry Andric   if (!lock) {
1790b57cec5SDimitry Andric     if (Log *log =
1800b57cec5SDimitry Andric             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
181*9dba64beSDimitry Andric       LLDB_LOGF(log,
182*9dba64beSDimitry Andric                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
1830b57cec5SDimitry Andric                 "packet '%.*s' (send_async=%d)",
184*9dba64beSDimitry Andric                 __FUNCTION__, int(payload.size()), payload.data(), send_async);
1850b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
1890b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
1900b57cec5SDimitry Andric     return packet_result;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
1930b57cec5SDimitry Andric                                      output_callback);
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
1970b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
1980b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response) {
1990b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
2000b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
2010b57cec5SDimitry Andric     return packet_result;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   const size_t max_response_retries = 3;
2040b57cec5SDimitry Andric   for (size_t i = 0; i < max_response_retries; ++i) {
2050b57cec5SDimitry Andric     packet_result = ReadPacket(response, GetPacketTimeout(), true);
2060b57cec5SDimitry Andric     // Make sure we received a response
2070b57cec5SDimitry Andric     if (packet_result != PacketResult::Success)
2080b57cec5SDimitry Andric       return packet_result;
2090b57cec5SDimitry Andric     // Make sure our response is valid for the payload that was sent
2100b57cec5SDimitry Andric     if (response.ValidateResponse())
2110b57cec5SDimitry Andric       return packet_result;
2120b57cec5SDimitry Andric     // Response says it wasn't valid
2130b57cec5SDimitry Andric     Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
214*9dba64beSDimitry Andric     LLDB_LOGF(
215*9dba64beSDimitry Andric         log,
2160b57cec5SDimitry Andric         "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
217*9dba64beSDimitry Andric         int(payload.size()), payload.data(), response.GetStringRef().data(),
2180b57cec5SDimitry Andric         (i == (max_response_retries - 1))
2190b57cec5SDimitry Andric             ? "using invalid response and giving up"
2200b57cec5SDimitry Andric             : "ignoring response and waiting for another");
2210b57cec5SDimitry Andric   }
2220b57cec5SDimitry Andric   return packet_result;
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload,
2260b57cec5SDimitry Andric                                           StringExtractorGDBRemote &response) {
2270b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
228*9dba64beSDimitry Andric   LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   // we want to lock down packet sending while we continue
2310b57cec5SDimitry Andric   Lock lock(*this, true);
2320b57cec5SDimitry Andric 
233*9dba64beSDimitry Andric   LLDB_LOGF(log,
2340b57cec5SDimitry Andric             "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s",
2350b57cec5SDimitry Andric             __FUNCTION__, int(payload.size()), payload.data());
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   if (SendPacketNoLock(payload) != PacketResult::Success)
2380b57cec5SDimitry Andric     return false;
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   OnRunPacketSent(true);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   // wait for the response to the vCont
2430b57cec5SDimitry Andric   if (ReadPacket(response, llvm::None, false) == PacketResult::Success) {
2440b57cec5SDimitry Andric     if (response.IsOKResponse())
2450b57cec5SDimitry Andric       return true;
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   return false;
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
2510b57cec5SDimitry Andric                                      StringExtractorGDBRemote &response) {
2520b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(m_mutex);
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   if (m_async_count == 0)
2550b57cec5SDimitry Andric     return true; // We were not interrupted. The process stopped on its own.
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   // Older debugserver stubs (before April 2016) can return two stop-reply
2580b57cec5SDimitry Andric   // packets in response to a ^C packet. Additionally, all debugservers still
2590b57cec5SDimitry Andric   // return two stop replies if the inferior stops due to some other reason
2600b57cec5SDimitry Andric   // before the remote stub manages to interrupt it. We need to wait for this
2610b57cec5SDimitry Andric   // additional packet to make sure the packet sequence does not get skewed.
2620b57cec5SDimitry Andric   StringExtractorGDBRemote extra_stop_reply_packet;
2630b57cec5SDimitry Andric   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
2660b57cec5SDimitry Andric   // stops with some other signal, we definitely want to stop.
2670b57cec5SDimitry Andric   const uint8_t signo = response.GetHexU8(UINT8_MAX);
2680b57cec5SDimitry Andric   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
2690b57cec5SDimitry Andric       signo != signals.GetSignalNumberFromName("SIGINT"))
2700b57cec5SDimitry Andric     return true;
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   // We probably only stopped to perform some async processing, so continue
2730b57cec5SDimitry Andric   // after that is done.
2740b57cec5SDimitry Andric   // TODO: This is not 100% correct, as the process may have been stopped with
2750b57cec5SDimitry Andric   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
2760b57cec5SDimitry Andric   // normally cause a stop, but if it's done concurrently with a async
2770b57cec5SDimitry Andric   // interrupt, that stop will get eaten (llvm.org/pr20231).
2780b57cec5SDimitry Andric   return false;
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric void GDBRemoteClientBase::OnRunPacketSent(bool first) {
2820b57cec5SDimitry Andric   if (first)
2830b57cec5SDimitry Andric     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
2840b57cec5SDimitry Andric }
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric ///////////////////////////////////////
2870b57cec5SDimitry Andric // GDBRemoteClientBase::ContinueLock //
2880b57cec5SDimitry Andric ///////////////////////////////////////
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
2910b57cec5SDimitry Andric     : m_comm(comm), m_acquired(false) {
2920b57cec5SDimitry Andric   lock();
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::~ContinueLock() {
2960b57cec5SDimitry Andric   if (m_acquired)
2970b57cec5SDimitry Andric     unlock();
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric void GDBRemoteClientBase::ContinueLock::unlock() {
3010b57cec5SDimitry Andric   lldbassert(m_acquired);
3020b57cec5SDimitry Andric   {
3030b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3040b57cec5SDimitry Andric     m_comm.m_is_running = false;
3050b57cec5SDimitry Andric   }
3060b57cec5SDimitry Andric   m_comm.m_cv.notify_all();
3070b57cec5SDimitry Andric   m_acquired = false;
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::LockResult
3110b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::lock() {
3120b57cec5SDimitry Andric   Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
313*9dba64beSDimitry Andric   LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
3140b57cec5SDimitry Andric             __FUNCTION__, m_comm.m_continue_packet.c_str());
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric   lldbassert(!m_acquired);
3170b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3180b57cec5SDimitry Andric   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
3190b57cec5SDimitry Andric   if (m_comm.m_should_stop) {
3200b57cec5SDimitry Andric     m_comm.m_should_stop = false;
321*9dba64beSDimitry Andric     LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
3220b57cec5SDimitry Andric               __FUNCTION__);
3230b57cec5SDimitry Andric     return LockResult::Cancelled;
3240b57cec5SDimitry Andric   }
3250b57cec5SDimitry Andric   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
3260b57cec5SDimitry Andric       PacketResult::Success)
3270b57cec5SDimitry Andric     return LockResult::Failed;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   lldbassert(!m_comm.m_is_running);
3300b57cec5SDimitry Andric   m_comm.m_is_running = true;
3310b57cec5SDimitry Andric   m_acquired = true;
3320b57cec5SDimitry Andric   return LockResult::Success;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric ///////////////////////////////
3360b57cec5SDimitry Andric // GDBRemoteClientBase::Lock //
3370b57cec5SDimitry Andric ///////////////////////////////
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt)
3400b57cec5SDimitry Andric     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
3410b57cec5SDimitry Andric       m_acquired(false), m_did_interrupt(false) {
3420b57cec5SDimitry Andric   SyncWithContinueThread(interrupt);
3430b57cec5SDimitry Andric   if (m_acquired)
3440b57cec5SDimitry Andric     m_async_lock.lock();
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) {
3480b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
3490b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3500b57cec5SDimitry Andric   if (m_comm.m_is_running && !interrupt)
3510b57cec5SDimitry Andric     return; // We were asked to avoid interrupting the sender. Lock is not
3520b57cec5SDimitry Andric             // acquired.
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   ++m_comm.m_async_count;
3550b57cec5SDimitry Andric   if (m_comm.m_is_running) {
3560b57cec5SDimitry Andric     if (m_comm.m_async_count == 1) {
3570b57cec5SDimitry Andric       // The sender has sent the continue packet and we are the first async
3580b57cec5SDimitry Andric       // packet. Let's interrupt it.
3590b57cec5SDimitry Andric       const char ctrl_c = '\x03';
3600b57cec5SDimitry Andric       ConnectionStatus status = eConnectionStatusSuccess;
3610b57cec5SDimitry Andric       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
3620b57cec5SDimitry Andric       if (bytes_written == 0) {
3630b57cec5SDimitry Andric         --m_comm.m_async_count;
364*9dba64beSDimitry Andric         LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
3650b57cec5SDimitry Andric                        "interrupt packet");
3660b57cec5SDimitry Andric         return;
3670b57cec5SDimitry Andric       }
3680b57cec5SDimitry Andric       if (log)
3690b57cec5SDimitry Andric         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
3700b57cec5SDimitry Andric       m_comm.m_interrupt_time = steady_clock::now();
3710b57cec5SDimitry Andric     }
3720b57cec5SDimitry Andric     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
3730b57cec5SDimitry Andric     m_did_interrupt = true;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric   m_acquired = true;
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric GDBRemoteClientBase::Lock::~Lock() {
3790b57cec5SDimitry Andric   if (!m_acquired)
3800b57cec5SDimitry Andric     return;
3810b57cec5SDimitry Andric   {
3820b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3830b57cec5SDimitry Andric     --m_comm.m_async_count;
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   m_comm.m_cv.notify_one();
3860b57cec5SDimitry Andric }
387