1*0b57cec5SDimitry Andric //===-- GDBRemoteClientBase.h -----------------------------------*- 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 #ifndef liblldb_GDBRemoteClientBase_h_ 10*0b57cec5SDimitry Andric #define liblldb_GDBRemoteClientBase_h_ 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric #include "GDBRemoteCommunication.h" 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include <condition_variable> 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric namespace lldb_private { 17*0b57cec5SDimitry Andric namespace process_gdb_remote { 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric class GDBRemoteClientBase : public GDBRemoteCommunication { 20*0b57cec5SDimitry Andric public: 21*0b57cec5SDimitry Andric struct ContinueDelegate { 22*0b57cec5SDimitry Andric virtual ~ContinueDelegate(); 23*0b57cec5SDimitry Andric virtual void HandleAsyncStdout(llvm::StringRef out) = 0; 24*0b57cec5SDimitry Andric virtual void HandleAsyncMisc(llvm::StringRef data) = 0; 25*0b57cec5SDimitry Andric virtual void HandleStopReply() = 0; 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric // ========================================================================= 28*0b57cec5SDimitry Andric /// Process asynchronously-received structured data. 29*0b57cec5SDimitry Andric /// 30*0b57cec5SDimitry Andric /// \param[in] data 31*0b57cec5SDimitry Andric /// The complete data packet, expected to start with JSON-async. 32*0b57cec5SDimitry Andric // ========================================================================= 33*0b57cec5SDimitry Andric virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; 34*0b57cec5SDimitry Andric }; 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric GDBRemoteClientBase(const char *comm_name, const char *listener_name); 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric bool SendAsyncSignal(int signo); 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric bool Interrupt(); 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric lldb::StateType SendContinuePacketAndWaitForResponse( 43*0b57cec5SDimitry Andric ContinueDelegate &delegate, const UnixSignals &signals, 44*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response); 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, 47*0b57cec5SDimitry Andric StringExtractorGDBRemote &response, 48*0b57cec5SDimitry Andric bool send_async); 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric PacketResult SendPacketAndReceiveResponseWithOutputSupport( 51*0b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 52*0b57cec5SDimitry Andric bool send_async, 53*0b57cec5SDimitry Andric llvm::function_ref<void(llvm::StringRef)> output_callback); 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric bool SendvContPacket(llvm::StringRef payload, 56*0b57cec5SDimitry Andric StringExtractorGDBRemote &response); 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric class Lock { 59*0b57cec5SDimitry Andric public: 60*0b57cec5SDimitry Andric Lock(GDBRemoteClientBase &comm, bool interrupt); 61*0b57cec5SDimitry Andric ~Lock(); 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric // Whether we had to interrupt the continue thread to acquire the 66*0b57cec5SDimitry Andric // connection. 67*0b57cec5SDimitry Andric bool DidInterrupt() const { return m_did_interrupt; } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric private: 70*0b57cec5SDimitry Andric std::unique_lock<std::recursive_mutex> m_async_lock; 71*0b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 72*0b57cec5SDimitry Andric bool m_acquired; 73*0b57cec5SDimitry Andric bool m_did_interrupt; 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void SyncWithContinueThread(bool interrupt); 76*0b57cec5SDimitry Andric }; 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric protected: 79*0b57cec5SDimitry Andric PacketResult 80*0b57cec5SDimitry Andric SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, 81*0b57cec5SDimitry Andric StringExtractorGDBRemote &response); 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric virtual void OnRunPacketSent(bool first); 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric private: 86*0b57cec5SDimitry Andric // Variables handling synchronization between the Continue thread and any 87*0b57cec5SDimitry Andric // other threads 88*0b57cec5SDimitry Andric // wishing to send packets over the connection. Either the continue thread has 89*0b57cec5SDimitry Andric // control over 90*0b57cec5SDimitry Andric // the connection (m_is_running == true) or the connection is free for an 91*0b57cec5SDimitry Andric // arbitrary number of 92*0b57cec5SDimitry Andric // other senders to take which indicate their interest by incrementing 93*0b57cec5SDimitry Andric // m_async_count. 94*0b57cec5SDimitry Andric // Semantics of individual states: 95*0b57cec5SDimitry Andric // - m_continue_packet == false, m_async_count == 0: connection is free 96*0b57cec5SDimitry Andric // - m_continue_packet == true, m_async_count == 0: only continue thread is 97*0b57cec5SDimitry Andric // present 98*0b57cec5SDimitry Andric // - m_continue_packet == true, m_async_count > 0: continue thread has 99*0b57cec5SDimitry Andric // control, async threads 100*0b57cec5SDimitry Andric // should interrupt it and wait for it to set m_continue_packet to false 101*0b57cec5SDimitry Andric // - m_continue_packet == false, m_async_count > 0: async threads have 102*0b57cec5SDimitry Andric // control, continue 103*0b57cec5SDimitry Andric // thread needs to wait for them to finish (m_async_count goes down to 0). 104*0b57cec5SDimitry Andric std::mutex m_mutex; 105*0b57cec5SDimitry Andric std::condition_variable m_cv; 106*0b57cec5SDimitry Andric // Packet with which to resume after an async interrupt. Can be changed by an 107*0b57cec5SDimitry Andric // async thread 108*0b57cec5SDimitry Andric // e.g. to inject a signal. 109*0b57cec5SDimitry Andric std::string m_continue_packet; 110*0b57cec5SDimitry Andric // When was the interrupt packet sent. Used to make sure we time out if the 111*0b57cec5SDimitry Andric // stub does not 112*0b57cec5SDimitry Andric // respond to interrupt requests. 113*0b57cec5SDimitry Andric std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time; 114*0b57cec5SDimitry Andric uint32_t m_async_count; 115*0b57cec5SDimitry Andric bool m_is_running; 116*0b57cec5SDimitry Andric bool m_should_stop; // Whether we should resume after a stop. 117*0b57cec5SDimitry Andric // end of continue thread synchronization block 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric // This handles the synchronization between individual async threads. For now 120*0b57cec5SDimitry Andric // they just use a 121*0b57cec5SDimitry Andric // simple mutex. 122*0b57cec5SDimitry Andric std::recursive_mutex m_async_mutex; 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric bool ShouldStop(const UnixSignals &signals, 125*0b57cec5SDimitry Andric StringExtractorGDBRemote &response); 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric class ContinueLock { 128*0b57cec5SDimitry Andric public: 129*0b57cec5SDimitry Andric enum class LockResult { Success, Cancelled, Failed }; 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric explicit ContinueLock(GDBRemoteClientBase &comm); 132*0b57cec5SDimitry Andric ~ContinueLock(); 133*0b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric LockResult lock(); 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric void unlock(); 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric private: 140*0b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 141*0b57cec5SDimitry Andric bool m_acquired; 142*0b57cec5SDimitry Andric }; 143*0b57cec5SDimitry Andric }; 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric } // namespace process_gdb_remote 146*0b57cec5SDimitry Andric } // namespace lldb_private 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric #endif // liblldb_GDBRemoteCommunicationClient_h_ 149