11#include "llvm/ADT/StringExtras.h"
12#include "llvm/Support/ErrorExtras.h"
22using namespace std::chrono;
41 llvm::StringRef payload, std::chrono::seconds interrupt_timeout,
47 std::lock_guard<std::mutex> lock(
m_mutex);
60 std::chrono::seconds computed_timeout = std::min(interrupt_timeout,
67 switch (read_result) {
69 std::lock_guard<std::mutex> lock(
m_mutex);
73 auto cur_time = steady_clock::now();
83 std::chrono::duration_cast<std::chrono::seconds>(new_wait));
91 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () ReadPacket(...) => false",
98 const char stop_type = response.
GetChar();
99 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
110 LLDB_LOGF(log,
"GDBRemoteClientBase::%s () unrecognized async packet",
114 std::string inferior_stdout;
129 const bool should_stop =
ShouldStop(signals, response);
147 switch (cont_lock.
lock()) {
162 int signo, std::chrono::seconds interrupt_timeout) {
163 Lock lock(*
this, interrupt_timeout);
174 Lock lock(*
this, interrupt_timeout);
184 std::chrono::seconds interrupt_timeout,
bool sync_on_timeout) {
185 Lock lock(*
this, interrupt_timeout);
189 "GDBRemoteClientBase::%s failed to get mutex, not sending "
191 __FUNCTION__,
int(payload.size()), payload.data());
198llvm::Expected<StringExtractorGDBRemote>
200 llvm::StringRef payload, std::chrono::seconds interrupt_timeout) {
205 return llvm::createStringErrorV(
"failed to send packet: '{0}'", payload);
208 return llvm::createStringErrorV(
"unsupported response: '{0}'",
211 return std::move(response);
217 bool sync_on_timeout,
218 llvm::function_ref<
void(llvm::StringRef)> output_callback) {
219 auto result =
ReadPacket(response, timeout, sync_on_timeout);
225 output_callback(output);
226 result =
ReadPacket(response, timeout, sync_on_timeout);
234 std::chrono::seconds interrupt_timeout,
235 llvm::function_ref<
void(llvm::StringRef)> output_callback) {
236 Lock lock(*
this, interrupt_timeout);
240 "GDBRemoteClientBase::%s failed to get mutex, not sending "
242 __FUNCTION__,
int(payload.size()), payload.data());
248 return packet_result;
257 bool sync_on_timeout) {
260 return packet_result;
262 const size_t max_response_retries = 3;
263 for (
size_t i = 0; i < max_response_retries; ++i) {
267 return packet_result;
270 return packet_result;
275 "error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
276 int(payload.size()), payload.data(), response.
GetStringRef().data(),
277 (i == (max_response_retries - 1))
278 ?
"using invalid response and giving up"
279 :
"ignoring response and waiting for another");
281 return packet_result;
286 std::lock_guard<std::mutex> lock(
m_mutex);
297 ReadPacket(extra_stop_reply_packet, milliseconds(100),
false);
301 const uint8_t signo = response.
GetHexU8(UINT8_MAX);
337 std::unique_lock<std::mutex>
lock(
m_comm.m_mutex);
338 m_comm.m_is_running =
false;
347 LLDB_LOGF(log,
"GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
348 __FUNCTION__,
m_comm.m_continue_packet.c_str());
351 std::unique_lock<std::mutex>
lock(
m_comm.m_mutex);
353 if (
m_comm.m_should_stop) {
354 m_comm.m_should_stop =
false;
355 LLDB_LOGF(log,
"GDBRemoteClientBase::ContinueLock::%s() cancelled",
359 if (
m_comm.SendPacketNoLock(
m_comm.m_continue_packet) !=
364 m_comm.m_is_running =
true;
374 std::chrono::seconds interrupt_timeout)
385 std::unique_lock<std::mutex> lock(
m_comm.m_mutex);
391 if (
m_comm.m_is_running) {
392 if (
m_comm.m_async_count == 1) {
395 const char ctrl_c =
'\x03';
397 size_t bytes_written =
m_comm.Write(&ctrl_c, 1, status,
nullptr);
398 if (bytes_written == 0) {
400 LLDB_LOGF(log,
"GDBRemoteClientBase::Lock::Lock failed to send "
406 log->
PutCString(
"GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
408 m_comm.m_cv.wait(lock, [
this] {
return !
m_comm.m_is_running; });
418 std::unique_lock<std::mutex> lock(
m_comm.m_mutex);
static const seconds kWakeupInterval(5)
#define LLDB_LOGF(log,...)
Broadcaster(lldb::BroadcasterManagerSP manager_sp, std::string name)
Construct with a broadcaster with a name.
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
GDBRemoteClientBase & m_comm
ContinueLock(GDBRemoteClientBase &comm)
Lock(GDBRemoteClientBase &comm, std::chrono::seconds interrupt_timeout=std::chrono::seconds(0))
GDBRemoteClientBase & m_comm
bool DidInterrupt() const
void SyncWithContinueThread()
std::unique_lock< std::recursive_mutex > m_async_lock
std::chrono::seconds m_interrupt_timeout
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.
GDBRemoteClientBase(const char *comm_name)
uint32_t m_async_count
Number of threads interested in sending.
bool Interrupt(std::chrono::seconds interrupt_timeout)
llvm::Expected< StringExtractorGDBRemote > SendPacketAndExpectResponse(llvm::StringRef payload, std::chrono::seconds interrupt_timeout=std::chrono::seconds(0))
Wrapper around SendPacketAndWaitForResponse that returns an Expected.
@ eBroadcastBitRunPacketSent
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)
PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response, std::chrono::seconds interrupt_timeout=std::chrono::seconds(0), bool sync_on_timeout=true)
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.
bool m_is_running
Whether the continue thread has control.
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.
PacketResult SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, StringExtractorGDBRemote &response, bool sync_on_timeout=true)
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