180814287SRaphael Isemann //===-- GDBRemoteClientBase.cpp -------------------------------------------===//
28c1b6bd7SPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68c1b6bd7SPavel Labath //
78c1b6bd7SPavel Labath //===----------------------------------------------------------------------===//
88c1b6bd7SPavel Labath 
98c1b6bd7SPavel Labath #include "GDBRemoteClientBase.h"
108c1b6bd7SPavel Labath 
118c1b6bd7SPavel Labath #include "llvm/ADT/StringExtras.h"
128c1b6bd7SPavel Labath 
138c1b6bd7SPavel Labath #include "lldb/Target/UnixSignals.h"
148c1b6bd7SPavel Labath #include "lldb/Utility/LLDBAssert.h"
158c1b6bd7SPavel Labath 
168c1b6bd7SPavel Labath #include "ProcessGDBRemoteLog.h"
178c1b6bd7SPavel Labath 
188c1b6bd7SPavel Labath using namespace lldb;
198c1b6bd7SPavel Labath using namespace lldb_private;
208c1b6bd7SPavel Labath using namespace lldb_private::process_gdb_remote;
211eff73c3SPavel Labath using namespace std::chrono;
228c1b6bd7SPavel Labath 
23379f24ffSJim Ingham // When we've sent a continue packet and are waiting for the target to stop,
24379f24ffSJim Ingham // we wake up the wait with this interval to make sure the stub hasn't gone
25379f24ffSJim Ingham // away while we were waiting.
26379f24ffSJim Ingham static const seconds kWakeupInterval(5);
278c1b6bd7SPavel Labath 
288c1b6bd7SPavel Labath /////////////////////////
298c1b6bd7SPavel Labath // GDBRemoteClientBase //
308c1b6bd7SPavel Labath /////////////////////////
318c1b6bd7SPavel Labath 
328c1b6bd7SPavel Labath GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
338c1b6bd7SPavel Labath 
GDBRemoteClientBase(const char * comm_name,const char * listener_name)34b9c1b51eSKate Stone GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name,
35b9c1b51eSKate Stone                                          const char *listener_name)
36b9c1b51eSKate Stone     : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0),
37b9c1b51eSKate Stone       m_is_running(false), m_should_stop(false) {}
388c1b6bd7SPavel Labath 
SendContinuePacketAndWaitForResponse(ContinueDelegate & delegate,const UnixSignals & signals,llvm::StringRef payload,std::chrono::seconds interrupt_timeout,StringExtractorGDBRemote & response)39b9c1b51eSKate Stone StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
40b9c1b51eSKate Stone     ContinueDelegate &delegate, const UnixSignals &signals,
41379f24ffSJim Ingham     llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
42379f24ffSJim Ingham     StringExtractorGDBRemote &response) {
43b1127753SPavel Labath   Log *log = GetLog(GDBRLog::Process);
448c1b6bd7SPavel Labath   response.Clear();
458c1b6bd7SPavel Labath 
468c1b6bd7SPavel Labath   {
478c1b6bd7SPavel Labath     std::lock_guard<std::mutex> lock(m_mutex);
48adcd0268SBenjamin Kramer     m_continue_packet = std::string(payload);
498c1b6bd7SPavel Labath     m_should_stop = false;
508c1b6bd7SPavel Labath   }
518c1b6bd7SPavel Labath   ContinueLock cont_lock(*this);
528c1b6bd7SPavel Labath   if (!cont_lock)
538c1b6bd7SPavel Labath     return eStateInvalid;
548c1b6bd7SPavel Labath   OnRunPacketSent(true);
55379f24ffSJim Ingham   // The main ReadPacket loop wakes up at computed_timeout intervals, just to
56379f24ffSJim Ingham   // check that the connection hasn't dropped.  When we wake up we also check
57379f24ffSJim Ingham   // whether there is an interrupt request that has reached its endpoint.
58379f24ffSJim Ingham   // If we want a shorter interrupt timeout that kWakeupInterval, we need to
59379f24ffSJim Ingham   // choose the shorter interval for the wake up as well.
60379f24ffSJim Ingham   std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
61379f24ffSJim Ingham                                                    kWakeupInterval);
62b9c1b51eSKate Stone   for (;;) {
63379f24ffSJim Ingham     PacketResult read_result = ReadPacket(response, computed_timeout, false);
64379f24ffSJim Ingham     // Reset the computed_timeout to the default value in case we are going
65379f24ffSJim Ingham     // round again.
66379f24ffSJim Ingham     computed_timeout = std::min(interrupt_timeout, kWakeupInterval);
67b9c1b51eSKate Stone     switch (read_result) {
68b9c1b51eSKate Stone     case PacketResult::ErrorReplyTimeout: {
698c1b6bd7SPavel Labath       std::lock_guard<std::mutex> lock(m_mutex);
70379f24ffSJim Ingham       if (m_async_count == 0) {
718c1b6bd7SPavel Labath         continue;
72379f24ffSJim Ingham       }
73379f24ffSJim Ingham       auto cur_time = steady_clock::now();
74379f24ffSJim Ingham       if (cur_time >= m_interrupt_endpoint)
758c1b6bd7SPavel Labath         return eStateInvalid;
76379f24ffSJim Ingham       else {
77379f24ffSJim Ingham         // We woke up and found an interrupt is in flight, but we haven't
78379f24ffSJim Ingham         // exceeded the interrupt wait time.  So reset the wait time to the
79379f24ffSJim Ingham         // time left till the interrupt timeout.  But don't wait longer
80379f24ffSJim Ingham         // than our wakeup timeout.
81379f24ffSJim Ingham         auto new_wait = m_interrupt_endpoint - cur_time;
82379f24ffSJim Ingham         computed_timeout = std::min(kWakeupInterval,
83379f24ffSJim Ingham             std::chrono::duration_cast<std::chrono::seconds>(new_wait));
84379f24ffSJim Ingham         continue;
85379f24ffSJim Ingham       }
86a01e024aSAdrian Prantl       break;
878c1b6bd7SPavel Labath     }
888c1b6bd7SPavel Labath     case PacketResult::Success:
898c1b6bd7SPavel Labath       break;
908c1b6bd7SPavel Labath     default:
9163e5fb76SJonas Devlieghere       LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
92b9c1b51eSKate Stone                 __FUNCTION__);
938c1b6bd7SPavel Labath       return eStateInvalid;
948c1b6bd7SPavel Labath     }
958c1b6bd7SPavel Labath     if (response.Empty())
968c1b6bd7SPavel Labath       return eStateInvalid;
978c1b6bd7SPavel Labath 
988c1b6bd7SPavel Labath     const char stop_type = response.GetChar();
9963e5fb76SJonas Devlieghere     LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
100d35b42f2SJonas Devlieghere               response.GetStringRef().data());
1018c1b6bd7SPavel Labath 
102b9c1b51eSKate Stone     switch (stop_type) {
1038c1b6bd7SPavel Labath     case 'W':
1048c1b6bd7SPavel Labath     case 'X':
1058c1b6bd7SPavel Labath       return eStateExited;
1068c1b6bd7SPavel Labath     case 'E':
1078c1b6bd7SPavel Labath       // ERROR
1088c1b6bd7SPavel Labath       return eStateInvalid;
1098c1b6bd7SPavel Labath     default:
11063e5fb76SJonas Devlieghere       LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
111b9c1b51eSKate Stone                 __FUNCTION__);
1128c1b6bd7SPavel Labath       return eStateInvalid;
113b9c1b51eSKate Stone     case 'O': {
1148c1b6bd7SPavel Labath       std::string inferior_stdout;
1158c1b6bd7SPavel Labath       response.GetHexByteString(inferior_stdout);
1168c1b6bd7SPavel Labath       delegate.HandleAsyncStdout(inferior_stdout);
1178c1b6bd7SPavel Labath       break;
1188c1b6bd7SPavel Labath     }
1198c1b6bd7SPavel Labath     case 'A':
120b9c1b51eSKate Stone       delegate.HandleAsyncMisc(
121b9c1b51eSKate Stone           llvm::StringRef(response.GetStringRef()).substr(1));
1228c1b6bd7SPavel Labath       break;
12375930019STodd Fiala     case 'J':
124fcdb1af6STodd Fiala       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
12575930019STodd Fiala       break;
1268c1b6bd7SPavel Labath     case 'T':
1278c1b6bd7SPavel Labath     case 'S':
1288c1b6bd7SPavel Labath       // Do this with the continue lock held.
1298c1b6bd7SPavel Labath       const bool should_stop = ShouldStop(signals, response);
1308c1b6bd7SPavel Labath       response.SetFilePos(0);
1318c1b6bd7SPavel Labath 
13205097246SAdrian Prantl       // The packet we should resume with. In the future we should check our
13305097246SAdrian Prantl       // thread list and "do the right thing" for new threads that show up
13405097246SAdrian Prantl       // while we stop and run async packets. Setting the packet to 'c' to
13505097246SAdrian Prantl       // continue all threads is the right thing to do 99.99% of the time
13605097246SAdrian Prantl       // because if a thread was single stepping, and we sent an interrupt, we
13705097246SAdrian Prantl       // will notice above that we didn't stop due to an interrupt but stopped
13805097246SAdrian Prantl       // due to stepping and we would _not_ continue. This packet may get
13905097246SAdrian Prantl       // modified by the async actions (e.g. to send a signal).
1408c1b6bd7SPavel Labath       m_continue_packet = 'c';
1418c1b6bd7SPavel Labath       cont_lock.unlock();
1428c1b6bd7SPavel Labath 
1438c1b6bd7SPavel Labath       delegate.HandleStopReply();
1448c1b6bd7SPavel Labath       if (should_stop)
1458c1b6bd7SPavel Labath         return eStateStopped;
1468c1b6bd7SPavel Labath 
147b9c1b51eSKate Stone       switch (cont_lock.lock()) {
1488c1b6bd7SPavel Labath       case ContinueLock::LockResult::Success:
1498c1b6bd7SPavel Labath         break;
1508c1b6bd7SPavel Labath       case ContinueLock::LockResult::Failed:
1518c1b6bd7SPavel Labath         return eStateInvalid;
1528c1b6bd7SPavel Labath       case ContinueLock::LockResult::Cancelled:
1538c1b6bd7SPavel Labath         return eStateStopped;
1548c1b6bd7SPavel Labath       }
1558c1b6bd7SPavel Labath       OnRunPacketSent(false);
1568c1b6bd7SPavel Labath       break;
1578c1b6bd7SPavel Labath     }
1588c1b6bd7SPavel Labath   }
1598c1b6bd7SPavel Labath }
1608c1b6bd7SPavel Labath 
SendAsyncSignal(int signo,std::chrono::seconds interrupt_timeout)161379f24ffSJim Ingham bool GDBRemoteClientBase::SendAsyncSignal(
162379f24ffSJim Ingham     int signo, std::chrono::seconds interrupt_timeout) {
163379f24ffSJim Ingham   Lock lock(*this, interrupt_timeout);
1648c1b6bd7SPavel Labath   if (!lock || !lock.DidInterrupt())
1658c1b6bd7SPavel Labath     return false;
1668c1b6bd7SPavel Labath 
1678c1b6bd7SPavel Labath   m_continue_packet = 'C';
1688c1b6bd7SPavel Labath   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
1698c1b6bd7SPavel Labath   m_continue_packet += llvm::hexdigit(signo % 16);
1708c1b6bd7SPavel Labath   return true;
1718c1b6bd7SPavel Labath }
1728c1b6bd7SPavel Labath 
Interrupt(std::chrono::seconds interrupt_timeout)173379f24ffSJim Ingham bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
174379f24ffSJim Ingham   Lock lock(*this, interrupt_timeout);
1758c1b6bd7SPavel Labath   if (!lock.DidInterrupt())
1768c1b6bd7SPavel Labath     return false;
1778c1b6bd7SPavel Labath   m_should_stop = true;
1788c1b6bd7SPavel Labath   return true;
1798c1b6bd7SPavel Labath }
180379f24ffSJim Ingham 
1818c1b6bd7SPavel Labath GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponse(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout)182b9c1b51eSKate Stone GDBRemoteClientBase::SendPacketAndWaitForResponse(
183b9c1b51eSKate Stone     llvm::StringRef payload, StringExtractorGDBRemote &response,
184379f24ffSJim Ingham     std::chrono::seconds interrupt_timeout) {
185379f24ffSJim Ingham   Lock lock(*this, interrupt_timeout);
186b9c1b51eSKate Stone   if (!lock) {
187b1127753SPavel Labath     if (Log *log = GetLog(GDBRLog::Process))
18863e5fb76SJonas Devlieghere       LLDB_LOGF(log,
18963e5fb76SJonas Devlieghere                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
190379f24ffSJim Ingham                 "packet '%.*s'",
191379f24ffSJim Ingham                 __FUNCTION__, int(payload.size()), payload.data());
1928c1b6bd7SPavel Labath     return PacketResult::ErrorSendFailed;
1938c1b6bd7SPavel Labath   }
1948c1b6bd7SPavel Labath 
1955c95ee4dSPavel Labath   return SendPacketAndWaitForResponseNoLock(payload, response);
1968c1b6bd7SPavel Labath }
1978c1b6bd7SPavel Labath 
1988c1b6bd7SPavel Labath GDBRemoteCommunication::PacketResult
SendPacketAndReceiveResponseWithOutputSupport(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout,llvm::function_ref<void (llvm::StringRef)> output_callback)1997da84753SPavel Labath GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
2007da84753SPavel Labath     llvm::StringRef payload, StringExtractorGDBRemote &response,
201379f24ffSJim Ingham     std::chrono::seconds interrupt_timeout,
2027da84753SPavel Labath     llvm::function_ref<void(llvm::StringRef)> output_callback) {
203379f24ffSJim Ingham   Lock lock(*this, interrupt_timeout);
2047da84753SPavel Labath   if (!lock) {
205b1127753SPavel Labath     if (Log *log = GetLog(GDBRLog::Process))
20663e5fb76SJonas Devlieghere       LLDB_LOGF(log,
20763e5fb76SJonas Devlieghere                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
208379f24ffSJim Ingham                 "packet '%.*s'",
209379f24ffSJim Ingham                 __FUNCTION__, int(payload.size()), payload.data());
2107da84753SPavel Labath     return PacketResult::ErrorSendFailed;
2117da84753SPavel Labath   }
2127da84753SPavel Labath 
2137da84753SPavel Labath   PacketResult packet_result = SendPacketNoLock(payload);
2147da84753SPavel Labath   if (packet_result != PacketResult::Success)
2157da84753SPavel Labath     return packet_result;
2167da84753SPavel Labath 
2177da84753SPavel Labath   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
2187da84753SPavel Labath                                      output_callback);
2197da84753SPavel Labath }
2207da84753SPavel Labath 
2217da84753SPavel Labath GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,StringExtractorGDBRemote & response)222b9c1b51eSKate Stone GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
223b9c1b51eSKate Stone     llvm::StringRef payload, StringExtractorGDBRemote &response) {
22426709df8SZachary Turner   PacketResult packet_result = SendPacketNoLock(payload);
2258c1b6bd7SPavel Labath   if (packet_result != PacketResult::Success)
2268c1b6bd7SPavel Labath     return packet_result;
2278c1b6bd7SPavel Labath 
2288c1b6bd7SPavel Labath   const size_t max_response_retries = 3;
229b9c1b51eSKate Stone   for (size_t i = 0; i < max_response_retries; ++i) {
2301eff73c3SPavel Labath     packet_result = ReadPacket(response, GetPacketTimeout(), true);
2318c1b6bd7SPavel Labath     // Make sure we received a response
2328c1b6bd7SPavel Labath     if (packet_result != PacketResult::Success)
2338c1b6bd7SPavel Labath       return packet_result;
2348c1b6bd7SPavel Labath     // Make sure our response is valid for the payload that was sent
2358c1b6bd7SPavel Labath     if (response.ValidateResponse())
2368c1b6bd7SPavel Labath       return packet_result;
2378c1b6bd7SPavel Labath     // Response says it wasn't valid
238b1127753SPavel Labath     Log *log = GetLog(GDBRLog::Packets);
23963e5fb76SJonas Devlieghere     LLDB_LOGF(
24063e5fb76SJonas Devlieghere         log,
241b9c1b51eSKate Stone         "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
242d35b42f2SJonas Devlieghere         int(payload.size()), payload.data(), response.GetStringRef().data(),
243b9c1b51eSKate Stone         (i == (max_response_retries - 1))
244b9c1b51eSKate Stone             ? "using invalid response and giving up"
2458c1b6bd7SPavel Labath             : "ignoring response and waiting for another");
2468c1b6bd7SPavel Labath   }
2478c1b6bd7SPavel Labath   return packet_result;
2488c1b6bd7SPavel Labath }
2498c1b6bd7SPavel Labath 
ShouldStop(const UnixSignals & signals,StringExtractorGDBRemote & response)250b9c1b51eSKate Stone bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
251b9c1b51eSKate Stone                                      StringExtractorGDBRemote &response) {
2528c1b6bd7SPavel Labath   std::lock_guard<std::mutex> lock(m_mutex);
2538c1b6bd7SPavel Labath 
2548c1b6bd7SPavel Labath   if (m_async_count == 0)
2558c1b6bd7SPavel Labath     return true; // We were not interrupted. The process stopped on its own.
2568c1b6bd7SPavel Labath 
25705097246SAdrian Prantl   // Older debugserver stubs (before April 2016) can return two stop-reply
25805097246SAdrian Prantl   // packets in response to a ^C packet. Additionally, all debugservers still
25905097246SAdrian Prantl   // return two stop replies if the inferior stops due to some other reason
26005097246SAdrian Prantl   // before the remote stub manages to interrupt it. We need to wait for this
26105097246SAdrian Prantl   // additional packet to make sure the packet sequence does not get skewed.
2628c1b6bd7SPavel Labath   StringExtractorGDBRemote extra_stop_reply_packet;
2631eff73c3SPavel Labath   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
2648c1b6bd7SPavel Labath 
26505097246SAdrian Prantl   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
26605097246SAdrian Prantl   // stops with some other signal, we definitely want to stop.
2678c1b6bd7SPavel Labath   const uint8_t signo = response.GetHexU8(UINT8_MAX);
268b9c1b51eSKate Stone   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
269b9c1b51eSKate Stone       signo != signals.GetSignalNumberFromName("SIGINT"))
2708c1b6bd7SPavel Labath     return true;
2718c1b6bd7SPavel Labath 
272b9c1b51eSKate Stone   // We probably only stopped to perform some async processing, so continue
273b9c1b51eSKate Stone   // after that is done.
274b9c1b51eSKate Stone   // TODO: This is not 100% correct, as the process may have been stopped with
2751eff73c3SPavel Labath   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
2761eff73c3SPavel Labath   // normally cause a stop, but if it's done concurrently with a async
2771eff73c3SPavel Labath   // interrupt, that stop will get eaten (llvm.org/pr20231).
2788c1b6bd7SPavel Labath   return false;
2798c1b6bd7SPavel Labath }
2808c1b6bd7SPavel Labath 
OnRunPacketSent(bool first)281b9c1b51eSKate Stone void GDBRemoteClientBase::OnRunPacketSent(bool first) {
2828c1b6bd7SPavel Labath   if (first)
283248a1305SKonrad Kleine     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
2848c1b6bd7SPavel Labath }
2858c1b6bd7SPavel Labath 
2868c1b6bd7SPavel Labath ///////////////////////////////////////
2878c1b6bd7SPavel Labath // GDBRemoteClientBase::ContinueLock //
2888c1b6bd7SPavel Labath ///////////////////////////////////////
2898c1b6bd7SPavel Labath 
ContinueLock(GDBRemoteClientBase & comm)290b9c1b51eSKate Stone GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
291b9c1b51eSKate Stone     : m_comm(comm), m_acquired(false) {
2928c1b6bd7SPavel Labath   lock();
2938c1b6bd7SPavel Labath }
2948c1b6bd7SPavel Labath 
~ContinueLock()295b9c1b51eSKate Stone GDBRemoteClientBase::ContinueLock::~ContinueLock() {
2968c1b6bd7SPavel Labath   if (m_acquired)
2978c1b6bd7SPavel Labath     unlock();
2988c1b6bd7SPavel Labath }
2998c1b6bd7SPavel Labath 
unlock()300b9c1b51eSKate Stone void GDBRemoteClientBase::ContinueLock::unlock() {
3018c1b6bd7SPavel Labath   lldbassert(m_acquired);
3028c1b6bd7SPavel Labath   {
3038c1b6bd7SPavel Labath     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3048c1b6bd7SPavel Labath     m_comm.m_is_running = false;
3058c1b6bd7SPavel Labath   }
3068c1b6bd7SPavel Labath   m_comm.m_cv.notify_all();
3078c1b6bd7SPavel Labath   m_acquired = false;
3088c1b6bd7SPavel Labath }
3098c1b6bd7SPavel Labath 
3108c1b6bd7SPavel Labath GDBRemoteClientBase::ContinueLock::LockResult
lock()311b9c1b51eSKate Stone GDBRemoteClientBase::ContinueLock::lock() {
312b1127753SPavel Labath   Log *log = GetLog(GDBRLog::Process);
31363e5fb76SJonas Devlieghere   LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
314b9c1b51eSKate Stone             __FUNCTION__, m_comm.m_continue_packet.c_str());
3158c1b6bd7SPavel Labath 
3168c1b6bd7SPavel Labath   lldbassert(!m_acquired);
3178c1b6bd7SPavel Labath   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3188c1b6bd7SPavel Labath   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
319b9c1b51eSKate Stone   if (m_comm.m_should_stop) {
3208c1b6bd7SPavel Labath     m_comm.m_should_stop = false;
32163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
322b9c1b51eSKate Stone               __FUNCTION__);
3238c1b6bd7SPavel Labath     return LockResult::Cancelled;
3248c1b6bd7SPavel Labath   }
325b9c1b51eSKate Stone   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
326b9c1b51eSKate Stone       PacketResult::Success)
3278c1b6bd7SPavel Labath     return LockResult::Failed;
3288c1b6bd7SPavel Labath 
3298c1b6bd7SPavel Labath   lldbassert(!m_comm.m_is_running);
3308c1b6bd7SPavel Labath   m_comm.m_is_running = true;
3318c1b6bd7SPavel Labath   m_acquired = true;
3328c1b6bd7SPavel Labath   return LockResult::Success;
3338c1b6bd7SPavel Labath }
3348c1b6bd7SPavel Labath 
3358c1b6bd7SPavel Labath ///////////////////////////////
3368c1b6bd7SPavel Labath // GDBRemoteClientBase::Lock //
3378c1b6bd7SPavel Labath ///////////////////////////////
3388c1b6bd7SPavel Labath 
Lock(GDBRemoteClientBase & comm,std::chrono::seconds interrupt_timeout)339379f24ffSJim Ingham GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
340379f24ffSJim Ingham                                 std::chrono::seconds interrupt_timeout)
341b9c1b51eSKate Stone     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
342379f24ffSJim Ingham       m_interrupt_timeout(interrupt_timeout), m_acquired(false),
343379f24ffSJim Ingham       m_did_interrupt(false) {
344379f24ffSJim Ingham   SyncWithContinueThread();
3458c1b6bd7SPavel Labath   if (m_acquired)
3468c1b6bd7SPavel Labath     m_async_lock.lock();
3478c1b6bd7SPavel Labath }
3488c1b6bd7SPavel Labath 
SyncWithContinueThread()349379f24ffSJim Ingham void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
350*63865e1fSJim Ingham   Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets);
3518c1b6bd7SPavel Labath   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
352379f24ffSJim Ingham   if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
353b9c1b51eSKate Stone     return; // We were asked to avoid interrupting the sender. Lock is not
354b9c1b51eSKate Stone             // acquired.
3558c1b6bd7SPavel Labath 
3568c1b6bd7SPavel Labath   ++m_comm.m_async_count;
357b9c1b51eSKate Stone   if (m_comm.m_is_running) {
358b9c1b51eSKate Stone     if (m_comm.m_async_count == 1) {
359b9c1b51eSKate Stone       // The sender has sent the continue packet and we are the first async
360b9c1b51eSKate Stone       // packet. Let's interrupt it.
3618c1b6bd7SPavel Labath       const char ctrl_c = '\x03';
3628c1b6bd7SPavel Labath       ConnectionStatus status = eConnectionStatusSuccess;
363248a1305SKonrad Kleine       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
364b9c1b51eSKate Stone       if (bytes_written == 0) {
3658c1b6bd7SPavel Labath         --m_comm.m_async_count;
36663e5fb76SJonas Devlieghere         LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
367b9c1b51eSKate Stone                        "interrupt packet");
3688c1b6bd7SPavel Labath         return;
3698c1b6bd7SPavel Labath       }
370379f24ffSJim Ingham       m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
3718c1b6bd7SPavel Labath       if (log)
3728c1b6bd7SPavel Labath         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
3738c1b6bd7SPavel Labath     }
374a6682a41SJonas Devlieghere     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
3758c1b6bd7SPavel Labath     m_did_interrupt = true;
3768c1b6bd7SPavel Labath   }
3778c1b6bd7SPavel Labath   m_acquired = true;
3788c1b6bd7SPavel Labath }
3798c1b6bd7SPavel Labath 
~Lock()380b9c1b51eSKate Stone GDBRemoteClientBase::Lock::~Lock() {
3818c1b6bd7SPavel Labath   if (!m_acquired)
3828c1b6bd7SPavel Labath     return;
3838c1b6bd7SPavel Labath   {
3848c1b6bd7SPavel Labath     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
3858c1b6bd7SPavel Labath     --m_comm.m_async_count;
3868c1b6bd7SPavel Labath   }
3878c1b6bd7SPavel Labath   m_comm.m_cv.notify_one();
3888c1b6bd7SPavel Labath }
389