1*0b57cec5SDimitry Andric //===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "GDBRemoteClientBase.h" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "lldb/Target/UnixSignals.h" 14*0b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h" 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "ProcessGDBRemoteLog.h" 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric using namespace lldb; 19*0b57cec5SDimitry Andric using namespace lldb_private; 20*0b57cec5SDimitry Andric using namespace lldb_private::process_gdb_remote; 21*0b57cec5SDimitry Andric using namespace std::chrono; 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric static const seconds kInterruptTimeout(5); 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric ///////////////////////// 26*0b57cec5SDimitry Andric // GDBRemoteClientBase // 27*0b57cec5SDimitry Andric ///////////////////////// 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default; 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name, 32*0b57cec5SDimitry Andric const char *listener_name) 33*0b57cec5SDimitry Andric : GDBRemoteCommunication(comm_name, listener_name), m_async_count(0), 34*0b57cec5SDimitry Andric m_is_running(false), m_should_stop(false) {} 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( 37*0b57cec5SDimitry Andric ContinueDelegate &delegate, const UnixSignals &signals, 38*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response) { 39*0b57cec5SDimitry Andric Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); 40*0b57cec5SDimitry Andric response.Clear(); 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric { 43*0b57cec5SDimitry Andric std::lock_guard<std::mutex> lock(m_mutex); 44*0b57cec5SDimitry Andric m_continue_packet = payload; 45*0b57cec5SDimitry Andric m_should_stop = false; 46*0b57cec5SDimitry Andric } 47*0b57cec5SDimitry Andric ContinueLock cont_lock(*this); 48*0b57cec5SDimitry Andric if (!cont_lock) 49*0b57cec5SDimitry Andric return eStateInvalid; 50*0b57cec5SDimitry Andric OnRunPacketSent(true); 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric for (;;) { 53*0b57cec5SDimitry Andric PacketResult read_result = ReadPacket(response, kInterruptTimeout, false); 54*0b57cec5SDimitry Andric switch (read_result) { 55*0b57cec5SDimitry Andric case PacketResult::ErrorReplyTimeout: { 56*0b57cec5SDimitry Andric std::lock_guard<std::mutex> lock(m_mutex); 57*0b57cec5SDimitry Andric if (m_async_count == 0) 58*0b57cec5SDimitry Andric continue; 59*0b57cec5SDimitry Andric if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout) 60*0b57cec5SDimitry Andric return eStateInvalid; 61*0b57cec5SDimitry Andric break; 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric case PacketResult::Success: 64*0b57cec5SDimitry Andric break; 65*0b57cec5SDimitry Andric default: 66*0b57cec5SDimitry Andric if (log) 67*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false", 68*0b57cec5SDimitry Andric __FUNCTION__); 69*0b57cec5SDimitry Andric return eStateInvalid; 70*0b57cec5SDimitry Andric } 71*0b57cec5SDimitry Andric if (response.Empty()) 72*0b57cec5SDimitry Andric return eStateInvalid; 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric const char stop_type = response.GetChar(); 75*0b57cec5SDimitry Andric if (log) 76*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__, 77*0b57cec5SDimitry Andric response.GetStringRef().c_str()); 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric switch (stop_type) { 80*0b57cec5SDimitry Andric case 'W': 81*0b57cec5SDimitry Andric case 'X': 82*0b57cec5SDimitry Andric return eStateExited; 83*0b57cec5SDimitry Andric case 'E': 84*0b57cec5SDimitry Andric // ERROR 85*0b57cec5SDimitry Andric return eStateInvalid; 86*0b57cec5SDimitry Andric default: 87*0b57cec5SDimitry Andric if (log) 88*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::%s () unrecognized async packet", 89*0b57cec5SDimitry Andric __FUNCTION__); 90*0b57cec5SDimitry Andric return eStateInvalid; 91*0b57cec5SDimitry Andric case 'O': { 92*0b57cec5SDimitry Andric std::string inferior_stdout; 93*0b57cec5SDimitry Andric response.GetHexByteString(inferior_stdout); 94*0b57cec5SDimitry Andric delegate.HandleAsyncStdout(inferior_stdout); 95*0b57cec5SDimitry Andric break; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric case 'A': 98*0b57cec5SDimitry Andric delegate.HandleAsyncMisc( 99*0b57cec5SDimitry Andric llvm::StringRef(response.GetStringRef()).substr(1)); 100*0b57cec5SDimitry Andric break; 101*0b57cec5SDimitry Andric case 'J': 102*0b57cec5SDimitry Andric delegate.HandleAsyncStructuredDataPacket(response.GetStringRef()); 103*0b57cec5SDimitry Andric break; 104*0b57cec5SDimitry Andric case 'T': 105*0b57cec5SDimitry Andric case 'S': 106*0b57cec5SDimitry Andric // Do this with the continue lock held. 107*0b57cec5SDimitry Andric const bool should_stop = ShouldStop(signals, response); 108*0b57cec5SDimitry Andric response.SetFilePos(0); 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric // The packet we should resume with. In the future we should check our 111*0b57cec5SDimitry Andric // thread list and "do the right thing" for new threads that show up 112*0b57cec5SDimitry Andric // while we stop and run async packets. Setting the packet to 'c' to 113*0b57cec5SDimitry Andric // continue all threads is the right thing to do 99.99% of the time 114*0b57cec5SDimitry Andric // because if a thread was single stepping, and we sent an interrupt, we 115*0b57cec5SDimitry Andric // will notice above that we didn't stop due to an interrupt but stopped 116*0b57cec5SDimitry Andric // due to stepping and we would _not_ continue. This packet may get 117*0b57cec5SDimitry Andric // modified by the async actions (e.g. to send a signal). 118*0b57cec5SDimitry Andric m_continue_packet = 'c'; 119*0b57cec5SDimitry Andric cont_lock.unlock(); 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric delegate.HandleStopReply(); 122*0b57cec5SDimitry Andric if (should_stop) 123*0b57cec5SDimitry Andric return eStateStopped; 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric switch (cont_lock.lock()) { 126*0b57cec5SDimitry Andric case ContinueLock::LockResult::Success: 127*0b57cec5SDimitry Andric break; 128*0b57cec5SDimitry Andric case ContinueLock::LockResult::Failed: 129*0b57cec5SDimitry Andric return eStateInvalid; 130*0b57cec5SDimitry Andric case ContinueLock::LockResult::Cancelled: 131*0b57cec5SDimitry Andric return eStateStopped; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric OnRunPacketSent(false); 134*0b57cec5SDimitry Andric break; 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric } 137*0b57cec5SDimitry Andric } 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric bool GDBRemoteClientBase::SendAsyncSignal(int signo) { 140*0b57cec5SDimitry Andric Lock lock(*this, true); 141*0b57cec5SDimitry Andric if (!lock || !lock.DidInterrupt()) 142*0b57cec5SDimitry Andric return false; 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric m_continue_packet = 'C'; 145*0b57cec5SDimitry Andric m_continue_packet += llvm::hexdigit((signo / 16) % 16); 146*0b57cec5SDimitry Andric m_continue_packet += llvm::hexdigit(signo % 16); 147*0b57cec5SDimitry Andric return true; 148*0b57cec5SDimitry Andric } 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric bool GDBRemoteClientBase::Interrupt() { 151*0b57cec5SDimitry Andric Lock lock(*this, true); 152*0b57cec5SDimitry Andric if (!lock.DidInterrupt()) 153*0b57cec5SDimitry Andric return false; 154*0b57cec5SDimitry Andric m_should_stop = true; 155*0b57cec5SDimitry Andric return true; 156*0b57cec5SDimitry Andric } 157*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult 158*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponse( 159*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 160*0b57cec5SDimitry Andric bool send_async) { 161*0b57cec5SDimitry Andric Lock lock(*this, send_async); 162*0b57cec5SDimitry Andric if (!lock) { 163*0b57cec5SDimitry Andric if (Log *log = 164*0b57cec5SDimitry Andric ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) 165*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " 166*0b57cec5SDimitry Andric "packet '%.*s' (send_async=%d)", 167*0b57cec5SDimitry Andric __FUNCTION__, int(payload.size()), payload.data(), 168*0b57cec5SDimitry Andric send_async); 169*0b57cec5SDimitry Andric return PacketResult::ErrorSendFailed; 170*0b57cec5SDimitry Andric } 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric return SendPacketAndWaitForResponseNoLock(payload, response); 173*0b57cec5SDimitry Andric } 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult 176*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport( 177*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 178*0b57cec5SDimitry Andric bool send_async, 179*0b57cec5SDimitry Andric llvm::function_ref<void(llvm::StringRef)> output_callback) { 180*0b57cec5SDimitry Andric Lock lock(*this, send_async); 181*0b57cec5SDimitry Andric if (!lock) { 182*0b57cec5SDimitry Andric if (Log *log = 183*0b57cec5SDimitry Andric ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) 184*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending " 185*0b57cec5SDimitry Andric "packet '%.*s' (send_async=%d)", 186*0b57cec5SDimitry Andric __FUNCTION__, int(payload.size()), payload.data(), 187*0b57cec5SDimitry Andric send_async); 188*0b57cec5SDimitry Andric return PacketResult::ErrorSendFailed; 189*0b57cec5SDimitry Andric } 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric PacketResult packet_result = SendPacketNoLock(payload); 192*0b57cec5SDimitry Andric if (packet_result != PacketResult::Success) 193*0b57cec5SDimitry Andric return packet_result; 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric return ReadPacketWithOutputSupport(response, GetPacketTimeout(), true, 196*0b57cec5SDimitry Andric output_callback); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric GDBRemoteCommunication::PacketResult 200*0b57cec5SDimitry Andric GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( 201*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response) { 202*0b57cec5SDimitry Andric PacketResult packet_result = SendPacketNoLock(payload); 203*0b57cec5SDimitry Andric if (packet_result != PacketResult::Success) 204*0b57cec5SDimitry Andric return packet_result; 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric const size_t max_response_retries = 3; 207*0b57cec5SDimitry Andric for (size_t i = 0; i < max_response_retries; ++i) { 208*0b57cec5SDimitry Andric packet_result = ReadPacket(response, GetPacketTimeout(), true); 209*0b57cec5SDimitry Andric // Make sure we received a response 210*0b57cec5SDimitry Andric if (packet_result != PacketResult::Success) 211*0b57cec5SDimitry Andric return packet_result; 212*0b57cec5SDimitry Andric // Make sure our response is valid for the payload that was sent 213*0b57cec5SDimitry Andric if (response.ValidateResponse()) 214*0b57cec5SDimitry Andric return packet_result; 215*0b57cec5SDimitry Andric // Response says it wasn't valid 216*0b57cec5SDimitry Andric Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS); 217*0b57cec5SDimitry Andric if (log) 218*0b57cec5SDimitry Andric log->Printf( 219*0b57cec5SDimitry Andric "error: packet with payload \"%.*s\" got invalid response \"%s\": %s", 220*0b57cec5SDimitry Andric int(payload.size()), payload.data(), response.GetStringRef().c_str(), 221*0b57cec5SDimitry Andric (i == (max_response_retries - 1)) 222*0b57cec5SDimitry Andric ? "using invalid response and giving up" 223*0b57cec5SDimitry Andric : "ignoring response and waiting for another"); 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric return packet_result; 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload, 229*0b57cec5SDimitry Andric StringExtractorGDBRemote &response) { 230*0b57cec5SDimitry Andric Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); 231*0b57cec5SDimitry Andric if (log) 232*0b57cec5SDimitry Andric log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric // we want to lock down packet sending while we continue 235*0b57cec5SDimitry Andric Lock lock(*this, true); 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric if (log) 238*0b57cec5SDimitry Andric log->Printf( 239*0b57cec5SDimitry Andric "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s", 240*0b57cec5SDimitry Andric __FUNCTION__, int(payload.size()), payload.data()); 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric if (SendPacketNoLock(payload) != PacketResult::Success) 243*0b57cec5SDimitry Andric return false; 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric OnRunPacketSent(true); 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric // wait for the response to the vCont 248*0b57cec5SDimitry Andric if (ReadPacket(response, llvm::None, false) == PacketResult::Success) { 249*0b57cec5SDimitry Andric if (response.IsOKResponse()) 250*0b57cec5SDimitry Andric return true; 251*0b57cec5SDimitry Andric } 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric return false; 254*0b57cec5SDimitry Andric } 255*0b57cec5SDimitry Andric bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals, 256*0b57cec5SDimitry Andric StringExtractorGDBRemote &response) { 257*0b57cec5SDimitry Andric std::lock_guard<std::mutex> lock(m_mutex); 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric if (m_async_count == 0) 260*0b57cec5SDimitry Andric return true; // We were not interrupted. The process stopped on its own. 261*0b57cec5SDimitry Andric 262*0b57cec5SDimitry Andric // Older debugserver stubs (before April 2016) can return two stop-reply 263*0b57cec5SDimitry Andric // packets in response to a ^C packet. Additionally, all debugservers still 264*0b57cec5SDimitry Andric // return two stop replies if the inferior stops due to some other reason 265*0b57cec5SDimitry Andric // before the remote stub manages to interrupt it. We need to wait for this 266*0b57cec5SDimitry Andric // additional packet to make sure the packet sequence does not get skewed. 267*0b57cec5SDimitry Andric StringExtractorGDBRemote extra_stop_reply_packet; 268*0b57cec5SDimitry Andric ReadPacket(extra_stop_reply_packet, milliseconds(100), false); 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric // Interrupting is typically done using SIGSTOP or SIGINT, so if the process 271*0b57cec5SDimitry Andric // stops with some other signal, we definitely want to stop. 272*0b57cec5SDimitry Andric const uint8_t signo = response.GetHexU8(UINT8_MAX); 273*0b57cec5SDimitry Andric if (signo != signals.GetSignalNumberFromName("SIGSTOP") && 274*0b57cec5SDimitry Andric signo != signals.GetSignalNumberFromName("SIGINT")) 275*0b57cec5SDimitry Andric return true; 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // We probably only stopped to perform some async processing, so continue 278*0b57cec5SDimitry Andric // after that is done. 279*0b57cec5SDimitry Andric // TODO: This is not 100% correct, as the process may have been stopped with 280*0b57cec5SDimitry Andric // SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will 281*0b57cec5SDimitry Andric // normally cause a stop, but if it's done concurrently with a async 282*0b57cec5SDimitry Andric // interrupt, that stop will get eaten (llvm.org/pr20231). 283*0b57cec5SDimitry Andric return false; 284*0b57cec5SDimitry Andric } 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric void GDBRemoteClientBase::OnRunPacketSent(bool first) { 287*0b57cec5SDimitry Andric if (first) 288*0b57cec5SDimitry Andric BroadcastEvent(eBroadcastBitRunPacketSent, nullptr); 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric /////////////////////////////////////// 292*0b57cec5SDimitry Andric // GDBRemoteClientBase::ContinueLock // 293*0b57cec5SDimitry Andric /////////////////////////////////////// 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm) 296*0b57cec5SDimitry Andric : m_comm(comm), m_acquired(false) { 297*0b57cec5SDimitry Andric lock(); 298*0b57cec5SDimitry Andric } 299*0b57cec5SDimitry Andric 300*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::~ContinueLock() { 301*0b57cec5SDimitry Andric if (m_acquired) 302*0b57cec5SDimitry Andric unlock(); 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric void GDBRemoteClientBase::ContinueLock::unlock() { 306*0b57cec5SDimitry Andric lldbassert(m_acquired); 307*0b57cec5SDimitry Andric { 308*0b57cec5SDimitry Andric std::unique_lock<std::mutex> lock(m_comm.m_mutex); 309*0b57cec5SDimitry Andric m_comm.m_is_running = false; 310*0b57cec5SDimitry Andric } 311*0b57cec5SDimitry Andric m_comm.m_cv.notify_all(); 312*0b57cec5SDimitry Andric m_acquired = false; 313*0b57cec5SDimitry Andric } 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::LockResult 316*0b57cec5SDimitry Andric GDBRemoteClientBase::ContinueLock::lock() { 317*0b57cec5SDimitry Andric Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS); 318*0b57cec5SDimitry Andric if (log) 319*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::ContinueLock::%s() resuming with %s", 320*0b57cec5SDimitry Andric __FUNCTION__, m_comm.m_continue_packet.c_str()); 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric lldbassert(!m_acquired); 323*0b57cec5SDimitry Andric std::unique_lock<std::mutex> lock(m_comm.m_mutex); 324*0b57cec5SDimitry Andric m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; }); 325*0b57cec5SDimitry Andric if (m_comm.m_should_stop) { 326*0b57cec5SDimitry Andric m_comm.m_should_stop = false; 327*0b57cec5SDimitry Andric if (log) 328*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::ContinueLock::%s() cancelled", 329*0b57cec5SDimitry Andric __FUNCTION__); 330*0b57cec5SDimitry Andric return LockResult::Cancelled; 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) != 333*0b57cec5SDimitry Andric PacketResult::Success) 334*0b57cec5SDimitry Andric return LockResult::Failed; 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric lldbassert(!m_comm.m_is_running); 337*0b57cec5SDimitry Andric m_comm.m_is_running = true; 338*0b57cec5SDimitry Andric m_acquired = true; 339*0b57cec5SDimitry Andric return LockResult::Success; 340*0b57cec5SDimitry Andric } 341*0b57cec5SDimitry Andric 342*0b57cec5SDimitry Andric /////////////////////////////// 343*0b57cec5SDimitry Andric // GDBRemoteClientBase::Lock // 344*0b57cec5SDimitry Andric /////////////////////////////// 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt) 347*0b57cec5SDimitry Andric : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), 348*0b57cec5SDimitry Andric m_acquired(false), m_did_interrupt(false) { 349*0b57cec5SDimitry Andric SyncWithContinueThread(interrupt); 350*0b57cec5SDimitry Andric if (m_acquired) 351*0b57cec5SDimitry Andric m_async_lock.lock(); 352*0b57cec5SDimitry Andric } 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { 355*0b57cec5SDimitry Andric Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); 356*0b57cec5SDimitry Andric std::unique_lock<std::mutex> lock(m_comm.m_mutex); 357*0b57cec5SDimitry Andric if (m_comm.m_is_running && !interrupt) 358*0b57cec5SDimitry Andric return; // We were asked to avoid interrupting the sender. Lock is not 359*0b57cec5SDimitry Andric // acquired. 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric ++m_comm.m_async_count; 362*0b57cec5SDimitry Andric if (m_comm.m_is_running) { 363*0b57cec5SDimitry Andric if (m_comm.m_async_count == 1) { 364*0b57cec5SDimitry Andric // The sender has sent the continue packet and we are the first async 365*0b57cec5SDimitry Andric // packet. Let's interrupt it. 366*0b57cec5SDimitry Andric const char ctrl_c = '\x03'; 367*0b57cec5SDimitry Andric ConnectionStatus status = eConnectionStatusSuccess; 368*0b57cec5SDimitry Andric size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, nullptr); 369*0b57cec5SDimitry Andric if (bytes_written == 0) { 370*0b57cec5SDimitry Andric --m_comm.m_async_count; 371*0b57cec5SDimitry Andric if (log) 372*0b57cec5SDimitry Andric log->Printf("GDBRemoteClientBase::Lock::Lock failed to send " 373*0b57cec5SDimitry Andric "interrupt packet"); 374*0b57cec5SDimitry Andric return; 375*0b57cec5SDimitry Andric } 376*0b57cec5SDimitry Andric if (log) 377*0b57cec5SDimitry Andric log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); 378*0b57cec5SDimitry Andric m_comm.m_interrupt_time = steady_clock::now(); 379*0b57cec5SDimitry Andric } 380*0b57cec5SDimitry Andric m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; }); 381*0b57cec5SDimitry Andric m_did_interrupt = true; 382*0b57cec5SDimitry Andric } 383*0b57cec5SDimitry Andric m_acquired = true; 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric GDBRemoteClientBase::Lock::~Lock() { 387*0b57cec5SDimitry Andric if (!m_acquired) 388*0b57cec5SDimitry Andric return; 389*0b57cec5SDimitry Andric { 390*0b57cec5SDimitry Andric std::unique_lock<std::mutex> lock(m_comm.m_mutex); 391*0b57cec5SDimitry Andric --m_comm.m_async_count; 392*0b57cec5SDimitry Andric } 393*0b57cec5SDimitry Andric m_comm.m_cv.notify_one(); 394*0b57cec5SDimitry Andric } 395