1061da546Spatrick //===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9*dda28197Spatrick #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 10*dda28197Spatrick #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 11061da546Spatrick 12061da546Spatrick #include "GDBRemoteCommunication.h" 13061da546Spatrick 14061da546Spatrick #include <condition_variable> 15061da546Spatrick 16061da546Spatrick namespace lldb_private { 17061da546Spatrick namespace process_gdb_remote { 18061da546Spatrick 19061da546Spatrick class GDBRemoteClientBase : public GDBRemoteCommunication { 20061da546Spatrick public: 21061da546Spatrick struct ContinueDelegate { 22061da546Spatrick virtual ~ContinueDelegate(); 23061da546Spatrick virtual void HandleAsyncStdout(llvm::StringRef out) = 0; 24061da546Spatrick virtual void HandleAsyncMisc(llvm::StringRef data) = 0; 25061da546Spatrick virtual void HandleStopReply() = 0; 26061da546Spatrick 27061da546Spatrick /// Process asynchronously-received structured data. 28061da546Spatrick /// 29061da546Spatrick /// \param[in] data 30061da546Spatrick /// The complete data packet, expected to start with JSON-async. 31061da546Spatrick virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; 32061da546Spatrick }; 33061da546Spatrick 34061da546Spatrick GDBRemoteClientBase(const char *comm_name, const char *listener_name); 35061da546Spatrick 36061da546Spatrick bool SendAsyncSignal(int signo); 37061da546Spatrick 38061da546Spatrick bool Interrupt(); 39061da546Spatrick 40061da546Spatrick lldb::StateType SendContinuePacketAndWaitForResponse( 41061da546Spatrick ContinueDelegate &delegate, const UnixSignals &signals, 42061da546Spatrick llvm::StringRef payload, StringExtractorGDBRemote &response); 43061da546Spatrick 44061da546Spatrick PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, 45061da546Spatrick StringExtractorGDBRemote &response, 46061da546Spatrick bool send_async); 47061da546Spatrick 48061da546Spatrick PacketResult SendPacketAndReceiveResponseWithOutputSupport( 49061da546Spatrick llvm::StringRef payload, StringExtractorGDBRemote &response, 50061da546Spatrick bool send_async, 51061da546Spatrick llvm::function_ref<void(llvm::StringRef)> output_callback); 52061da546Spatrick 53061da546Spatrick bool SendvContPacket(llvm::StringRef payload, 54061da546Spatrick StringExtractorGDBRemote &response); 55061da546Spatrick 56061da546Spatrick class Lock { 57061da546Spatrick public: 58061da546Spatrick Lock(GDBRemoteClientBase &comm, bool interrupt); 59061da546Spatrick ~Lock(); 60061da546Spatrick 61061da546Spatrick explicit operator bool() { return m_acquired; } 62061da546Spatrick 63061da546Spatrick // Whether we had to interrupt the continue thread to acquire the 64061da546Spatrick // connection. 65061da546Spatrick bool DidInterrupt() const { return m_did_interrupt; } 66061da546Spatrick 67061da546Spatrick private: 68061da546Spatrick std::unique_lock<std::recursive_mutex> m_async_lock; 69061da546Spatrick GDBRemoteClientBase &m_comm; 70061da546Spatrick bool m_acquired; 71061da546Spatrick bool m_did_interrupt; 72061da546Spatrick 73061da546Spatrick void SyncWithContinueThread(bool interrupt); 74061da546Spatrick }; 75061da546Spatrick 76061da546Spatrick protected: 77061da546Spatrick PacketResult 78061da546Spatrick SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, 79061da546Spatrick StringExtractorGDBRemote &response); 80061da546Spatrick 81061da546Spatrick virtual void OnRunPacketSent(bool first); 82061da546Spatrick 83061da546Spatrick private: 84061da546Spatrick /// Variables handling synchronization between the Continue thread and any 85061da546Spatrick /// other threads wishing to send packets over the connection. Either the 86061da546Spatrick /// continue thread has control over the connection (m_is_running == true) or 87061da546Spatrick /// the connection is free for an arbitrary number of other senders to take 88061da546Spatrick /// which indicate their interest by incrementing m_async_count. 89061da546Spatrick /// 90061da546Spatrick /// Semantics of individual states: 91061da546Spatrick /// 92061da546Spatrick /// - m_continue_packet == false, m_async_count == 0: 93061da546Spatrick /// connection is free 94061da546Spatrick /// - m_continue_packet == true, m_async_count == 0: 95061da546Spatrick /// only continue thread is present 96061da546Spatrick /// - m_continue_packet == true, m_async_count > 0: 97061da546Spatrick /// continue thread has control, async threads should interrupt it and wait 98061da546Spatrick /// for it to set m_continue_packet to false 99061da546Spatrick /// - m_continue_packet == false, m_async_count > 0: 100061da546Spatrick /// async threads have control, continue thread needs to wait for them to 101061da546Spatrick /// finish (m_async_count goes down to 0). 102061da546Spatrick /// @{ 103061da546Spatrick std::mutex m_mutex; 104061da546Spatrick std::condition_variable m_cv; 105061da546Spatrick 106061da546Spatrick /// Packet with which to resume after an async interrupt. Can be changed by 107061da546Spatrick /// an async thread e.g. to inject a signal. 108061da546Spatrick std::string m_continue_packet; 109061da546Spatrick 110061da546Spatrick /// When was the interrupt packet sent. Used to make sure we time out if the 111061da546Spatrick /// stub does not respond to interrupt requests. 112061da546Spatrick std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time; 113061da546Spatrick 114061da546Spatrick /// Number of threads interested in sending. 115061da546Spatrick uint32_t m_async_count; 116061da546Spatrick 117061da546Spatrick /// Whether the continue thread has control. 118061da546Spatrick bool m_is_running; 119061da546Spatrick 120061da546Spatrick /// Whether we should resume after a stop. 121061da546Spatrick bool m_should_stop; 122061da546Spatrick /// @} 123061da546Spatrick 124061da546Spatrick /// This handles the synchronization between individual async threads. For 125061da546Spatrick /// now they just use a simple mutex. 126061da546Spatrick std::recursive_mutex m_async_mutex; 127061da546Spatrick 128061da546Spatrick bool ShouldStop(const UnixSignals &signals, 129061da546Spatrick StringExtractorGDBRemote &response); 130061da546Spatrick 131061da546Spatrick class ContinueLock { 132061da546Spatrick public: 133061da546Spatrick enum class LockResult { Success, Cancelled, Failed }; 134061da546Spatrick 135061da546Spatrick explicit ContinueLock(GDBRemoteClientBase &comm); 136061da546Spatrick ~ContinueLock(); 137061da546Spatrick explicit operator bool() { return m_acquired; } 138061da546Spatrick 139061da546Spatrick LockResult lock(); 140061da546Spatrick 141061da546Spatrick void unlock(); 142061da546Spatrick 143061da546Spatrick private: 144061da546Spatrick GDBRemoteClientBase &m_comm; 145061da546Spatrick bool m_acquired; 146061da546Spatrick }; 147061da546Spatrick }; 148061da546Spatrick 149061da546Spatrick } // namespace process_gdb_remote 150061da546Spatrick } // namespace lldb_private 151061da546Spatrick 152*dda28197Spatrick #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 153