xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
15ffd83dbSDimitry Andric //===-- GDBRemoteClientBase.cpp -------------------------------------------===//
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 
23fe6060f1SDimitry Andric // When we've sent a continue packet and are waiting for the target to stop,
24fe6060f1SDimitry Andric // we wake up the wait with this interval to make sure the stub hasn't gone
25fe6060f1SDimitry Andric // away while we were waiting.
26fe6060f1SDimitry Andric static const seconds kWakeupInterval(5);
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric /////////////////////////
290b57cec5SDimitry Andric // GDBRemoteClientBase //
300b57cec5SDimitry Andric /////////////////////////
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
330b57cec5SDimitry Andric 
GDBRemoteClientBase(const char * comm_name)34*bdd1243dSDimitry Andric GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name)
35*bdd1243dSDimitry Andric     : GDBRemoteCommunication(), Broadcaster(nullptr, comm_name),
36*bdd1243dSDimitry Andric       m_async_count(0), m_is_running(false), m_should_stop(false) {}
370b57cec5SDimitry Andric 
SendContinuePacketAndWaitForResponse(ContinueDelegate & delegate,const UnixSignals & signals,llvm::StringRef payload,std::chrono::seconds interrupt_timeout,StringExtractorGDBRemote & response)380b57cec5SDimitry Andric StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
390b57cec5SDimitry Andric     ContinueDelegate &delegate, const UnixSignals &signals,
40fe6060f1SDimitry Andric     llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
41fe6060f1SDimitry Andric     StringExtractorGDBRemote &response) {
421fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Process);
430b57cec5SDimitry Andric   response.Clear();
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   {
460b57cec5SDimitry Andric     std::lock_guard<std::mutex> lock(m_mutex);
475ffd83dbSDimitry Andric     m_continue_packet = std::string(payload);
480b57cec5SDimitry Andric     m_should_stop = false;
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric   ContinueLock cont_lock(*this);
510b57cec5SDimitry Andric   if (!cont_lock)
520b57cec5SDimitry Andric     return eStateInvalid;
530b57cec5SDimitry Andric   OnRunPacketSent(true);
54fe6060f1SDimitry Andric   // The main ReadPacket loop wakes up at computed_timeout intervals, just to
55fe6060f1SDimitry Andric   // check that the connection hasn't dropped.  When we wake up we also check
56fe6060f1SDimitry Andric   // whether there is an interrupt request that has reached its endpoint.
57fe6060f1SDimitry Andric   // If we want a shorter interrupt timeout that kWakeupInterval, we need to
58fe6060f1SDimitry Andric   // choose the shorter interval for the wake up as well.
59fe6060f1SDimitry Andric   std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
60fe6060f1SDimitry Andric                                                    kWakeupInterval);
610b57cec5SDimitry Andric   for (;;) {
62fe6060f1SDimitry Andric     PacketResult read_result = ReadPacket(response, computed_timeout, false);
63fe6060f1SDimitry Andric     // Reset the computed_timeout to the default value in case we are going
64fe6060f1SDimitry Andric     // round again.
65fe6060f1SDimitry Andric     computed_timeout = std::min(interrupt_timeout, kWakeupInterval);
660b57cec5SDimitry Andric     switch (read_result) {
670b57cec5SDimitry Andric     case PacketResult::ErrorReplyTimeout: {
680b57cec5SDimitry Andric       std::lock_guard<std::mutex> lock(m_mutex);
69fe6060f1SDimitry Andric       if (m_async_count == 0) {
700b57cec5SDimitry Andric         continue;
71fe6060f1SDimitry Andric       }
72fe6060f1SDimitry Andric       auto cur_time = steady_clock::now();
73fe6060f1SDimitry Andric       if (cur_time >= m_interrupt_endpoint)
740b57cec5SDimitry Andric         return eStateInvalid;
75fe6060f1SDimitry Andric       else {
76fe6060f1SDimitry Andric         // We woke up and found an interrupt is in flight, but we haven't
77fe6060f1SDimitry Andric         // exceeded the interrupt wait time.  So reset the wait time to the
78fe6060f1SDimitry Andric         // time left till the interrupt timeout.  But don't wait longer
79fe6060f1SDimitry Andric         // than our wakeup timeout.
80fe6060f1SDimitry Andric         auto new_wait = m_interrupt_endpoint - cur_time;
81fe6060f1SDimitry Andric         computed_timeout = std::min(kWakeupInterval,
82fe6060f1SDimitry Andric             std::chrono::duration_cast<std::chrono::seconds>(new_wait));
83fe6060f1SDimitry Andric         continue;
84fe6060f1SDimitry Andric       }
850b57cec5SDimitry Andric       break;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric     case PacketResult::Success:
880b57cec5SDimitry Andric       break;
890b57cec5SDimitry Andric     default:
909dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
910b57cec5SDimitry Andric                 __FUNCTION__);
920b57cec5SDimitry Andric       return eStateInvalid;
930b57cec5SDimitry Andric     }
940b57cec5SDimitry Andric     if (response.Empty())
950b57cec5SDimitry Andric       return eStateInvalid;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric     const char stop_type = response.GetChar();
989dba64beSDimitry Andric     LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
999dba64beSDimitry Andric               response.GetStringRef().data());
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     switch (stop_type) {
1020b57cec5SDimitry Andric     case 'W':
1030b57cec5SDimitry Andric     case 'X':
1040b57cec5SDimitry Andric       return eStateExited;
1050b57cec5SDimitry Andric     case 'E':
1060b57cec5SDimitry Andric       // ERROR
1070b57cec5SDimitry Andric       return eStateInvalid;
1080b57cec5SDimitry Andric     default:
1099dba64beSDimitry Andric       LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
1100b57cec5SDimitry Andric                 __FUNCTION__);
1110b57cec5SDimitry Andric       return eStateInvalid;
1120b57cec5SDimitry Andric     case 'O': {
1130b57cec5SDimitry Andric       std::string inferior_stdout;
1140b57cec5SDimitry Andric       response.GetHexByteString(inferior_stdout);
1150b57cec5SDimitry Andric       delegate.HandleAsyncStdout(inferior_stdout);
1160b57cec5SDimitry Andric       break;
1170b57cec5SDimitry Andric     }
1180b57cec5SDimitry Andric     case 'A':
1190b57cec5SDimitry Andric       delegate.HandleAsyncMisc(
1200b57cec5SDimitry Andric           llvm::StringRef(response.GetStringRef()).substr(1));
1210b57cec5SDimitry Andric       break;
1220b57cec5SDimitry Andric     case 'J':
1230b57cec5SDimitry Andric       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
1240b57cec5SDimitry Andric       break;
1250b57cec5SDimitry Andric     case 'T':
1260b57cec5SDimitry Andric     case 'S':
1270b57cec5SDimitry Andric       // Do this with the continue lock held.
1280b57cec5SDimitry Andric       const bool should_stop = ShouldStop(signals, response);
1290b57cec5SDimitry Andric       response.SetFilePos(0);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric       // The packet we should resume with. In the future we should check our
1320b57cec5SDimitry Andric       // thread list and "do the right thing" for new threads that show up
1330b57cec5SDimitry Andric       // while we stop and run async packets. Setting the packet to 'c' to
1340b57cec5SDimitry Andric       // continue all threads is the right thing to do 99.99% of the time
1350b57cec5SDimitry Andric       // because if a thread was single stepping, and we sent an interrupt, we
1360b57cec5SDimitry Andric       // will notice above that we didn't stop due to an interrupt but stopped
1370b57cec5SDimitry Andric       // due to stepping and we would _not_ continue. This packet may get
1380b57cec5SDimitry Andric       // modified by the async actions (e.g. to send a signal).
1390b57cec5SDimitry Andric       m_continue_packet = 'c';
1400b57cec5SDimitry Andric       cont_lock.unlock();
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric       delegate.HandleStopReply();
1430b57cec5SDimitry Andric       if (should_stop)
1440b57cec5SDimitry Andric         return eStateStopped;
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric       switch (cont_lock.lock()) {
1470b57cec5SDimitry Andric       case ContinueLock::LockResult::Success:
1480b57cec5SDimitry Andric         break;
1490b57cec5SDimitry Andric       case ContinueLock::LockResult::Failed:
1500b57cec5SDimitry Andric         return eStateInvalid;
1510b57cec5SDimitry Andric       case ContinueLock::LockResult::Cancelled:
1520b57cec5SDimitry Andric         return eStateStopped;
1530b57cec5SDimitry Andric       }
1540b57cec5SDimitry Andric       OnRunPacketSent(false);
1550b57cec5SDimitry Andric       break;
1560b57cec5SDimitry Andric     }
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
SendAsyncSignal(int signo,std::chrono::seconds interrupt_timeout)160fe6060f1SDimitry Andric bool GDBRemoteClientBase::SendAsyncSignal(
161fe6060f1SDimitry Andric     int signo, std::chrono::seconds interrupt_timeout) {
162fe6060f1SDimitry Andric   Lock lock(*this, interrupt_timeout);
1630b57cec5SDimitry Andric   if (!lock || !lock.DidInterrupt())
1640b57cec5SDimitry Andric     return false;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   m_continue_packet = 'C';
1670b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
1680b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit(signo % 16);
1690b57cec5SDimitry Andric   return true;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
Interrupt(std::chrono::seconds interrupt_timeout)172fe6060f1SDimitry Andric bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
173fe6060f1SDimitry Andric   Lock lock(*this, interrupt_timeout);
1740b57cec5SDimitry Andric   if (!lock.DidInterrupt())
1750b57cec5SDimitry Andric     return false;
1760b57cec5SDimitry Andric   m_should_stop = true;
1770b57cec5SDimitry Andric   return true;
1780b57cec5SDimitry Andric }
179fe6060f1SDimitry Andric 
1800b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponse(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout)1810b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponse(
1820b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
183fe6060f1SDimitry Andric     std::chrono::seconds interrupt_timeout) {
184fe6060f1SDimitry Andric   Lock lock(*this, interrupt_timeout);
1850b57cec5SDimitry Andric   if (!lock) {
1861fd87a68SDimitry Andric     if (Log *log = GetLog(GDBRLog::Process))
1879dba64beSDimitry Andric       LLDB_LOGF(log,
1889dba64beSDimitry Andric                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
189fe6060f1SDimitry Andric                 "packet '%.*s'",
190fe6060f1SDimitry Andric                 __FUNCTION__, int(payload.size()), payload.data());
1910b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   return SendPacketAndWaitForResponseNoLock(payload, response);
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
ReadPacketWithOutputSupport(StringExtractorGDBRemote & response,Timeout<std::micro> timeout,bool sync_on_timeout,llvm::function_ref<void (llvm::StringRef)> output_callback)198*bdd1243dSDimitry Andric GDBRemoteClientBase::ReadPacketWithOutputSupport(
199*bdd1243dSDimitry Andric     StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
200*bdd1243dSDimitry Andric     bool sync_on_timeout,
201*bdd1243dSDimitry Andric     llvm::function_ref<void(llvm::StringRef)> output_callback) {
202*bdd1243dSDimitry Andric   auto result = ReadPacket(response, timeout, sync_on_timeout);
203*bdd1243dSDimitry Andric   while (result == PacketResult::Success && response.IsNormalResponse() &&
204*bdd1243dSDimitry Andric          response.PeekChar() == 'O') {
205*bdd1243dSDimitry Andric     response.GetChar();
206*bdd1243dSDimitry Andric     std::string output;
207*bdd1243dSDimitry Andric     if (response.GetHexByteString(output))
208*bdd1243dSDimitry Andric       output_callback(output);
209*bdd1243dSDimitry Andric     result = ReadPacket(response, timeout, sync_on_timeout);
210*bdd1243dSDimitry Andric   }
211*bdd1243dSDimitry Andric   return result;
212*bdd1243dSDimitry Andric }
213*bdd1243dSDimitry Andric 
214*bdd1243dSDimitry Andric GDBRemoteCommunication::PacketResult
SendPacketAndReceiveResponseWithOutputSupport(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout,llvm::function_ref<void (llvm::StringRef)> output_callback)2150b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
2160b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
217fe6060f1SDimitry Andric     std::chrono::seconds interrupt_timeout,
2180b57cec5SDimitry Andric     llvm::function_ref<void(llvm::StringRef)> output_callback) {
219fe6060f1SDimitry Andric   Lock lock(*this, interrupt_timeout);
2200b57cec5SDimitry Andric   if (!lock) {
2211fd87a68SDimitry Andric     if (Log *log = GetLog(GDBRLog::Process))
2229dba64beSDimitry Andric       LLDB_LOGF(log,
2239dba64beSDimitry Andric                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
224fe6060f1SDimitry Andric                 "packet '%.*s'",
225fe6060f1SDimitry Andric                 __FUNCTION__, int(payload.size()), payload.data());
2260b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
2300b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
2310b57cec5SDimitry Andric     return packet_result;
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
2340b57cec5SDimitry Andric                                      output_callback);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,StringExtractorGDBRemote & response)2380b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
2390b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response) {
2400b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
2410b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
2420b57cec5SDimitry Andric     return packet_result;
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   const size_t max_response_retries = 3;
2450b57cec5SDimitry Andric   for (size_t i = 0; i < max_response_retries; ++i) {
2460b57cec5SDimitry Andric     packet_result = ReadPacket(response, GetPacketTimeout(), true);
2470b57cec5SDimitry Andric     // Make sure we received a response
2480b57cec5SDimitry Andric     if (packet_result != PacketResult::Success)
2490b57cec5SDimitry Andric       return packet_result;
2500b57cec5SDimitry Andric     // Make sure our response is valid for the payload that was sent
2510b57cec5SDimitry Andric     if (response.ValidateResponse())
2520b57cec5SDimitry Andric       return packet_result;
2530b57cec5SDimitry Andric     // Response says it wasn't valid
2541fd87a68SDimitry Andric     Log *log = GetLog(GDBRLog::Packets);
2559dba64beSDimitry Andric     LLDB_LOGF(
2569dba64beSDimitry Andric         log,
2570b57cec5SDimitry Andric         "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
2589dba64beSDimitry Andric         int(payload.size()), payload.data(), response.GetStringRef().data(),
2590b57cec5SDimitry Andric         (i == (max_response_retries - 1))
2600b57cec5SDimitry Andric             ? "using invalid response and giving up"
2610b57cec5SDimitry Andric             : "ignoring response and waiting for another");
2620b57cec5SDimitry Andric   }
2630b57cec5SDimitry Andric   return packet_result;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
ShouldStop(const UnixSignals & signals,StringExtractorGDBRemote & response)2660b57cec5SDimitry Andric bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
2670b57cec5SDimitry Andric                                      StringExtractorGDBRemote &response) {
2680b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(m_mutex);
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   if (m_async_count == 0)
2710b57cec5SDimitry Andric     return true; // We were not interrupted. The process stopped on its own.
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   // Older debugserver stubs (before April 2016) can return two stop-reply
2740b57cec5SDimitry Andric   // packets in response to a ^C packet. Additionally, all debugservers still
2750b57cec5SDimitry Andric   // return two stop replies if the inferior stops due to some other reason
2760b57cec5SDimitry Andric   // before the remote stub manages to interrupt it. We need to wait for this
2770b57cec5SDimitry Andric   // additional packet to make sure the packet sequence does not get skewed.
2780b57cec5SDimitry Andric   StringExtractorGDBRemote extra_stop_reply_packet;
2790b57cec5SDimitry Andric   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
2820b57cec5SDimitry Andric   // stops with some other signal, we definitely want to stop.
2830b57cec5SDimitry Andric   const uint8_t signo = response.GetHexU8(UINT8_MAX);
2840b57cec5SDimitry Andric   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
2850b57cec5SDimitry Andric       signo != signals.GetSignalNumberFromName("SIGINT"))
2860b57cec5SDimitry Andric     return true;
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric   // We probably only stopped to perform some async processing, so continue
2890b57cec5SDimitry Andric   // after that is done.
2900b57cec5SDimitry Andric   // TODO: This is not 100% correct, as the process may have been stopped with
2910b57cec5SDimitry Andric   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
2920b57cec5SDimitry Andric   // normally cause a stop, but if it's done concurrently with a async
2930b57cec5SDimitry Andric   // interrupt, that stop will get eaten (llvm.org/pr20231).
2940b57cec5SDimitry Andric   return false;
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
OnRunPacketSent(bool first)2970b57cec5SDimitry Andric void GDBRemoteClientBase::OnRunPacketSent(bool first) {
2980b57cec5SDimitry Andric   if (first)
2990b57cec5SDimitry Andric     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric ///////////////////////////////////////
3030b57cec5SDimitry Andric // GDBRemoteClientBase::ContinueLock //
3040b57cec5SDimitry Andric ///////////////////////////////////////
3050b57cec5SDimitry Andric 
ContinueLock(GDBRemoteClientBase & comm)3060b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
3070b57cec5SDimitry Andric     : m_comm(comm), m_acquired(false) {
3080b57cec5SDimitry Andric   lock();
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric 
~ContinueLock()3110b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::~ContinueLock() {
3120b57cec5SDimitry Andric   if (m_acquired)
3130b57cec5SDimitry Andric     unlock();
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
unlock()3160b57cec5SDimitry Andric void GDBRemoteClientBase::ContinueLock::unlock() {
3170b57cec5SDimitry Andric   lldbassert(m_acquired);
3180b57cec5SDimitry Andric   {
3190b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3200b57cec5SDimitry Andric     m_comm.m_is_running = false;
3210b57cec5SDimitry Andric   }
3220b57cec5SDimitry Andric   m_comm.m_cv.notify_all();
3230b57cec5SDimitry Andric   m_acquired = false;
3240b57cec5SDimitry Andric }
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::LockResult
lock()3270b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::lock() {
3281fd87a68SDimitry Andric   Log *log = GetLog(GDBRLog::Process);
3299dba64beSDimitry Andric   LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
3300b57cec5SDimitry Andric             __FUNCTION__, m_comm.m_continue_packet.c_str());
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   lldbassert(!m_acquired);
3330b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3340b57cec5SDimitry Andric   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
3350b57cec5SDimitry Andric   if (m_comm.m_should_stop) {
3360b57cec5SDimitry Andric     m_comm.m_should_stop = false;
3379dba64beSDimitry Andric     LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
3380b57cec5SDimitry Andric               __FUNCTION__);
3390b57cec5SDimitry Andric     return LockResult::Cancelled;
3400b57cec5SDimitry Andric   }
3410b57cec5SDimitry Andric   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
3420b57cec5SDimitry Andric       PacketResult::Success)
3430b57cec5SDimitry Andric     return LockResult::Failed;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   lldbassert(!m_comm.m_is_running);
3460b57cec5SDimitry Andric   m_comm.m_is_running = true;
3470b57cec5SDimitry Andric   m_acquired = true;
3480b57cec5SDimitry Andric   return LockResult::Success;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric ///////////////////////////////
3520b57cec5SDimitry Andric // GDBRemoteClientBase::Lock //
3530b57cec5SDimitry Andric ///////////////////////////////
3540b57cec5SDimitry Andric 
Lock(GDBRemoteClientBase & comm,std::chrono::seconds interrupt_timeout)355fe6060f1SDimitry Andric GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
356fe6060f1SDimitry Andric                                 std::chrono::seconds interrupt_timeout)
3570b57cec5SDimitry Andric     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
358fe6060f1SDimitry Andric       m_interrupt_timeout(interrupt_timeout), m_acquired(false),
359fe6060f1SDimitry Andric       m_did_interrupt(false) {
360fe6060f1SDimitry Andric   SyncWithContinueThread();
3610b57cec5SDimitry Andric   if (m_acquired)
3620b57cec5SDimitry Andric     m_async_lock.lock();
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric 
SyncWithContinueThread()365fe6060f1SDimitry Andric void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
36681ad6265SDimitry Andric   Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets);
3670b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
368fe6060f1SDimitry Andric   if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
3690b57cec5SDimitry Andric     return; // We were asked to avoid interrupting the sender. Lock is not
3700b57cec5SDimitry Andric             // acquired.
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   ++m_comm.m_async_count;
3730b57cec5SDimitry Andric   if (m_comm.m_is_running) {
3740b57cec5SDimitry Andric     if (m_comm.m_async_count == 1) {
3750b57cec5SDimitry Andric       // The sender has sent the continue packet and we are the first async
3760b57cec5SDimitry Andric       // packet. Let's interrupt it.
3770b57cec5SDimitry Andric       const char ctrl_c = '\x03';
3780b57cec5SDimitry Andric       ConnectionStatus status = eConnectionStatusSuccess;
3790b57cec5SDimitry Andric       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
3800b57cec5SDimitry Andric       if (bytes_written == 0) {
3810b57cec5SDimitry Andric         --m_comm.m_async_count;
3829dba64beSDimitry Andric         LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
3830b57cec5SDimitry Andric                        "interrupt packet");
3840b57cec5SDimitry Andric         return;
3850b57cec5SDimitry Andric       }
386fe6060f1SDimitry Andric       m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
3870b57cec5SDimitry Andric       if (log)
3880b57cec5SDimitry Andric         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
3890b57cec5SDimitry Andric     }
3900b57cec5SDimitry Andric     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
3910b57cec5SDimitry Andric     m_did_interrupt = true;
3920b57cec5SDimitry Andric   }
3930b57cec5SDimitry Andric   m_acquired = true;
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric 
~Lock()3960b57cec5SDimitry Andric GDBRemoteClientBase::Lock::~Lock() {
3970b57cec5SDimitry Andric   if (!m_acquired)
3980b57cec5SDimitry Andric     return;
3990b57cec5SDimitry Andric   {
4000b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
4010b57cec5SDimitry Andric     --m_comm.m_async_count;
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric   m_comm.m_cv.notify_one();
4040b57cec5SDimitry Andric }
405