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