10b57cec5SDimitry Andric //===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef liblldb_GDBRemoteClientBase_h_ 100b57cec5SDimitry Andric #define liblldb_GDBRemoteClientBase_h_ 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "GDBRemoteCommunication.h" 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include <condition_variable> 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric namespace lldb_private { 170b57cec5SDimitry Andric namespace process_gdb_remote { 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric class GDBRemoteClientBase : public GDBRemoteCommunication { 200b57cec5SDimitry Andric public: 210b57cec5SDimitry Andric struct ContinueDelegate { 220b57cec5SDimitry Andric virtual ~ContinueDelegate(); 230b57cec5SDimitry Andric virtual void HandleAsyncStdout(llvm::StringRef out) = 0; 240b57cec5SDimitry Andric virtual void HandleAsyncMisc(llvm::StringRef data) = 0; 250b57cec5SDimitry Andric virtual void HandleStopReply() = 0; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric /// Process asynchronously-received structured data. 280b57cec5SDimitry Andric /// 290b57cec5SDimitry Andric /// \param[in] data 300b57cec5SDimitry Andric /// The complete data packet, expected to start with JSON-async. 310b57cec5SDimitry Andric virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; 320b57cec5SDimitry Andric }; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric GDBRemoteClientBase(const char *comm_name, const char *listener_name); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric bool SendAsyncSignal(int signo); 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric bool Interrupt(); 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric lldb::StateType SendContinuePacketAndWaitForResponse( 410b57cec5SDimitry Andric ContinueDelegate &delegate, const UnixSignals &signals, 420b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, 450b57cec5SDimitry Andric StringExtractorGDBRemote &response, 460b57cec5SDimitry Andric bool send_async); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric PacketResult SendPacketAndReceiveResponseWithOutputSupport( 490b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 500b57cec5SDimitry Andric bool send_async, 510b57cec5SDimitry Andric llvm::function_ref<void(llvm::StringRef)> output_callback); 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric bool SendvContPacket(llvm::StringRef payload, 540b57cec5SDimitry Andric StringExtractorGDBRemote &response); 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric class Lock { 570b57cec5SDimitry Andric public: 580b57cec5SDimitry Andric Lock(GDBRemoteClientBase &comm, bool interrupt); 590b57cec5SDimitry Andric ~Lock(); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric // Whether we had to interrupt the continue thread to acquire the 640b57cec5SDimitry Andric // connection. 650b57cec5SDimitry Andric bool DidInterrupt() const { return m_did_interrupt; } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric private: 680b57cec5SDimitry Andric std::unique_lock<std::recursive_mutex> m_async_lock; 690b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 700b57cec5SDimitry Andric bool m_acquired; 710b57cec5SDimitry Andric bool m_did_interrupt; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void SyncWithContinueThread(bool interrupt); 740b57cec5SDimitry Andric }; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric protected: 770b57cec5SDimitry Andric PacketResult 780b57cec5SDimitry Andric SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, 790b57cec5SDimitry Andric StringExtractorGDBRemote &response); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric virtual void OnRunPacketSent(bool first); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric private: 84*9dba64beSDimitry Andric /// Variables handling synchronization between the Continue thread and any 85*9dba64beSDimitry Andric /// other threads wishing to send packets over the connection. Either the 86*9dba64beSDimitry Andric /// continue thread has control over the connection (m_is_running == true) or 87*9dba64beSDimitry Andric /// the connection is free for an arbitrary number of other senders to take 88*9dba64beSDimitry Andric /// which indicate their interest by incrementing m_async_count. 89*9dba64beSDimitry Andric /// 90*9dba64beSDimitry Andric /// Semantics of individual states: 91*9dba64beSDimitry Andric /// 92*9dba64beSDimitry Andric /// - m_continue_packet == false, m_async_count == 0: 93*9dba64beSDimitry Andric /// connection is free 94*9dba64beSDimitry Andric /// - m_continue_packet == true, m_async_count == 0: 95*9dba64beSDimitry Andric /// only continue thread is present 96*9dba64beSDimitry Andric /// - m_continue_packet == true, m_async_count > 0: 97*9dba64beSDimitry Andric /// continue thread has control, async threads should interrupt it and wait 98*9dba64beSDimitry Andric /// for it to set m_continue_packet to false 99*9dba64beSDimitry Andric /// - m_continue_packet == false, m_async_count > 0: 100*9dba64beSDimitry Andric /// async threads have control, continue thread needs to wait for them to 101*9dba64beSDimitry Andric /// finish (m_async_count goes down to 0). 102*9dba64beSDimitry Andric /// @{ 1030b57cec5SDimitry Andric std::mutex m_mutex; 1040b57cec5SDimitry Andric std::condition_variable m_cv; 1050b57cec5SDimitry Andric 106*9dba64beSDimitry Andric /// Packet with which to resume after an async interrupt. Can be changed by 107*9dba64beSDimitry Andric /// an async thread e.g. to inject a signal. 108*9dba64beSDimitry Andric std::string m_continue_packet; 109*9dba64beSDimitry Andric 110*9dba64beSDimitry Andric /// When was the interrupt packet sent. Used to make sure we time out if the 111*9dba64beSDimitry Andric /// stub does not respond to interrupt requests. 112*9dba64beSDimitry Andric std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time; 113*9dba64beSDimitry Andric 114*9dba64beSDimitry Andric /// Number of threads interested in sending. 115*9dba64beSDimitry Andric uint32_t m_async_count; 116*9dba64beSDimitry Andric 117*9dba64beSDimitry Andric /// Whether the continue thread has control. 118*9dba64beSDimitry Andric bool m_is_running; 119*9dba64beSDimitry Andric 120*9dba64beSDimitry Andric /// Whether we should resume after a stop. 121*9dba64beSDimitry Andric bool m_should_stop; 122*9dba64beSDimitry Andric /// @} 123*9dba64beSDimitry Andric 124*9dba64beSDimitry Andric /// This handles the synchronization between individual async threads. For 125*9dba64beSDimitry Andric /// now they just use a simple mutex. 1260b57cec5SDimitry Andric std::recursive_mutex m_async_mutex; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric bool ShouldStop(const UnixSignals &signals, 1290b57cec5SDimitry Andric StringExtractorGDBRemote &response); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric class ContinueLock { 1320b57cec5SDimitry Andric public: 1330b57cec5SDimitry Andric enum class LockResult { Success, Cancelled, Failed }; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric explicit ContinueLock(GDBRemoteClientBase &comm); 1360b57cec5SDimitry Andric ~ContinueLock(); 1370b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric LockResult lock(); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric void unlock(); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric private: 1440b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 1450b57cec5SDimitry Andric bool m_acquired; 1460b57cec5SDimitry Andric }; 1470b57cec5SDimitry Andric }; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric } // namespace process_gdb_remote 1500b57cec5SDimitry Andric } // namespace lldb_private 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric #endif // liblldb_GDBRemoteCommunicationClient_h_ 153