xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
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 
23*be691f3bSpatrick // When we've sent a continue packet and are waiting for the target to stop,
24*be691f3bSpatrick // we wake up the wait with this interval to make sure the stub hasn't gone
25*be691f3bSpatrick // away while we were waiting.
26*be691f3bSpatrick static const seconds kWakeupInterval(5);
27061da546Spatrick 
28061da546Spatrick /////////////////////////
29061da546Spatrick // GDBRemoteClientBase //
30061da546Spatrick /////////////////////////
31061da546Spatrick 
32061da546Spatrick GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
33061da546Spatrick 
34061da546Spatrick GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name,
35061da546Spatrick                                          const char *listener_name)
36061da546Spatrick     : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0),
37061da546Spatrick       m_is_running(false), m_should_stop(false) {}
38061da546Spatrick 
39061da546Spatrick StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
40061da546Spatrick     ContinueDelegate &delegate, const UnixSignals &signals,
41*be691f3bSpatrick     llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
42*be691f3bSpatrick     StringExtractorGDBRemote &response) {
43061da546Spatrick   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
44061da546Spatrick   response.Clear();
45061da546Spatrick 
46061da546Spatrick   {
47061da546Spatrick     std::lock_guard<std::mutex> lock(m_mutex);
48dda28197Spatrick     m_continue_packet = std::string(payload);
49061da546Spatrick     m_should_stop = false;
50061da546Spatrick   }
51061da546Spatrick   ContinueLock cont_lock(*this);
52061da546Spatrick   if (!cont_lock)
53061da546Spatrick     return eStateInvalid;
54061da546Spatrick   OnRunPacketSent(true);
55*be691f3bSpatrick   // The main ReadPacket loop wakes up at computed_timeout intervals, just to
56*be691f3bSpatrick   // check that the connection hasn't dropped.  When we wake up we also check
57*be691f3bSpatrick   // whether there is an interrupt request that has reached its endpoint.
58*be691f3bSpatrick   // If we want a shorter interrupt timeout that kWakeupInterval, we need to
59*be691f3bSpatrick   // choose the shorter interval for the wake up as well.
60*be691f3bSpatrick   std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
61*be691f3bSpatrick                                                    kWakeupInterval);
62061da546Spatrick   for (;;) {
63*be691f3bSpatrick     PacketResult read_result = ReadPacket(response, computed_timeout, false);
64*be691f3bSpatrick     // Reset the computed_timeout to the default value in case we are going
65*be691f3bSpatrick     // round again.
66*be691f3bSpatrick     computed_timeout = std::min(interrupt_timeout, kWakeupInterval);
67061da546Spatrick     switch (read_result) {
68061da546Spatrick     case PacketResult::ErrorReplyTimeout: {
69061da546Spatrick       std::lock_guard<std::mutex> lock(m_mutex);
70*be691f3bSpatrick       if (m_async_count == 0) {
71061da546Spatrick         continue;
72*be691f3bSpatrick       }
73*be691f3bSpatrick       auto cur_time = steady_clock::now();
74*be691f3bSpatrick       if (cur_time >= m_interrupt_endpoint)
75061da546Spatrick         return eStateInvalid;
76*be691f3bSpatrick       else {
77*be691f3bSpatrick         // We woke up and found an interrupt is in flight, but we haven't
78*be691f3bSpatrick         // exceeded the interrupt wait time.  So reset the wait time to the
79*be691f3bSpatrick         // time left till the interrupt timeout.  But don't wait longer
80*be691f3bSpatrick         // than our wakeup timeout.
81*be691f3bSpatrick         auto new_wait = m_interrupt_endpoint - cur_time;
82*be691f3bSpatrick         computed_timeout = std::min(kWakeupInterval,
83*be691f3bSpatrick             std::chrono::duration_cast<std::chrono::seconds>(new_wait));
84*be691f3bSpatrick         continue;
85*be691f3bSpatrick       }
86061da546Spatrick       break;
87061da546Spatrick     }
88061da546Spatrick     case PacketResult::Success:
89061da546Spatrick       break;
90061da546Spatrick     default:
91061da546Spatrick       LLDB_LOGF(log, "GDBRemoteClientBase::%s () ReadPacket(...) => false",
92061da546Spatrick                 __FUNCTION__);
93061da546Spatrick       return eStateInvalid;
94061da546Spatrick     }
95061da546Spatrick     if (response.Empty())
96061da546Spatrick       return eStateInvalid;
97061da546Spatrick 
98061da546Spatrick     const char stop_type = response.GetChar();
99061da546Spatrick     LLDB_LOGF(log, "GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
100061da546Spatrick               response.GetStringRef().data());
101061da546Spatrick 
102061da546Spatrick     switch (stop_type) {
103061da546Spatrick     case 'W':
104061da546Spatrick     case 'X':
105061da546Spatrick       return eStateExited;
106061da546Spatrick     case 'E':
107061da546Spatrick       // ERROR
108061da546Spatrick       return eStateInvalid;
109061da546Spatrick     default:
110061da546Spatrick       LLDB_LOGF(log, "GDBRemoteClientBase::%s () unrecognized async packet",
111061da546Spatrick                 __FUNCTION__);
112061da546Spatrick       return eStateInvalid;
113061da546Spatrick     case 'O': {
114061da546Spatrick       std::string inferior_stdout;
115061da546Spatrick       response.GetHexByteString(inferior_stdout);
116061da546Spatrick       delegate.HandleAsyncStdout(inferior_stdout);
117061da546Spatrick       break;
118061da546Spatrick     }
119061da546Spatrick     case 'A':
120061da546Spatrick       delegate.HandleAsyncMisc(
121061da546Spatrick           llvm::StringRef(response.GetStringRef()).substr(1));
122061da546Spatrick       break;
123061da546Spatrick     case 'J':
124061da546Spatrick       delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
125061da546Spatrick       break;
126061da546Spatrick     case 'T':
127061da546Spatrick     case 'S':
128061da546Spatrick       // Do this with the continue lock held.
129061da546Spatrick       const bool should_stop = ShouldStop(signals, response);
130061da546Spatrick       response.SetFilePos(0);
131061da546Spatrick 
132061da546Spatrick       // The packet we should resume with. In the future we should check our
133061da546Spatrick       // thread list and "do the right thing" for new threads that show up
134061da546Spatrick       // while we stop and run async packets. Setting the packet to 'c' to
135061da546Spatrick       // continue all threads is the right thing to do 99.99% of the time
136061da546Spatrick       // because if a thread was single stepping, and we sent an interrupt, we
137061da546Spatrick       // will notice above that we didn't stop due to an interrupt but stopped
138061da546Spatrick       // due to stepping and we would _not_ continue. This packet may get
139061da546Spatrick       // modified by the async actions (e.g. to send a signal).
140061da546Spatrick       m_continue_packet = 'c';
141061da546Spatrick       cont_lock.unlock();
142061da546Spatrick 
143061da546Spatrick       delegate.HandleStopReply();
144061da546Spatrick       if (should_stop)
145061da546Spatrick         return eStateStopped;
146061da546Spatrick 
147061da546Spatrick       switch (cont_lock.lock()) {
148061da546Spatrick       case ContinueLock::LockResult::Success:
149061da546Spatrick         break;
150061da546Spatrick       case ContinueLock::LockResult::Failed:
151061da546Spatrick         return eStateInvalid;
152061da546Spatrick       case ContinueLock::LockResult::Cancelled:
153061da546Spatrick         return eStateStopped;
154061da546Spatrick       }
155061da546Spatrick       OnRunPacketSent(false);
156061da546Spatrick       break;
157061da546Spatrick     }
158061da546Spatrick   }
159061da546Spatrick }
160061da546Spatrick 
161*be691f3bSpatrick bool GDBRemoteClientBase::SendAsyncSignal(
162*be691f3bSpatrick     int signo, std::chrono::seconds interrupt_timeout) {
163*be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
164061da546Spatrick   if (!lock || !lock.DidInterrupt())
165061da546Spatrick     return false;
166061da546Spatrick 
167061da546Spatrick   m_continue_packet = 'C';
168061da546Spatrick   m_continue_packet += llvm::hexdigit((signo / 16) % 16);
169061da546Spatrick   m_continue_packet += llvm::hexdigit(signo % 16);
170061da546Spatrick   return true;
171061da546Spatrick }
172061da546Spatrick 
173*be691f3bSpatrick bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) {
174*be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
175061da546Spatrick   if (!lock.DidInterrupt())
176061da546Spatrick     return false;
177061da546Spatrick   m_should_stop = true;
178061da546Spatrick   return true;
179061da546Spatrick }
180*be691f3bSpatrick 
181061da546Spatrick GDBRemoteCommunication::PacketResult
182061da546Spatrick GDBRemoteClientBase::SendPacketAndWaitForResponse(
183061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response,
184*be691f3bSpatrick     std::chrono::seconds interrupt_timeout) {
185*be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
186061da546Spatrick   if (!lock) {
187061da546Spatrick     if (Log *log =
188061da546Spatrick             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
189061da546Spatrick       LLDB_LOGF(log,
190061da546Spatrick                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
191*be691f3bSpatrick                 "packet '%.*s'",
192*be691f3bSpatrick                 __FUNCTION__, int(payload.size()), payload.data());
193061da546Spatrick     return PacketResult::ErrorSendFailed;
194061da546Spatrick   }
195061da546Spatrick 
196061da546Spatrick   return SendPacketAndWaitForResponseNoLock(payload, response);
197061da546Spatrick }
198061da546Spatrick 
199061da546Spatrick GDBRemoteCommunication::PacketResult
200061da546Spatrick GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport(
201061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response,
202*be691f3bSpatrick     std::chrono::seconds interrupt_timeout,
203061da546Spatrick     llvm::function_ref<void(llvm::StringRef)> output_callback) {
204*be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
205061da546Spatrick   if (!lock) {
206061da546Spatrick     if (Log *log =
207061da546Spatrick             ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
208061da546Spatrick       LLDB_LOGF(log,
209061da546Spatrick                 "GDBRemoteClientBase::%s failed to get mutex, not sending "
210*be691f3bSpatrick                 "packet '%.*s'",
211*be691f3bSpatrick                 __FUNCTION__, int(payload.size()), payload.data());
212061da546Spatrick     return PacketResult::ErrorSendFailed;
213061da546Spatrick   }
214061da546Spatrick 
215061da546Spatrick   PacketResult packet_result = SendPacketNoLock(payload);
216061da546Spatrick   if (packet_result != PacketResult::Success)
217061da546Spatrick     return packet_result;
218061da546Spatrick 
219061da546Spatrick   return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true,
220061da546Spatrick                                      output_callback);
221061da546Spatrick }
222061da546Spatrick 
223061da546Spatrick GDBRemoteCommunication::PacketResult
224061da546Spatrick GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
225061da546Spatrick     llvm::StringRef payload, StringExtractorGDBRemote &response) {
226061da546Spatrick   PacketResult packet_result = SendPacketNoLock(payload);
227061da546Spatrick   if (packet_result != PacketResult::Success)
228061da546Spatrick     return packet_result;
229061da546Spatrick 
230061da546Spatrick   const size_t max_response_retries = 3;
231061da546Spatrick   for (size_t i = 0; i < max_response_retries; ++i) {
232061da546Spatrick     packet_result = ReadPacket(response, GetPacketTimeout(), true);
233061da546Spatrick     // Make sure we received a response
234061da546Spatrick     if (packet_result != PacketResult::Success)
235061da546Spatrick       return packet_result;
236061da546Spatrick     // Make sure our response is valid for the payload that was sent
237061da546Spatrick     if (response.ValidateResponse())
238061da546Spatrick       return packet_result;
239061da546Spatrick     // Response says it wasn't valid
240061da546Spatrick     Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
241061da546Spatrick     LLDB_LOGF(
242061da546Spatrick         log,
243061da546Spatrick         "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
244061da546Spatrick         int(payload.size()), payload.data(), response.GetStringRef().data(),
245061da546Spatrick         (i == (max_response_retries - 1))
246061da546Spatrick             ? "using invalid response and giving up"
247061da546Spatrick             : "ignoring response and waiting for another");
248061da546Spatrick   }
249061da546Spatrick   return packet_result;
250061da546Spatrick }
251061da546Spatrick 
252*be691f3bSpatrick bool GDBRemoteClientBase::SendvContPacket(
253*be691f3bSpatrick     llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
254061da546Spatrick     StringExtractorGDBRemote &response) {
255061da546Spatrick   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
256061da546Spatrick   LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
257061da546Spatrick 
258061da546Spatrick   // we want to lock down packet sending while we continue
259*be691f3bSpatrick   Lock lock(*this, interrupt_timeout);
260061da546Spatrick 
261061da546Spatrick   LLDB_LOGF(log,
262061da546Spatrick             "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s",
263061da546Spatrick             __FUNCTION__, int(payload.size()), payload.data());
264061da546Spatrick 
265061da546Spatrick   if (SendPacketNoLock(payload) != PacketResult::Success)
266061da546Spatrick     return false;
267061da546Spatrick 
268061da546Spatrick   OnRunPacketSent(true);
269061da546Spatrick 
270061da546Spatrick   // wait for the response to the vCont
271061da546Spatrick   if (ReadPacket(response, llvm::None, false) == PacketResult::Success) {
272061da546Spatrick     if (response.IsOKResponse())
273061da546Spatrick       return true;
274061da546Spatrick   }
275061da546Spatrick 
276061da546Spatrick   return false;
277061da546Spatrick }
278061da546Spatrick bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
279061da546Spatrick                                      StringExtractorGDBRemote &response) {
280061da546Spatrick   std::lock_guard<std::mutex> lock(m_mutex);
281061da546Spatrick 
282061da546Spatrick   if (m_async_count == 0)
283061da546Spatrick     return true; // We were not interrupted. The process stopped on its own.
284061da546Spatrick 
285061da546Spatrick   // Older debugserver stubs (before April 2016) can return two stop-reply
286061da546Spatrick   // packets in response to a ^C packet. Additionally, all debugservers still
287061da546Spatrick   // return two stop replies if the inferior stops due to some other reason
288061da546Spatrick   // before the remote stub manages to interrupt it. We need to wait for this
289061da546Spatrick   // additional packet to make sure the packet sequence does not get skewed.
290061da546Spatrick   StringExtractorGDBRemote extra_stop_reply_packet;
291061da546Spatrick   ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
292061da546Spatrick 
293061da546Spatrick   // Interrupting is typically done using SIGSTOP or SIGINT, so if the process
294061da546Spatrick   // stops with some other signal, we definitely want to stop.
295061da546Spatrick   const uint8_t signo = response.GetHexU8(UINT8_MAX);
296061da546Spatrick   if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
297061da546Spatrick       signo != signals.GetSignalNumberFromName("SIGINT"))
298061da546Spatrick     return true;
299061da546Spatrick 
300061da546Spatrick   // We probably only stopped to perform some async processing, so continue
301061da546Spatrick   // after that is done.
302061da546Spatrick   // TODO: This is not 100% correct, as the process may have been stopped with
303061da546Spatrick   // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
304061da546Spatrick   // normally cause a stop, but if it's done concurrently with a async
305061da546Spatrick   // interrupt, that stop will get eaten (llvm.org/pr20231).
306061da546Spatrick   return false;
307061da546Spatrick }
308061da546Spatrick 
309061da546Spatrick void GDBRemoteClientBase::OnRunPacketSent(bool first) {
310061da546Spatrick   if (first)
311061da546Spatrick     BroadcastEvent(eBroadcastBitRunPacketSent, nullptr);
312061da546Spatrick }
313061da546Spatrick 
314061da546Spatrick ///////////////////////////////////////
315061da546Spatrick // GDBRemoteClientBase::ContinueLock //
316061da546Spatrick ///////////////////////////////////////
317061da546Spatrick 
318061da546Spatrick GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
319061da546Spatrick     : m_comm(comm), m_acquired(false) {
320061da546Spatrick   lock();
321061da546Spatrick }
322061da546Spatrick 
323061da546Spatrick GDBRemoteClientBase::ContinueLock::~ContinueLock() {
324061da546Spatrick   if (m_acquired)
325061da546Spatrick     unlock();
326061da546Spatrick }
327061da546Spatrick 
328061da546Spatrick void GDBRemoteClientBase::ContinueLock::unlock() {
329061da546Spatrick   lldbassert(m_acquired);
330061da546Spatrick   {
331061da546Spatrick     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
332061da546Spatrick     m_comm.m_is_running = false;
333061da546Spatrick   }
334061da546Spatrick   m_comm.m_cv.notify_all();
335061da546Spatrick   m_acquired = false;
336061da546Spatrick }
337061da546Spatrick 
338061da546Spatrick GDBRemoteClientBase::ContinueLock::LockResult
339061da546Spatrick GDBRemoteClientBase::ContinueLock::lock() {
340061da546Spatrick   Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
341061da546Spatrick   LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
342061da546Spatrick             __FUNCTION__, m_comm.m_continue_packet.c_str());
343061da546Spatrick 
344061da546Spatrick   lldbassert(!m_acquired);
345061da546Spatrick   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
346061da546Spatrick   m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
347061da546Spatrick   if (m_comm.m_should_stop) {
348061da546Spatrick     m_comm.m_should_stop = false;
349061da546Spatrick     LLDB_LOGF(log, "GDBRemoteClientBase::ContinueLock::%s() cancelled",
350061da546Spatrick               __FUNCTION__);
351061da546Spatrick     return LockResult::Cancelled;
352061da546Spatrick   }
353061da546Spatrick   if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
354061da546Spatrick       PacketResult::Success)
355061da546Spatrick     return LockResult::Failed;
356061da546Spatrick 
357061da546Spatrick   lldbassert(!m_comm.m_is_running);
358061da546Spatrick   m_comm.m_is_running = true;
359061da546Spatrick   m_acquired = true;
360061da546Spatrick   return LockResult::Success;
361061da546Spatrick }
362061da546Spatrick 
363061da546Spatrick ///////////////////////////////
364061da546Spatrick // GDBRemoteClientBase::Lock //
365061da546Spatrick ///////////////////////////////
366061da546Spatrick 
367*be691f3bSpatrick GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
368*be691f3bSpatrick                                 std::chrono::seconds interrupt_timeout)
369061da546Spatrick     : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
370*be691f3bSpatrick       m_interrupt_timeout(interrupt_timeout), m_acquired(false),
371*be691f3bSpatrick       m_did_interrupt(false) {
372*be691f3bSpatrick   SyncWithContinueThread();
373061da546Spatrick   if (m_acquired)
374061da546Spatrick     m_async_lock.lock();
375061da546Spatrick }
376061da546Spatrick 
377*be691f3bSpatrick void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
378061da546Spatrick   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
379061da546Spatrick   std::unique_lock<std::mutex> lock(m_comm.m_mutex);
380*be691f3bSpatrick   if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
381061da546Spatrick     return; // We were asked to avoid interrupting the sender. Lock is not
382061da546Spatrick             // acquired.
383061da546Spatrick 
384061da546Spatrick   ++m_comm.m_async_count;
385061da546Spatrick   if (m_comm.m_is_running) {
386061da546Spatrick     if (m_comm.m_async_count == 1) {
387061da546Spatrick       // The sender has sent the continue packet and we are the first async
388061da546Spatrick       // packet. Let's interrupt it.
389061da546Spatrick       const char ctrl_c = '\x03';
390061da546Spatrick       ConnectionStatus status = eConnectionStatusSuccess;
391061da546Spatrick       size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
392061da546Spatrick       if (bytes_written == 0) {
393061da546Spatrick         --m_comm.m_async_count;
394061da546Spatrick         LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
395061da546Spatrick                        "interrupt packet");
396061da546Spatrick         return;
397061da546Spatrick       }
398*be691f3bSpatrick       m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
399061da546Spatrick       if (log)
400061da546Spatrick         log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
401061da546Spatrick     }
402061da546Spatrick     m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
403061da546Spatrick     m_did_interrupt = true;
404061da546Spatrick   }
405061da546Spatrick   m_acquired = true;
406061da546Spatrick }
407061da546Spatrick 
408061da546Spatrick GDBRemoteClientBase::Lock::~Lock() {
409061da546Spatrick   if (!m_acquired)
410061da546Spatrick     return;
411061da546Spatrick   {
412061da546Spatrick     std::unique_lock<std::mutex> lock(m_comm.m_mutex);
413061da546Spatrick     --m_comm.m_async_count;
414061da546Spatrick   }
415061da546Spatrick   m_comm.m_cv.notify_one();
416061da546Spatrick }
417