Skip to content

Commit 446b61c

Browse files
committed
[lldb] [gdb-remote] Send interrupt packets from async thread
Refactor the mechanism for sending interrupt packets to send them from async thread (i.e. the same thread that sends the continue packet preceding them and that waits for the response), rather than from the thread requesting the interrupt. This is going to become especially important when using the vCtrlC packet as part of the non-stop protocol, as -- unlike the simple ^c sent in the all-stop mode -- this packet involves an explicit reply. Suggested by Pavel Labath in D126614. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D131075
1 parent 3b217f2 commit 446b61c

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/ADT/StringExtras.h"
1212

1313
#include "lldb/Target/UnixSignals.h"
14+
#include "lldb/Utility/Connection.h"
1415
#include "lldb/Utility/LLDBAssert.h"
1516

1617
#include "ProcessGDBRemoteLog.h"
@@ -52,13 +53,15 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
5253
if (!cont_lock)
5354
return eStateInvalid;
5455
OnRunPacketSent(true);
55-
// The main ReadPacket loop wakes up at computed_timeout intervals, just to
56+
// The main ReadPacket loop wakes up at computed_timeout intervals, just to
5657
// check that the connection hasn't dropped. When we wake up we also check
5758
// whether there is an interrupt request that has reached its endpoint.
58-
// If we want a shorter interrupt timeout that kWakeupInterval, we need to
59+
// If we want a shorter interrupt timeout that kWakeupInterval, we need to
5960
// choose the shorter interval for the wake up as well.
60-
std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
61-
kWakeupInterval);
61+
std::chrono::seconds computed_timeout =
62+
std::min(interrupt_timeout, kWakeupInterval);
63+
std::chrono::time_point<std::chrono::steady_clock> interrupt_endpoint;
64+
bool interrupt_sent = false;
6265
for (;;) {
6366
PacketResult read_result = ReadPacket(response, computed_timeout, false);
6467
// Reset the computed_timeout to the default value in case we are going
@@ -70,16 +73,35 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
7073
if (m_async_count == 0) {
7174
continue;
7275
}
76+
if (!interrupt_sent) {
77+
const char ctrl_c = '\x03';
78+
ConnectionStatus status = eConnectionStatusSuccess;
79+
size_t bytes_written = Write(&ctrl_c, 1, status, nullptr);
80+
if (bytes_written == 0) {
81+
LLDB_LOG(log, "failed to send interrupt packet");
82+
return eStateInvalid;
83+
}
84+
interrupt_endpoint = steady_clock::now() + interrupt_timeout;
85+
if (log)
86+
log->PutCString(
87+
"GDBRemoteClientBase::SendContinuePacketAndWaitForResponse sent "
88+
"packet: \\x03");
89+
90+
interrupt_sent = true;
91+
continue;
92+
}
93+
7394
auto cur_time = steady_clock::now();
74-
if (cur_time >= m_interrupt_endpoint)
95+
if (cur_time >= interrupt_endpoint)
7596
return eStateInvalid;
7697
else {
7798
// We woke up and found an interrupt is in flight, but we haven't
7899
// exceeded the interrupt wait time. So reset the wait time to the
79100
// time left till the interrupt timeout. But don't wait longer
80101
// than our wakeup timeout.
81-
auto new_wait = m_interrupt_endpoint - cur_time;
82-
computed_timeout = std::min(kWakeupInterval,
102+
auto new_wait = interrupt_endpoint - cur_time;
103+
computed_timeout = std::min(
104+
kWakeupInterval,
83105
std::chrono::duration_cast<std::chrono::seconds>(new_wait));
84106
continue;
85107
}
@@ -347,30 +369,18 @@ GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm,
347369
}
348370

349371
void GDBRemoteClientBase::Lock::SyncWithContinueThread() {
350-
Log *log = GetLog(GDBRLog::Process|GDBRLog::Packets);
351372
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
352373
if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
353374
return; // We were asked to avoid interrupting the sender. Lock is not
354375
// acquired.
355376

356377
++m_comm.m_async_count;
357378
if (m_comm.m_is_running) {
358-
if (m_comm.m_async_count == 1) {
359-
// The sender has sent the continue packet and we are the first async
360-
// packet. Let's interrupt it.
361-
const char ctrl_c = '\x03';
362-
ConnectionStatus status = eConnectionStatusSuccess;
363-
size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr);
364-
if (bytes_written == 0) {
365-
--m_comm.m_async_count;
366-
LLDB_LOGF(log, "GDBRemoteClientBase::Lock::Lock failed to send "
367-
"interrupt packet");
368-
return;
369-
}
370-
m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
371-
if (log)
372-
log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
373-
}
379+
// SendContinuePacketAndWaitForResponse() takes care of sending
380+
// the actual interrupt packet since we've increased m_async_count.
381+
// Interrupt the ReadPacket() call to avoid having to wait for
382+
// the interrupt timeout.
383+
m_comm.GetConnection()->InterruptRead();
374384
m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; });
375385
m_did_interrupt = true;
376386
}

lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,6 @@ class GDBRemoteClientBase : public GDBRemoteCommunication {
121121
/// an async thread e.g. to inject a signal.
122122
std::string m_continue_packet;
123123

124-
/// When was the interrupt packet sent. Used to make sure we time out if the
125-
/// stub does not respond to interrupt requests.
126-
std::chrono::time_point<std::chrono::steady_clock> m_interrupt_endpoint;
127-
128124
/// Number of threads interested in sending.
129125
uint32_t m_async_count;
130126

0 commit comments

Comments
 (0)