xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- GDBRemoteClientBase.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "GDBRemoteClientBase.h"
10061da546Spatrick 
11061da546Spatrick #include "llvm/ADT/StringExtras.h"
12061da546Spatrick 
13061da546Spatrick #include "lldb/Target/UnixSignals.h"
14061da546Spatrick #include "lldb/Utility/LLDBAssert.h"
15061da546Spatrick 
16061da546Spatrick #include "ProcessGDBRemoteLog.h"
17061da546Spatrick 
18061da546Spatrick using namespace lldb;
19061da546Spatrick using namespace lldb_private;
20061da546Spatrick using namespace lldb_private::process_gdb_remote;
21061da546Spatrick using namespace std::chrono;
22061da546Spatrick 
23be691f3bSpatrick // When we've sent a continue packet and are waiting for the target to stop,
24be691f3bSpatrick // we wake up the wait with this interval to make sure the stub hasn't gone
25be691f3bSpatrick // away while we were waiting.
26be691f3bSpatrick static const seconds kWakeupInterval(5);
27061da546Spatrick 
28061da546Spatrick /////////////////////////
29061da546Spatrick // GDBRemoteClientBase //
30061da546Spatrick /////////////////////////
31061da546Spatrick 
32061da546Spatrick GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
33061da546Spatrick 
GDBRemoteClientBase(const char * comm_name)34*f6aab3d8Srobert GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name)
35*f6aab3d8Srobert     : GDBRemoteCommunication(), Broadcaster(nullptr, comm_name),
36*f6aab3d8Srobert       m_async_count(0), m_is_running(false), m_should_stop(false) {}
37061da546Spatrick 
SendContinuePacketAndWaitForResponse(ContinueDelegate & delegate,const UnixSignals & signals,llvm::StringRef payload,std::chrono::seconds interrupt_timeout,StringExtractorGDBRemote & response)38061da546Spatrick StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
39061da546Spatrick     ContinueDelegate &delegate, const UnixSignals &signals,
40be691f3bSpatrick     llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
41be691f3bSpatrick     StringExtractorGDBRemote &response) {
42*f6aab3d8Srobert   Log *log = GetLog(GDBRLog::Process);
43061da546Spatrick   response.Clear();
44061da546Spatrick 
45061da546Spatrick   {
46061da546Spatrick     std::lock_guard<std::mutex> lock(m_mutex);
47dda28197Spatrick     m_continue_packet = std::string(payload);
48061da546Spatrick     m_should_stop = false;
49061da546Spatrick   }
50061da546Spatrick   ContinueLock cont_lock(*this);
51061da546Spatrick   if (!cont_lock)
52061da546Spatrick     return eStateInvalid;
53061da546Spatrick   OnRunPacketSent(true);
54be691f3bSpatrick   // The main ReadPacket loop wakes up at computed_timeout intervals, just to
55be691f3bSpatrick   // check that the connection hasn't dropped.  When we wake up we also check
56be691f3bSpatrick   // whether there is an interrupt request that has reached its endpoint.
57be691f3bSpatrick   // If we want a shorter interrupt timeout that kWakeupInterval, we need to
58be691f3bSpatrick   // choose the shorter interval for the wake up as well.
59be691f3bSpatrick   std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
60be691f3bSpatrick                                                    kWakeupInterval);
61061da546Spatrick   for (;;) {
62be691f3bSpatrick     PacketResult read_result = ReadPacket(response, computed_timeout, false);
63be691f3bSpatrick     // Reset the computed_timeout to the default value in case we are going
64be691f3bSpatrick     // round again.
65be691f3bSpatrick     computed_timeout = std::min(interrupt_timeout, kWakeupInterval);
66061da546Spatrick     switch (read_result) {
67061da546Spatrick     case PacketResult::ErrorReplyTimeout: {
68061da546Spatrick       std::lock_guard<std::mutex> lock(m_mutex);
69be691f3bSpatrick       if (m_async_count == 0) {
70061da546Spatrick         continue;
71be691f3bSpatrick       }
72be691f3bSpatrick       auto cur_time = steady_clock::now();
73be691f3bSpatrick       if (cur_time >= m_interrupt_endpoint)
74061da546Spatrick         return eStateInvalid;
75be691f3bSpatrick       else {
76be691f3bSpatrick         // We woke up and found an interrupt is in flight, but we haven't
77be691f3bSpatrick         // exceeded the interrupt wait time.  So reset the wait time to the
78be691f3bSpatrick         // time left till the interrupt timeout.  But don't wait longer
79be691f3bSpatrick         // than our wakeup timeout.
80be691f3bSpatrick         auto new_wait = m_interrupt_endpoint - cur_time;
81be691f3bSpatrick         computed_timeout = std::min(kWakeupInterval,
82be691f3bSpatrick             std::chrono::duration_cast<std::chrono::seconds>(new_wait));
83be691f3bSpatrick         continue;
84be691f3bSpatrick       }
85061da546Spatrick       break;
86061da546Spatrick     }
87061da546Spatrick     case PacketResult::Success:
88061da546Spatrick       break;
89061da546Spatrick     default:
90061da546Spatrick       LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
91061da546Spatrick                 __FUNCTION__);
92061da546Spatrick       return eStateInvalid;
93061da546Spatrick     }
94061da546Spatrick     if (response.Empty())
95061da546Spatrick       return eStateInvalid;
96061da546Spatrick 
97061da546Spatrick     const char stop_type = response.GetChar();
98061da546Spatrick     LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
99061da546Spatrick               response.GetStringRef().data());
100061da546Spatrick 
101061da546Spatrick     switch (stop_type) {
102061da546Spatrick     case 'W':
103061da546Spatrick     case 'X':
104061da546Spatrick       return eStateExited;
105061da546Spatrick     case 'E':
106061da546Spatrick       // ERROR
107061da546Spatrick       return eStateInvalid;
108061da546Spatrick     default:
109061da546Spatrick       LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
110061da546Spatrick                 __FUNCTION__);
111061da546Spatrick       return eStateInvalid;
112061da546Spatrick     case 'O': {
113061da546Spatrick       std::string inferior_stdout;
114061da546Spatrick       response.GetHexByteString(inferior_stdout);
115061da546Spatrick       delegate.HandleAsyncStdout(inferior_stdout);
116061da546Spatrick       break;
117061da546Spatrick     }
118061da546Spatrick     case 'A':
119061da546Spatrick       delegate.HandleAsyncMisc(
120061da546Spatrick           llvm::StringRef(response.GetStringRef()).substr(1));
121061da546Spatrick       break;
122061da546Spatrick     case 'J':
123061da546Spatrick       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
124061da546Spatrick       break;
125061da546Spatrick     case 'T':
126061da546Spatrick     case 'S':
127061da546Spatrick       // Do this with the continue lock held.
128061da546Spatrick       const bool should_stop = ShouldStop(signals, response);
129061da546Spatrick       response.SetFilePos(0);
130061da546Spatrick 
131061da546Spatrick       // The packet we should resume with. In the future we should check our
132061da546Spatrick       // thread list and "do the right thing" for new threads that show up
133061da546Spatrick       // while we stop and run async packets. Setting the packet to 'c' to
134061da546Spatrick       // continue all threads is the right thing to do 99.99% of the time
135061da546Spatrick       // because if a thread was single stepping, and we sent an interrupt, we
136061da546Spatrick       // will notice above that we didn't stop due to an interrupt but stopped
137061da546Spatrick       // due to stepping and we would _not_ continue. This packet may get
138061da546Spatrick       // modified by the async actions (e.g. to send a signal).
139061da546Spatrick       m_continue_packet = 'c';
140061da546Spatrick       cont_lock.unlock();
141061da546Spatrick 
142061da546Spatrick       delegate.HandleStopReply();
143061da546Spatrick       if (should_stop)
144061da546Spatrick         return eStateStopped;
145061da546Spatrick 
146061da546Spatrick       switch (cont_lock.lock()) {
147061da546Spatrick       case ContinueLock::LockResult::Success:
148061da546Spatrick         break;
149061da546Spatrick       case ContinueLock::LockResult::Failed:
150061da546Spatrick         return eStateInvalid;
151061da546Spatrick       case ContinueLock::LockResult::Cancelled:
152061da546Spatrick         return eStateStopped;
153061da546Spatrick       }
154061da546Spatrick       OnRunPacketSent(false);
155061da546Spatrick       break;
156061da546Spatrick     }
157061da546Spatrick   }
158061da546Spatrick }
159061da546Spatrick 
SendAsyncSignal(int signo,std::chrono::seconds interrupt_timeout)160be691f3bSpatrick bool GDBRemoteClientBase::SendAsyncSignal(
161be691f3bSpatrick     int signo, std::chrono::seconds interrupt_timeout) {
162be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
163061da546Spatrick   if (!lock || !lock.DidInterrupt())
164061da546Spatrick     return false;
165061da546Spatrick 
166061da546Spatrick   m_continue_packet = 'C';
167061da546Spatrick   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
168061da546Spatrick   m_continue_packet += llvm::hexdigit(signo % 16);
169061da546Spatrick   return true;
170061da546Spatrick }
171061da546Spatrick 
Interrupt(std::chrono::seconds interrupt_timeout)172be691f3bSpatrick bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
173be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
174061da546Spatrick   if (!lock.DidInterrupt())
175061da546Spatrick     return false;
176061da546Spatrick   m_should_stop = true;
177061da546Spatrick   return true;
178061da546Spatrick }
179be691f3bSpatrick 
180061da546Spatrick GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponse(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout)181061da546Spatrick GDBRemoteClientBase::SendPacketAndWaitForResponse(
182061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response,
183be691f3bSpatrick     std::chrono::seconds interrupt_timeout) {
184be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
185061da546Spatrick   if (!lock) {
186*f6aab3d8Srobert     if (Log *log = GetLog(GDBRLog::Process))
187061da546Spatrick       LLDB_LOGF(log,
188061da546Spatrick                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
189be691f3bSpatrick                 "packet '%.*s'",
190be691f3bSpatrick                 __FUNCTION__, int(payload.size()), payload.data());
191061da546Spatrick     return PacketResult::ErrorSendFailed;
192061da546Spatrick   }
193061da546Spatrick 
194061da546Spatrick   return SendPacketAndWaitForResponseNoLock(payload, response);
195061da546Spatrick }
196061da546Spatrick 
197061da546Spatrick GDBRemoteCommunication::PacketResult
ReadPacketWithOutputSupport(StringExtractorGDBRemote & response,Timeout<std::micro> timeout,bool sync_on_timeout,llvm::function_ref<void (llvm::StringRef)> output_callback)198*f6aab3d8Srobert GDBRemoteClientBase::ReadPacketWithOutputSupport(
199*f6aab3d8Srobert     StringExtractorGDBRemote &response, Timeout<std::micro> timeout,
200*f6aab3d8Srobert     bool sync_on_timeout,
201*f6aab3d8Srobert     llvm::function_ref<void(llvm::StringRef)> output_callback) {
202*f6aab3d8Srobert   auto result = ReadPacket(response, timeout, sync_on_timeout);
203*f6aab3d8Srobert   while (result == PacketResult::Success && response.IsNormalResponse() &&
204*f6aab3d8Srobert          response.PeekChar() == 'O') {
205*f6aab3d8Srobert     response.GetChar();
206*f6aab3d8Srobert     std::string output;
207*f6aab3d8Srobert     if (response.GetHexByteString(output))
208*f6aab3d8Srobert       output_callback(output);
209*f6aab3d8Srobert     result = ReadPacket(response, timeout, sync_on_timeout);
210*f6aab3d8Srobert   }
211*f6aab3d8Srobert   return result;
212*f6aab3d8Srobert }
213*f6aab3d8Srobert 
214*f6aab3d8Srobert GDBRemoteCommunication::PacketResult
SendPacketAndReceiveResponseWithOutputSupport(llvm::StringRef payload,StringExtractorGDBRemote & response,std::chrono::seconds interrupt_timeout,llvm::function_ref<void (llvm::StringRef)> output_callback)215061da546Spatrick GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
216061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response,
217be691f3bSpatrick     std::chrono::seconds interrupt_timeout,
218061da546Spatrick     llvm::function_ref<void(llvm::StringRef)> output_callback) {
219be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
220061da546Spatrick   if (!lock) {
221*f6aab3d8Srobert     if (Log *log = GetLog(GDBRLog::Process))
222061da546Spatrick       LLDB_LOGF(log,
223061da546Spatrick                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
224be691f3bSpatrick                 "packet '%.*s'",
225be691f3bSpatrick                 __FUNCTION__, int(payload.size()), payload.data());
226061da546Spatrick     return PacketResult::ErrorSendFailed;
227061da546Spatrick   }
228061da546Spatrick 
229061da546Spatrick   PacketResult packet_result = SendPacketNoLock(payload);
230061da546Spatrick   if (packet_result != PacketResult::Success)
231061da546Spatrick     return packet_result;
232061da546Spatrick 
233061da546Spatrick   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
234061da546Spatrick                                      output_callback);
235061da546Spatrick }
236061da546Spatrick 
237061da546Spatrick GDBRemoteCommunication::PacketResult
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,StringExtractorGDBRemote & response)238061da546Spatrick GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
239061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response) {
240061da546Spatrick   PacketResult packet_result = SendPacketNoLock(payload);
241061da546Spatrick   if (packet_result != PacketResult::Success)
242061da546Spatrick     return packet_result;
243061da546Spatrick 
244061da546Spatrick   const size_t max_response_retries = 3;
245061da546Spatrick   for (size_t i = 0; i < max_response_retries; ++i) {
246061da546Spatrick     packet_result = ReadPacket(response, GetPacketTimeout(), true);
247061da546Spatrick     // Make sure we received a response
248061da546Spatrick     if (packet_result != PacketResult::Success)
249061da546Spatrick       return packet_result;
250061da546Spatrick     // Make sure our response is valid for the payload that was sent
251061da546Spatrick     if (response.ValidateResponse())
252061da546Spatrick       return packet_result;
253061da546Spatrick     // Response says it wasn't valid
254*f6aab3d8Srobert     Log *log = GetLog(GDBRLog::Packets);
255061da546Spatrick     LLDB_LOGF(
256061da546Spatrick         log,
257061da546Spatrick         "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
258061da546Spatrick         int(payload.size()), payload.data(), response.GetStringRef().data(),
259061da546Spatrick         (i == (max_response_retries - 1))
260061da546Spatrick             ? "using invalid response and giving up"
261061da546Spatrick             : "ignoring response and waiting for another");
262061da546Spatrick   }
263061da546Spatrick   return packet_result;
264061da546Spatrick }
265061da546Spatrick 
ShouldStop(const UnixSignals & signals,StringExtractorGDBRemote & response)266061da546Spatrick bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
267061da546Spatrick                                      StringExtractorGDBRemote &response) {
268061da546Spatrick   std::lock_guard<std::mutex> lock(m_mutex);
269061da546Spatrick 
270061da546Spatrick   if (m_async_count == 0)
271061da546Spatrick     return true; // We were not interrupted. The process stopped on its own.
272061da546Spatrick 
273061da546Spatrick   // Older debugserver stubs (before April 2016) can return two stop-reply
274061da546Spatrick   // packets in response to a ^C packet. Additionally, all debugservers still
275061da546Spatrick   // return two stop replies if the inferior stops due to some other reason
276061da546Spatrick   // before the remote stub manages to interrupt it. We need to wait for this
277061da546Spatrick   // additional packet to make sure the packet sequence does not get skewed.
278061da546Spatrick   StringExtractorGDBRemote extra_stop_reply_packet;
279061da546Spatrick   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
280061da546Spatrick 
281061da546Spatrick   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
282061da546Spatrick   // stops with some other signal, we definitely want to stop.
283061da546Spatrick   const uint8_t signo = response.GetHexU8(UINT8_MAX);
284061da546Spatrick   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
285061da546Spatrick       signo != signals.GetSignalNumberFromName("SIGINT"))
286061da546Spatrick     return true;
287061da546Spatrick 
288061da546Spatrick   // We probably only stopped to perform some async processing, so continue
289061da546Spatrick   // after that is done.
290061da546Spatrick   // TODO: This is not 100% correct, as the process may have been stopped with
291061da546Spatrick   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
292061da546Spatrick   // normally cause a stop, but if it's done concurrently with a async
293061da546Spatrick   // interrupt, that stop will get eaten (llvm.org/pr20231).
294061da546Spatrick   return false;
295061da546Spatrick }
296061da546Spatrick 
OnRunPacketSent(bool first)297061da546Spatrick void GDBRemoteClientBase::OnRunPacketSent(bool first) {
298061da546Spatrick   if (first)
299061da546Spatrick     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
300061da546Spatrick }
301061da546Spatrick 
302061da546Spatrick ///////////////////////////////////////
303061da546Spatrick // GDBRemoteClientBase::ContinueLock //
304061da546Spatrick ///////////////////////////////////////
305061da546Spatrick 
ContinueLock(GDBRemoteClientBase & comm)306061da546Spatrick GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
307061da546Spatrick     : m_comm(comm), m_acquired(false) {
308061da546Spatrick   lock();
309061da546Spatrick }
310061da546Spatrick 
~ContinueLock()311061da546Spatrick GDBRemoteClientBase::ContinueLock::~ContinueLock() {
312061da546Spatrick   if (m_acquired)
313061da546Spatrick     unlock();
314061da546Spatrick }
315061da546Spatrick 
unlock()316061da546Spatrick void GDBRemoteClientBase::ContinueLock::unlock() {
317061da546Spatrick   lldbassert(m_acquired);
318061da546Spatrick   {
319061da546Spatrick     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
320061da546Spatrick     m_comm.m_is_running = false;
321061da546Spatrick   }
322061da546Spatrick   m_comm.m_cv.notify_all();
323061da546Spatrick   m_acquired = false;
324061da546Spatrick }
325061da546Spatrick 
326061da546Spatrick GDBRemoteClientBase::ContinueLock::LockResult
lock()327061da546Spatrick GDBRemoteClientBase::ContinueLock::lock() {
328*f6aab3d8Srobert   Log *log = GetLog(GDBRLog::Process);
329061da546Spatrick   LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
330061da546Spatrick             __FUNCTION__, m_comm.m_continue_packet.c_str());
331061da546Spatrick 
332061da546Spatrick   lldbassert(!m_acquired);
333061da546Spatrick   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
334061da546Spatrick   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
335061da546Spatrick   if (m_comm.m_should_stop) {
336061da546Spatrick     m_comm.m_should_stop = false;
337061da546Spatrick     LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
338061da546Spatrick               __FUNCTION__);
339061da546Spatrick     return LockResult::Cancelled;
340061da546Spatrick   }
341061da546Spatrick   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
342061da546Spatrick       PacketResult::Success)
343061da546Spatrick     return LockResult::Failed;
344061da546Spatrick 
345061da546Spatrick   lldbassert(!m_comm.m_is_running);
346061da546Spatrick   m_comm.m_is_running = true;
347061da546Spatrick   m_acquired = true;
348061da546Spatrick   return LockResult::Success;
349061da546Spatrick }
350061da546Spatrick 
351061da546Spatrick ///////////////////////////////
352061da546Spatrick // GDBRemoteClientBase::Lock //
353061da546Spatrick ///////////////////////////////
354061da546Spatrick 
Lock(GDBRemoteClientBase & comm,std::chrono::seconds interrupt_timeout)355be691f3bSpatrick GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
356be691f3bSpatrick                                 std::chrono::seconds interrupt_timeout)
357061da546Spatrick     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
358be691f3bSpatrick       m_interrupt_timeout(interrupt_timeout), m_acquired(false),
359be691f3bSpatrick       m_did_interrupt(false) {
360be691f3bSpatrick   SyncWithContinueThread();
361061da546Spatrick   if (m_acquired)
362061da546Spatrick     m_async_lock.lock();
363061da546Spatrick }
364061da546Spatrick 
SyncWithContinueThread()365be691f3bSpatrick void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
366*f6aab3d8Srobert   Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets);
367061da546Spatrick   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
368be691f3bSpatrick   if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
369061da546Spatrick     return; // We were asked to avoid interrupting the sender. Lock is not
370061da546Spatrick             // acquired.
371061da546Spatrick 
372061da546Spatrick   ++m_comm.m_async_count;
373061da546Spatrick   if (m_comm.m_is_running) {
374061da546Spatrick     if (m_comm.m_async_count == 1) {
375061da546Spatrick       // The sender has sent the continue packet and we are the first async
376061da546Spatrick       // packet. Let's interrupt it.
377061da546Spatrick       const char ctrl_c = '\x03';
378061da546Spatrick       ConnectionStatus status = eConnectionStatusSuccess;
379061da546Spatrick       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
380061da546Spatrick       if (bytes_written == 0) {
381061da546Spatrick         --m_comm.m_async_count;
382061da546Spatrick         LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
383061da546Spatrick                        "interrupt packet");
384061da546Spatrick         return;
385061da546Spatrick       }
386be691f3bSpatrick       m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
387061da546Spatrick       if (log)
388061da546Spatrick         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
389061da546Spatrick     }
390061da546Spatrick     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
391061da546Spatrick     m_did_interrupt = true;
392061da546Spatrick   }
393061da546Spatrick   m_acquired = true;
394061da546Spatrick }
395061da546Spatrick 
~Lock()396061da546Spatrick GDBRemoteClientBase::Lock::~Lock() {
397061da546Spatrick   if (!m_acquired)
398061da546Spatrick     return;
399061da546Spatrick   {
400061da546Spatrick     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
401061da546Spatrick     --m_comm.m_async_count;
402061da546Spatrick   }
403061da546Spatrick   m_comm.m_cv.notify_one();
404061da546Spatrick }
405