xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "GDBRemoteClientBase.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "lldb/Target/UnixSignals.h"
14*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric #include "ProcessGDBRemoteLog.h"
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric using namespace lldb;
19*0b57cec5SDimitry Andric using namespace lldb_private;
20*0b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote;
21*0b57cec5SDimitry Andric using namespace std::chrono;
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric static const seconds kInterruptTimeout(5);
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric /////////////////////////
26*0b57cec5SDimitry Andric // GDBRemoteClientBase //
27*0b57cec5SDimitry Andric /////////////////////////
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
30*0b57cec5SDimitry Andric 
31*0b57cec5SDimitry Andric GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name,
32*0b57cec5SDimitry Andric                                          const char *listener_name)
33*0b57cec5SDimitry Andric     : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0),
34*0b57cec5SDimitry Andric       m_is_running(false), m_should_stop(false) {}
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
37*0b57cec5SDimitry Andric     ContinueDelegate &delegate, const UnixSignals &signals,
38*0b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response) {
39*0b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
40*0b57cec5SDimitry Andric   response.Clear();
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric   {
43*0b57cec5SDimitry Andric     std::lock_guard<std::mutex> lock(m_mutex);
44*0b57cec5SDimitry Andric     m_continue_packet = payload;
45*0b57cec5SDimitry Andric     m_should_stop = false;
46*0b57cec5SDimitry Andric   }
47*0b57cec5SDimitry Andric   ContinueLock cont_lock(*this);
48*0b57cec5SDimitry Andric   if (!cont_lock)
49*0b57cec5SDimitry Andric     return eStateInvalid;
50*0b57cec5SDimitry Andric   OnRunPacketSent(true);
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric   for (;;) {
53*0b57cec5SDimitry Andric     PacketResult read_result = ReadPacket(response, kInterruptTimeout, false);
54*0b57cec5SDimitry Andric     switch (read_result) {
55*0b57cec5SDimitry Andric     case PacketResult::ErrorReplyTimeout: {
56*0b57cec5SDimitry Andric       std::lock_guard<std::mutex> lock(m_mutex);
57*0b57cec5SDimitry Andric       if (m_async_count == 0)
58*0b57cec5SDimitry Andric         continue;
59*0b57cec5SDimitry Andric       if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout)
60*0b57cec5SDimitry Andric         return eStateInvalid;
61*0b57cec5SDimitry Andric       break;
62*0b57cec5SDimitry Andric     }
63*0b57cec5SDimitry Andric     case PacketResult::Success:
64*0b57cec5SDimitry Andric       break;
65*0b57cec5SDimitry Andric     default:
66*0b57cec5SDimitry Andric       if (log)
67*0b57cec5SDimitry Andric         log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false",
68*0b57cec5SDimitry Andric                     __FUNCTION__);
69*0b57cec5SDimitry Andric       return eStateInvalid;
70*0b57cec5SDimitry Andric     }
71*0b57cec5SDimitry Andric     if (response.Empty())
72*0b57cec5SDimitry Andric       return eStateInvalid;
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric     const char stop_type = response.GetChar();
75*0b57cec5SDimitry Andric     if (log)
76*0b57cec5SDimitry Andric       log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
77*0b57cec5SDimitry Andric                   response.GetStringRef().c_str());
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric     switch (stop_type) {
80*0b57cec5SDimitry Andric     case 'W':
81*0b57cec5SDimitry Andric     case 'X':
82*0b57cec5SDimitry Andric       return eStateExited;
83*0b57cec5SDimitry Andric     case 'E':
84*0b57cec5SDimitry Andric       // ERROR
85*0b57cec5SDimitry Andric       return eStateInvalid;
86*0b57cec5SDimitry Andric     default:
87*0b57cec5SDimitry Andric       if (log)
88*0b57cec5SDimitry Andric         log->Printf("GDBRemoteClientBase::%s () unrecognized async packet",
89*0b57cec5SDimitry Andric                     __FUNCTION__);
90*0b57cec5SDimitry Andric       return eStateInvalid;
91*0b57cec5SDimitry Andric     case 'O': {
92*0b57cec5SDimitry Andric       std::string inferior_stdout;
93*0b57cec5SDimitry Andric       response.GetHexByteString(inferior_stdout);
94*0b57cec5SDimitry Andric       delegate.HandleAsyncStdout(inferior_stdout);
95*0b57cec5SDimitry Andric       break;
96*0b57cec5SDimitry Andric     }
97*0b57cec5SDimitry Andric     case 'A':
98*0b57cec5SDimitry Andric       delegate.HandleAsyncMisc(
99*0b57cec5SDimitry Andric           llvm::StringRef(response.GetStringRef()).substr(1));
100*0b57cec5SDimitry Andric       break;
101*0b57cec5SDimitry Andric     case 'J':
102*0b57cec5SDimitry Andric       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
103*0b57cec5SDimitry Andric       break;
104*0b57cec5SDimitry Andric     case 'T':
105*0b57cec5SDimitry Andric     case 'S':
106*0b57cec5SDimitry Andric       // Do this with the continue lock held.
107*0b57cec5SDimitry Andric       const bool should_stop = ShouldStop(signals, response);
108*0b57cec5SDimitry Andric       response.SetFilePos(0);
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric       // The packet we should resume with. In the future we should check our
111*0b57cec5SDimitry Andric       // thread list and "do the right thing" for new threads that show up
112*0b57cec5SDimitry Andric       // while we stop and run async packets. Setting the packet to 'c' to
113*0b57cec5SDimitry Andric       // continue all threads is the right thing to do 99.99% of the time
114*0b57cec5SDimitry Andric       // because if a thread was single stepping, and we sent an interrupt, we
115*0b57cec5SDimitry Andric       // will notice above that we didn't stop due to an interrupt but stopped
116*0b57cec5SDimitry Andric       // due to stepping and we would _not_ continue. This packet may get
117*0b57cec5SDimitry Andric       // modified by the async actions (e.g. to send a signal).
118*0b57cec5SDimitry Andric       m_continue_packet = 'c';
119*0b57cec5SDimitry Andric       cont_lock.unlock();
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric       delegate.HandleStopReply();
122*0b57cec5SDimitry Andric       if (should_stop)
123*0b57cec5SDimitry Andric         return eStateStopped;
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric       switch (cont_lock.lock()) {
126*0b57cec5SDimitry Andric       case ContinueLock::LockResult::Success:
127*0b57cec5SDimitry Andric         break;
128*0b57cec5SDimitry Andric       case ContinueLock::LockResult::Failed:
129*0b57cec5SDimitry Andric         return eStateInvalid;
130*0b57cec5SDimitry Andric       case ContinueLock::LockResult::Cancelled:
131*0b57cec5SDimitry Andric         return eStateStopped;
132*0b57cec5SDimitry Andric       }
133*0b57cec5SDimitry Andric       OnRunPacketSent(false);
134*0b57cec5SDimitry Andric       break;
135*0b57cec5SDimitry Andric     }
136*0b57cec5SDimitry Andric   }
137*0b57cec5SDimitry Andric }
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric bool GDBRemoteClientBase::SendAsyncSignal(int signo) {
140*0b57cec5SDimitry Andric   Lock lock(*this, true);
141*0b57cec5SDimitry Andric   if (!lock || !lock.DidInterrupt())
142*0b57cec5SDimitry Andric     return false;
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric   m_continue_packet = 'C';
145*0b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
146*0b57cec5SDimitry Andric   m_continue_packet += llvm::hexdigit(signo % 16);
147*0b57cec5SDimitry Andric   return true;
148*0b57cec5SDimitry Andric }
149*0b57cec5SDimitry Andric 
150*0b57cec5SDimitry Andric bool GDBRemoteClientBase::Interrupt() {
151*0b57cec5SDimitry Andric   Lock lock(*this, true);
152*0b57cec5SDimitry Andric   if (!lock.DidInterrupt())
153*0b57cec5SDimitry Andric     return false;
154*0b57cec5SDimitry Andric   m_should_stop = true;
155*0b57cec5SDimitry Andric   return true;
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
158*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponse(
159*0b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
160*0b57cec5SDimitry Andric     bool send_async) {
161*0b57cec5SDimitry Andric   Lock lock(*this, send_async);
162*0b57cec5SDimitry Andric   if (!lock) {
163*0b57cec5SDimitry Andric     if (Log *log =
164*0b57cec5SDimitry Andric             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
165*0b57cec5SDimitry Andric       log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending "
166*0b57cec5SDimitry Andric                   "packet '%.*s' (send_async=%d)",
167*0b57cec5SDimitry Andric                   __FUNCTION__, int(payload.size()), payload.data(),
168*0b57cec5SDimitry Andric                   send_async);
169*0b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
170*0b57cec5SDimitry Andric   }
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric   return SendPacketAndWaitForResponseNoLock(payload, response);
173*0b57cec5SDimitry Andric }
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
176*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
177*0b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response,
178*0b57cec5SDimitry Andric     bool send_async,
179*0b57cec5SDimitry Andric     llvm::function_ref<void(llvm::StringRef)> output_callback) {
180*0b57cec5SDimitry Andric   Lock lock(*this, send_async);
181*0b57cec5SDimitry Andric   if (!lock) {
182*0b57cec5SDimitry Andric     if (Log *log =
183*0b57cec5SDimitry Andric             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
184*0b57cec5SDimitry Andric       log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending "
185*0b57cec5SDimitry Andric                   "packet '%.*s' (send_async=%d)",
186*0b57cec5SDimitry Andric                   __FUNCTION__, int(payload.size()), payload.data(),
187*0b57cec5SDimitry Andric                   send_async);
188*0b57cec5SDimitry Andric     return PacketResult::ErrorSendFailed;
189*0b57cec5SDimitry Andric   }
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
192*0b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
193*0b57cec5SDimitry Andric     return packet_result;
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
196*0b57cec5SDimitry Andric                                      output_callback);
197*0b57cec5SDimitry Andric }
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult
200*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
201*0b57cec5SDimitry Andric     llvm::StringRef payload, StringExtractorGDBRemote &response) {
202*0b57cec5SDimitry Andric   PacketResult packet_result = SendPacketNoLock(payload);
203*0b57cec5SDimitry Andric   if (packet_result != PacketResult::Success)
204*0b57cec5SDimitry Andric     return packet_result;
205*0b57cec5SDimitry Andric 
206*0b57cec5SDimitry Andric   const size_t max_response_retries = 3;
207*0b57cec5SDimitry Andric   for (size_t i = 0; i < max_response_retries; ++i) {
208*0b57cec5SDimitry Andric     packet_result = ReadPacket(response, GetPacketTimeout(), true);
209*0b57cec5SDimitry Andric     // Make sure we received a response
210*0b57cec5SDimitry Andric     if (packet_result != PacketResult::Success)
211*0b57cec5SDimitry Andric       return packet_result;
212*0b57cec5SDimitry Andric     // Make sure our response is valid for the payload that was sent
213*0b57cec5SDimitry Andric     if (response.ValidateResponse())
214*0b57cec5SDimitry Andric       return packet_result;
215*0b57cec5SDimitry Andric     // Response says it wasn't valid
216*0b57cec5SDimitry Andric     Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
217*0b57cec5SDimitry Andric     if (log)
218*0b57cec5SDimitry Andric       log->Printf(
219*0b57cec5SDimitry Andric           "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
220*0b57cec5SDimitry Andric           int(payload.size()), payload.data(), response.GetStringRef().c_str(),
221*0b57cec5SDimitry Andric           (i == (max_response_retries - 1))
222*0b57cec5SDimitry Andric               ? "using invalid response and giving up"
223*0b57cec5SDimitry Andric               : "ignoring response and waiting for another");
224*0b57cec5SDimitry Andric   }
225*0b57cec5SDimitry Andric   return packet_result;
226*0b57cec5SDimitry Andric }
227*0b57cec5SDimitry Andric 
228*0b57cec5SDimitry Andric bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload,
229*0b57cec5SDimitry Andric                                           StringExtractorGDBRemote &response) {
230*0b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
231*0b57cec5SDimitry Andric   if (log)
232*0b57cec5SDimitry Andric     log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
233*0b57cec5SDimitry Andric 
234*0b57cec5SDimitry Andric   // we want to lock down packet sending while we continue
235*0b57cec5SDimitry Andric   Lock lock(*this, true);
236*0b57cec5SDimitry Andric 
237*0b57cec5SDimitry Andric   if (log)
238*0b57cec5SDimitry Andric     log->Printf(
239*0b57cec5SDimitry Andric         "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s",
240*0b57cec5SDimitry Andric         __FUNCTION__, int(payload.size()), payload.data());
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric   if (SendPacketNoLock(payload) != PacketResult::Success)
243*0b57cec5SDimitry Andric     return false;
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric   OnRunPacketSent(true);
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric   // wait for the response to the vCont
248*0b57cec5SDimitry Andric   if (ReadPacket(response, llvm::None, false) == PacketResult::Success) {
249*0b57cec5SDimitry Andric     if (response.IsOKResponse())
250*0b57cec5SDimitry Andric       return true;
251*0b57cec5SDimitry Andric   }
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric   return false;
254*0b57cec5SDimitry Andric }
255*0b57cec5SDimitry Andric bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
256*0b57cec5SDimitry Andric                                      StringExtractorGDBRemote &response) {
257*0b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(m_mutex);
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric   if (m_async_count == 0)
260*0b57cec5SDimitry Andric     return true; // We were not interrupted. The process stopped on its own.
261*0b57cec5SDimitry Andric 
262*0b57cec5SDimitry Andric   // Older debugserver stubs (before April 2016) can return two stop-reply
263*0b57cec5SDimitry Andric   // packets in response to a ^C packet. Additionally, all debugservers still
264*0b57cec5SDimitry Andric   // return two stop replies if the inferior stops due to some other reason
265*0b57cec5SDimitry Andric   // before the remote stub manages to interrupt it. We need to wait for this
266*0b57cec5SDimitry Andric   // additional packet to make sure the packet sequence does not get skewed.
267*0b57cec5SDimitry Andric   StringExtractorGDBRemote extra_stop_reply_packet;
268*0b57cec5SDimitry Andric   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
269*0b57cec5SDimitry Andric 
270*0b57cec5SDimitry Andric   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
271*0b57cec5SDimitry Andric   // stops with some other signal, we definitely want to stop.
272*0b57cec5SDimitry Andric   const uint8_t signo = response.GetHexU8(UINT8_MAX);
273*0b57cec5SDimitry Andric   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
274*0b57cec5SDimitry Andric       signo != signals.GetSignalNumberFromName("SIGINT"))
275*0b57cec5SDimitry Andric     return true;
276*0b57cec5SDimitry Andric 
277*0b57cec5SDimitry Andric   // We probably only stopped to perform some async processing, so continue
278*0b57cec5SDimitry Andric   // after that is done.
279*0b57cec5SDimitry Andric   // TODO: This is not 100% correct, as the process may have been stopped with
280*0b57cec5SDimitry Andric   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
281*0b57cec5SDimitry Andric   // normally cause a stop, but if it's done concurrently with a async
282*0b57cec5SDimitry Andric   // interrupt, that stop will get eaten (llvm.org/pr20231).
283*0b57cec5SDimitry Andric   return false;
284*0b57cec5SDimitry Andric }
285*0b57cec5SDimitry Andric 
286*0b57cec5SDimitry Andric void GDBRemoteClientBase::OnRunPacketSent(bool first) {
287*0b57cec5SDimitry Andric   if (first)
288*0b57cec5SDimitry Andric     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
289*0b57cec5SDimitry Andric }
290*0b57cec5SDimitry Andric 
291*0b57cec5SDimitry Andric ///////////////////////////////////////
292*0b57cec5SDimitry Andric // GDBRemoteClientBase::ContinueLock //
293*0b57cec5SDimitry Andric ///////////////////////////////////////
294*0b57cec5SDimitry Andric 
295*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
296*0b57cec5SDimitry Andric     : m_comm(comm), m_acquired(false) {
297*0b57cec5SDimitry Andric   lock();
298*0b57cec5SDimitry Andric }
299*0b57cec5SDimitry Andric 
300*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::~ContinueLock() {
301*0b57cec5SDimitry Andric   if (m_acquired)
302*0b57cec5SDimitry Andric     unlock();
303*0b57cec5SDimitry Andric }
304*0b57cec5SDimitry Andric 
305*0b57cec5SDimitry Andric void GDBRemoteClientBase::ContinueLock::unlock() {
306*0b57cec5SDimitry Andric   lldbassert(m_acquired);
307*0b57cec5SDimitry Andric   {
308*0b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
309*0b57cec5SDimitry Andric     m_comm.m_is_running = false;
310*0b57cec5SDimitry Andric   }
311*0b57cec5SDimitry Andric   m_comm.m_cv.notify_all();
312*0b57cec5SDimitry Andric   m_acquired = false;
313*0b57cec5SDimitry Andric }
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::LockResult
316*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::lock() {
317*0b57cec5SDimitry Andric   Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
318*0b57cec5SDimitry Andric   if (log)
319*0b57cec5SDimitry Andric     log->Printf("GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
320*0b57cec5SDimitry Andric                 __FUNCTION__, m_comm.m_continue_packet.c_str());
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric   lldbassert(!m_acquired);
323*0b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
324*0b57cec5SDimitry Andric   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
325*0b57cec5SDimitry Andric   if (m_comm.m_should_stop) {
326*0b57cec5SDimitry Andric     m_comm.m_should_stop = false;
327*0b57cec5SDimitry Andric     if (log)
328*0b57cec5SDimitry Andric       log->Printf("GDBRemoteClientBase::ContinueLock::%s() cancelled",
329*0b57cec5SDimitry Andric                   __FUNCTION__);
330*0b57cec5SDimitry Andric     return LockResult::Cancelled;
331*0b57cec5SDimitry Andric   }
332*0b57cec5SDimitry Andric   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
333*0b57cec5SDimitry Andric       PacketResult::Success)
334*0b57cec5SDimitry Andric     return LockResult::Failed;
335*0b57cec5SDimitry Andric 
336*0b57cec5SDimitry Andric   lldbassert(!m_comm.m_is_running);
337*0b57cec5SDimitry Andric   m_comm.m_is_running = true;
338*0b57cec5SDimitry Andric   m_acquired = true;
339*0b57cec5SDimitry Andric   return LockResult::Success;
340*0b57cec5SDimitry Andric }
341*0b57cec5SDimitry Andric 
342*0b57cec5SDimitry Andric ///////////////////////////////
343*0b57cec5SDimitry Andric // GDBRemoteClientBase::Lock //
344*0b57cec5SDimitry Andric ///////////////////////////////
345*0b57cec5SDimitry Andric 
346*0b57cec5SDimitry Andric GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt)
347*0b57cec5SDimitry Andric     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
348*0b57cec5SDimitry Andric       m_acquired(false), m_did_interrupt(false) {
349*0b57cec5SDimitry Andric   SyncWithContinueThread(interrupt);
350*0b57cec5SDimitry Andric   if (m_acquired)
351*0b57cec5SDimitry Andric     m_async_lock.lock();
352*0b57cec5SDimitry Andric }
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) {
355*0b57cec5SDimitry Andric   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
356*0b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
357*0b57cec5SDimitry Andric   if (m_comm.m_is_running && !interrupt)
358*0b57cec5SDimitry Andric     return; // We were asked to avoid interrupting the sender. Lock is not
359*0b57cec5SDimitry Andric             // acquired.
360*0b57cec5SDimitry Andric 
361*0b57cec5SDimitry Andric   ++m_comm.m_async_count;
362*0b57cec5SDimitry Andric   if (m_comm.m_is_running) {
363*0b57cec5SDimitry Andric     if (m_comm.m_async_count == 1) {
364*0b57cec5SDimitry Andric       // The sender has sent the continue packet and we are the first async
365*0b57cec5SDimitry Andric       // packet. Let's interrupt it.
366*0b57cec5SDimitry Andric       const char ctrl_c = '\x03';
367*0b57cec5SDimitry Andric       ConnectionStatus status = eConnectionStatusSuccess;
368*0b57cec5SDimitry Andric       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
369*0b57cec5SDimitry Andric       if (bytes_written == 0) {
370*0b57cec5SDimitry Andric         --m_comm.m_async_count;
371*0b57cec5SDimitry Andric         if (log)
372*0b57cec5SDimitry Andric           log->Printf("GDBRemoteClientBase::Lock::Lock failed to send "
373*0b57cec5SDimitry Andric                       "interrupt packet");
374*0b57cec5SDimitry Andric         return;
375*0b57cec5SDimitry Andric       }
376*0b57cec5SDimitry Andric       if (log)
377*0b57cec5SDimitry Andric         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
378*0b57cec5SDimitry Andric       m_comm.m_interrupt_time = steady_clock::now();
379*0b57cec5SDimitry Andric     }
380*0b57cec5SDimitry Andric     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
381*0b57cec5SDimitry Andric     m_did_interrupt = true;
382*0b57cec5SDimitry Andric   }
383*0b57cec5SDimitry Andric   m_acquired = true;
384*0b57cec5SDimitry Andric }
385*0b57cec5SDimitry Andric 
386*0b57cec5SDimitry Andric GDBRemoteClientBase::Lock::~Lock() {
387*0b57cec5SDimitry Andric   if (!m_acquired)
388*0b57cec5SDimitry Andric     return;
389*0b57cec5SDimitry Andric   {
390*0b57cec5SDimitry Andric     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
391*0b57cec5SDimitry Andric     --m_comm.m_async_count;
392*0b57cec5SDimitry Andric   }
393*0b57cec5SDimitry Andric   m_comm.m_cv.notify_one();
394*0b57cec5SDimitry Andric }
395