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