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 9dda28197Spatrick #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 10dda28197Spatrick #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 19*f6aab3d8Srobert class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster { 20061da546Spatrick public: 21*f6aab3d8Srobert enum { 22*f6aab3d8Srobert eBroadcastBitRunPacketSent = (1u << 0), 23*f6aab3d8Srobert }; 24*f6aab3d8Srobert 25061da546Spatrick struct ContinueDelegate { 26061da546Spatrick virtual ~ContinueDelegate(); 27061da546Spatrick virtual void HandleAsyncStdout(llvm::StringRef out) = 0; 28061da546Spatrick virtual void HandleAsyncMisc(llvm::StringRef data) = 0; 29061da546Spatrick virtual void HandleStopReply() = 0; 30061da546Spatrick 31061da546Spatrick /// Process asynchronously-received structured data. 32061da546Spatrick /// 33061da546Spatrick /// \param[in] data 34061da546Spatrick /// The complete data packet, expected to start with JSON-async. 35061da546Spatrick virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; 36061da546Spatrick }; 37061da546Spatrick 38*f6aab3d8Srobert GDBRemoteClientBase(const char *comm_name); 39061da546Spatrick 40be691f3bSpatrick bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout); 41061da546Spatrick 42be691f3bSpatrick bool Interrupt(std::chrono::seconds interrupt_timeout); 43061da546Spatrick 44061da546Spatrick lldb::StateType SendContinuePacketAndWaitForResponse( 45061da546Spatrick ContinueDelegate &delegate, const UnixSignals &signals, 46be691f3bSpatrick llvm::StringRef payload, std::chrono::seconds interrupt_timeout, 47be691f3bSpatrick StringExtractorGDBRemote &response); 48061da546Spatrick 49be691f3bSpatrick // If interrupt_timeout == 0 seconds, don't interrupt the target. 50be691f3bSpatrick // Only send the packet if the target is stopped. 51be691f3bSpatrick // If you want to use this mode, use the fact that the timeout is defaulted 52be691f3bSpatrick // so it's clear from the call-site that you are using no-interrupt. 53be691f3bSpatrick // If it is non-zero, interrupt the target if it is running, and 54be691f3bSpatrick // send the packet. 55be691f3bSpatrick // It the target doesn't respond within the given timeout, it returns 56be691f3bSpatrick // ErrorReplyTimeout. 57be691f3bSpatrick PacketResult SendPacketAndWaitForResponse( 58be691f3bSpatrick llvm::StringRef payload, StringExtractorGDBRemote &response, 59be691f3bSpatrick std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); 60061da546Spatrick 61*f6aab3d8Srobert PacketResult ReadPacketWithOutputSupport( 62*f6aab3d8Srobert StringExtractorGDBRemote &response, Timeout<std::micro> timeout, 63*f6aab3d8Srobert bool sync_on_timeout, 64*f6aab3d8Srobert llvm::function_ref<void(llvm::StringRef)> output_callback); 65*f6aab3d8Srobert 66061da546Spatrick PacketResult SendPacketAndReceiveResponseWithOutputSupport( 67061da546Spatrick llvm::StringRef payload, StringExtractorGDBRemote &response, 68be691f3bSpatrick std::chrono::seconds interrupt_timeout, 69061da546Spatrick llvm::function_ref<void(llvm::StringRef)> output_callback); 70061da546Spatrick 71061da546Spatrick class Lock { 72061da546Spatrick public: 73be691f3bSpatrick // If interrupt_timeout == 0 seconds, only take the lock if the target is 74be691f3bSpatrick // not running. If using this option, use the fact that the 75be691f3bSpatrick // interrupt_timeout is defaulted so it will be obvious at the call site 76be691f3bSpatrick // that you are choosing this mode. If it is non-zero, interrupt the target 77be691f3bSpatrick // if it is running, waiting for the given timeout for the interrupt to 78be691f3bSpatrick // succeed. 79be691f3bSpatrick Lock(GDBRemoteClientBase &comm, 80be691f3bSpatrick std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); 81061da546Spatrick ~Lock(); 82061da546Spatrick 83061da546Spatrick explicit operator bool() { return m_acquired; } 84061da546Spatrick 85061da546Spatrick // Whether we had to interrupt the continue thread to acquire the 86061da546Spatrick // connection. DidInterrupt()87061da546Spatrick bool DidInterrupt() const { return m_did_interrupt; } 88061da546Spatrick 89061da546Spatrick private: 90061da546Spatrick std::unique_lock<std::recursive_mutex> m_async_lock; 91061da546Spatrick GDBRemoteClientBase &m_comm; 92be691f3bSpatrick std::chrono::seconds m_interrupt_timeout; 93061da546Spatrick bool m_acquired; 94061da546Spatrick bool m_did_interrupt; 95061da546Spatrick 96be691f3bSpatrick void SyncWithContinueThread(); 97061da546Spatrick }; 98061da546Spatrick 99061da546Spatrick protected: 100061da546Spatrick PacketResult 101061da546Spatrick SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, 102061da546Spatrick StringExtractorGDBRemote &response); 103061da546Spatrick 104061da546Spatrick virtual void OnRunPacketSent(bool first); 105061da546Spatrick 106061da546Spatrick private: 107061da546Spatrick /// Variables handling synchronization between the Continue thread and any 108061da546Spatrick /// other threads wishing to send packets over the connection. Either the 109061da546Spatrick /// continue thread has control over the connection (m_is_running == true) or 110061da546Spatrick /// the connection is free for an arbitrary number of other senders to take 111061da546Spatrick /// which indicate their interest by incrementing m_async_count. 112061da546Spatrick /// 113061da546Spatrick /// Semantics of individual states: 114061da546Spatrick /// 115061da546Spatrick /// - m_continue_packet == false, m_async_count == 0: 116061da546Spatrick /// connection is free 117061da546Spatrick /// - m_continue_packet == true, m_async_count == 0: 118061da546Spatrick /// only continue thread is present 119061da546Spatrick /// - m_continue_packet == true, m_async_count > 0: 120061da546Spatrick /// continue thread has control, async threads should interrupt it and wait 121061da546Spatrick /// for it to set m_continue_packet to false 122061da546Spatrick /// - m_continue_packet == false, m_async_count > 0: 123061da546Spatrick /// async threads have control, continue thread needs to wait for them to 124061da546Spatrick /// finish (m_async_count goes down to 0). 125061da546Spatrick /// @{ 126061da546Spatrick std::mutex m_mutex; 127061da546Spatrick std::condition_variable m_cv; 128061da546Spatrick 129061da546Spatrick /// Packet with which to resume after an async interrupt. Can be changed by 130061da546Spatrick /// an async thread e.g. to inject a signal. 131061da546Spatrick std::string m_continue_packet; 132061da546Spatrick 133061da546Spatrick /// When was the interrupt packet sent. Used to make sure we time out if the 134061da546Spatrick /// stub does not respond to interrupt requests. 135be691f3bSpatrick std::chrono::time_point<std::chrono::steady_clock> m_interrupt_endpoint; 136061da546Spatrick 137061da546Spatrick /// Number of threads interested in sending. 138061da546Spatrick uint32_t m_async_count; 139061da546Spatrick 140061da546Spatrick /// Whether the continue thread has control. 141061da546Spatrick bool m_is_running; 142061da546Spatrick 143061da546Spatrick /// Whether we should resume after a stop. 144061da546Spatrick bool m_should_stop; 145061da546Spatrick /// @} 146061da546Spatrick 147061da546Spatrick /// This handles the synchronization between individual async threads. For 148061da546Spatrick /// now they just use a simple mutex. 149061da546Spatrick std::recursive_mutex m_async_mutex; 150061da546Spatrick 151061da546Spatrick bool ShouldStop(const UnixSignals &signals, 152061da546Spatrick StringExtractorGDBRemote &response); 153061da546Spatrick 154061da546Spatrick class ContinueLock { 155061da546Spatrick public: 156061da546Spatrick enum class LockResult { Success, Cancelled, Failed }; 157061da546Spatrick 158061da546Spatrick explicit ContinueLock(GDBRemoteClientBase &comm); 159061da546Spatrick ~ContinueLock(); 160061da546Spatrick explicit operator bool() { return m_acquired; } 161061da546Spatrick 162061da546Spatrick LockResult lock(); 163061da546Spatrick 164061da546Spatrick void unlock(); 165061da546Spatrick 166061da546Spatrick private: 167061da546Spatrick GDBRemoteClientBase &m_comm; 168061da546Spatrick bool m_acquired; 169061da546Spatrick }; 170061da546Spatrick }; 171061da546Spatrick 172061da546Spatrick } // namespace process_gdb_remote 173061da546Spatrick } // namespace lldb_private 174061da546Spatrick 175dda28197Spatrick #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 176