11#include "llvm/ADT/StringExtras.h"
21using namespace std::chrono;
36 m_async_count(0), m_is_running(false), m_should_stop(false) {}
40 llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
46 std::lock_guard<std::mutex> lock(
m_mutex);
59 std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
66 switch (read_result) {
68 std::lock_guard<std::mutex> lock(
m_mutex);
72 auto cur_time = steady_clock::now();
82 std::chrono::duration_cast<std::chrono::seconds>(new_wait));
90 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () ReadPacket(...) => false",
97 const char stop_type = response.
GetChar();
98 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
109 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () unrecognized async packet",
113 std::string inferior_stdout;
128 const bool should_stop =
ShouldStop(signals, response);
146 switch (cont_lock.
lock()) {
161 int signo, std::chrono::seconds interrupt_timeout) {
162 Lock lock(*
this, interrupt_timeout);
173 Lock lock(*
this, interrupt_timeout);
183 std::chrono::seconds interrupt_timeout) {
184 Lock lock(*
this, interrupt_timeout);
188 "GDBRemoteClientBase::%s failed to get mutex, not sending "
190 __FUNCTION__,
int(payload.size()), payload.data());
200 bool sync_on_timeout,
201 llvm::function_ref<
void(llvm::StringRef)> output_callback) {
202 auto result =
ReadPacket(response, timeout, sync_on_timeout);
208 output_callback(output);
209 result =
ReadPacket(response, timeout, sync_on_timeout);
217 std::chrono::seconds interrupt_timeout,
218 llvm::function_ref<
void(llvm::StringRef)> output_callback) {
219 Lock lock(*
this, interrupt_timeout);
223 "GDBRemoteClientBase::%s failed to get mutex, not sending "
225 __FUNCTION__,
int(payload.size()), payload.data());
231 return packet_result;
242 return packet_result;
244 const size_t max_response_retries = 3;
245 for (
size_t i = 0; i < max_response_retries; ++i) {
249 return packet_result;
252 return packet_result;
257 "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
258 int(payload.size()), payload.data(), response.
GetStringRef().data(),
259 (i == (max_response_retries - 1))
260 ?
"using invalid response and giving up"
261 :
"ignoring response and waiting for another");
263 return packet_result;
268 std::lock_guard<std::mutex> lock(
m_mutex);
279 ReadPacket(extra_stop_reply_packet, milliseconds(100),
false);
283 const uint8_t signo = response.
GetHexU8(UINT8_MAX);
307 : m_comm(comm), m_acquired(false) {
319 std::unique_lock<std::mutex> lock(m_comm.m_mutex);
320 m_comm.m_is_running =
false;
322 m_comm.m_cv.notify_all();
329 LLDB_LOGF(log,
"GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
330 __FUNCTION__, m_comm.m_continue_packet.c_str());
333 std::unique_lock<std::mutex> lock(m_comm.m_mutex);
334 m_comm.m_cv.wait(lock, [
this] {
return m_comm.m_async_count == 0; });
335 if (m_comm.m_should_stop) {
336 m_comm.m_should_stop =
false;
337 LLDB_LOGF(log,
"GDBRemoteClientBase::ContinueLock::%s() cancelled",
339 return LockResult::Cancelled;
341 if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
343 return LockResult::Failed;
346 m_comm.m_is_running =
true;
348 return LockResult::Success;
356 std::chrono::seconds interrupt_timeout)
357 : m_async_lock(comm.
m_async_mutex, std::defer_lock), m_comm(comm),
358 m_interrupt_timeout(interrupt_timeout), m_acquired(false),
359 m_did_interrupt(false) {
367 std::unique_lock<std::mutex> lock(m_comm.m_mutex);
368 if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0))
372 ++m_comm.m_async_count;
373 if (m_comm.m_is_running) {
374 if (m_comm.m_async_count == 1) {
377 const char ctrl_c =
'\x03';
379 size_t bytes_written = m_comm.Write(&ctrl_c, 1, status,
nullptr);
380 if (bytes_written == 0) {
381 --m_comm.m_async_count;
382 LLDB_LOGF(log,
"GDBRemoteClientBase::Lock::Lock failed to send "
386 m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout;
388 log->
PutCString(
"GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
390 m_comm.m_cv.wait(lock, [
this] {
return !m_comm.m_is_running; });
391 m_did_interrupt =
true;
400 std::unique_lock<std::mutex> lock(m_comm.m_mutex);
401 --m_comm.m_async_count;
403 m_comm.m_cv.notify_one();
static const seconds kWakeupInterval(5)
#define LLDB_LOGF(log,...)
An event broadcasting class.
void BroadcastEvent(lldb::EventSP &event_sp)
Broadcast an event which has no associated data.
void PutCString(const char *cstr)
int32_t GetSignalNumberFromName(const char *name) const
ContinueLock(GDBRemoteClientBase &comm)
Lock(GDBRemoteClientBase &comm, std::chrono::seconds interrupt_timeout=std::chrono::seconds(0))
bool DidInterrupt() const
void SyncWithContinueThread()
std::unique_lock< std::recursive_mutex > m_async_lock
std::recursive_mutex m_async_mutex
This handles the synchronization between individual async threads.
bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout)
std::string m_continue_packet
Packet with which to resume after an async interrupt.
PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response, std::chrono::seconds interrupt_timeout=std::chrono::seconds(0))
GDBRemoteClientBase(const char *comm_name)
uint32_t m_async_count
Number of threads interested in sending.
bool Interrupt(std::chrono::seconds interrupt_timeout)
PacketResult SendPacketAndReceiveResponseWithOutputSupport(llvm::StringRef payload, StringExtractorGDBRemote &response, std::chrono::seconds interrupt_timeout, llvm::function_ref< void(llvm::StringRef)> output_callback)
bool ShouldStop(const UnixSignals &signals, StringExtractorGDBRemote &response)
std::mutex m_mutex
Variables handling synchronization between the Continue thread and any other threads wishing to send ...
std::chrono::time_point< std::chrono::steady_clock > m_interrupt_endpoint
When was the interrupt packet sent.
PacketResult SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, StringExtractorGDBRemote &response)
@ eBroadcastBitRunPacketSent
PacketResult ReadPacketWithOutputSupport(StringExtractorGDBRemote &response, Timeout< std::micro > timeout, bool sync_on_timeout, llvm::function_ref< void(llvm::StringRef)> output_callback)
bool m_should_stop
Whether we should resume after a stop.
lldb::StateType SendContinuePacketAndWaitForResponse(ContinueDelegate &delegate, const UnixSignals &signals, llvm::StringRef payload, std::chrono::seconds interrupt_timeout, StringExtractorGDBRemote &response)
virtual void OnRunPacketSent(bool first)
PacketResult ReadPacket(StringExtractorGDBRemote &response, Timeout< std::micro > timeout, bool sync_on_timeout)
PacketResult SendPacketNoLock(llvm::StringRef payload)
std::chrono::seconds GetPacketTimeout() const
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
ConnectionStatus
Connection Status Types.
@ eConnectionStatusSuccess
Success.
StateType
Process and Thread States.
@ eStateStopped
Process or thread is stopped and can be examined.
@ eStateExited
Process has exited and can't be examined.
virtual ~ContinueDelegate()
virtual void HandleStopReply()=0
virtual void HandleAsyncMisc(llvm::StringRef data)=0
virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data)=0
Process asynchronously-received structured data.
virtual void HandleAsyncStdout(llvm::StringRef out)=0