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 95ffd83dbSDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 105ffd83dbSDimitry Andric #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_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 19*bdd1243dSDimitry Andric class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster { 200b57cec5SDimitry Andric public: 21*bdd1243dSDimitry Andric enum { 22*bdd1243dSDimitry Andric eBroadcastBitRunPacketSent = (1u << 0), 23*bdd1243dSDimitry Andric }; 24*bdd1243dSDimitry Andric 250b57cec5SDimitry Andric struct ContinueDelegate { 260b57cec5SDimitry Andric virtual ~ContinueDelegate(); 270b57cec5SDimitry Andric virtual void HandleAsyncStdout(llvm::StringRef out) = 0; 280b57cec5SDimitry Andric virtual void HandleAsyncMisc(llvm::StringRef data) = 0; 290b57cec5SDimitry Andric virtual void HandleStopReply() = 0; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric /// Process asynchronously-received structured data. 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric /// \param[in] data 340b57cec5SDimitry Andric /// The complete data packet, expected to start with JSON-async. 350b57cec5SDimitry Andric virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0; 360b57cec5SDimitry Andric }; 370b57cec5SDimitry Andric 38*bdd1243dSDimitry Andric GDBRemoteClientBase(const char *comm_name); 390b57cec5SDimitry Andric 40fe6060f1SDimitry Andric bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout); 410b57cec5SDimitry Andric 42fe6060f1SDimitry Andric bool Interrupt(std::chrono::seconds interrupt_timeout); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric lldb::StateType SendContinuePacketAndWaitForResponse( 450b57cec5SDimitry Andric ContinueDelegate &delegate, const UnixSignals &signals, 46fe6060f1SDimitry Andric llvm::StringRef payload, std::chrono::seconds interrupt_timeout, 47fe6060f1SDimitry Andric StringExtractorGDBRemote &response); 480b57cec5SDimitry Andric 49fe6060f1SDimitry Andric // If interrupt_timeout == 0 seconds, don't interrupt the target. 50fe6060f1SDimitry Andric // Only send the packet if the target is stopped. 51fe6060f1SDimitry Andric // If you want to use this mode, use the fact that the timeout is defaulted 52fe6060f1SDimitry Andric // so it's clear from the call-site that you are using no-interrupt. 53fe6060f1SDimitry Andric // If it is non-zero, interrupt the target if it is running, and 54fe6060f1SDimitry Andric // send the packet. 55fe6060f1SDimitry Andric // It the target doesn't respond within the given timeout, it returns 56fe6060f1SDimitry Andric // ErrorReplyTimeout. 57fe6060f1SDimitry Andric PacketResult SendPacketAndWaitForResponse( 58fe6060f1SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 59fe6060f1SDimitry Andric std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); 600b57cec5SDimitry Andric 61*bdd1243dSDimitry Andric PacketResult ReadPacketWithOutputSupport( 62*bdd1243dSDimitry Andric StringExtractorGDBRemote &response, Timeout<std::micro> timeout, 63*bdd1243dSDimitry Andric bool sync_on_timeout, 64*bdd1243dSDimitry Andric llvm::function_ref<void(llvm::StringRef)> output_callback); 65*bdd1243dSDimitry Andric 660b57cec5SDimitry Andric PacketResult SendPacketAndReceiveResponseWithOutputSupport( 670b57cec5SDimitry Andric llvm::StringRef payload, StringExtractorGDBRemote &response, 68fe6060f1SDimitry Andric std::chrono::seconds interrupt_timeout, 690b57cec5SDimitry Andric llvm::function_ref<void(llvm::StringRef)> output_callback); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric class Lock { 720b57cec5SDimitry Andric public: 73fe6060f1SDimitry Andric // If interrupt_timeout == 0 seconds, only take the lock if the target is 74fe6060f1SDimitry Andric // not running. If using this option, use the fact that the 75fe6060f1SDimitry Andric // interrupt_timeout is defaulted so it will be obvious at the call site 76fe6060f1SDimitry Andric // that you are choosing this mode. If it is non-zero, interrupt the target 77fe6060f1SDimitry Andric // if it is running, waiting for the given timeout for the interrupt to 78fe6060f1SDimitry Andric // succeed. 79fe6060f1SDimitry Andric Lock(GDBRemoteClientBase &comm, 80fe6060f1SDimitry Andric std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); 810b57cec5SDimitry Andric ~Lock(); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // Whether we had to interrupt the continue thread to acquire the 860b57cec5SDimitry Andric // connection. DidInterrupt()870b57cec5SDimitry Andric bool DidInterrupt() const { return m_did_interrupt; } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric private: 900b57cec5SDimitry Andric std::unique_lock<std::recursive_mutex> m_async_lock; 910b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 92fe6060f1SDimitry Andric std::chrono::seconds m_interrupt_timeout; 930b57cec5SDimitry Andric bool m_acquired; 940b57cec5SDimitry Andric bool m_did_interrupt; 950b57cec5SDimitry Andric 96fe6060f1SDimitry Andric void SyncWithContinueThread(); 970b57cec5SDimitry Andric }; 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric protected: 1000b57cec5SDimitry Andric PacketResult 1010b57cec5SDimitry Andric SendPacketAndWaitForResponseNoLock(llvm::StringRef payload, 1020b57cec5SDimitry Andric StringExtractorGDBRemote &response); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric virtual void OnRunPacketSent(bool first); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric private: 1079dba64beSDimitry Andric /// Variables handling synchronization between the Continue thread and any 1089dba64beSDimitry Andric /// other threads wishing to send packets over the connection. Either the 1099dba64beSDimitry Andric /// continue thread has control over the connection (m_is_running == true) or 1109dba64beSDimitry Andric /// the connection is free for an arbitrary number of other senders to take 1119dba64beSDimitry Andric /// which indicate their interest by incrementing m_async_count. 1129dba64beSDimitry Andric /// 1139dba64beSDimitry Andric /// Semantics of individual states: 1149dba64beSDimitry Andric /// 1159dba64beSDimitry Andric /// - m_continue_packet == false, m_async_count == 0: 1169dba64beSDimitry Andric /// connection is free 1179dba64beSDimitry Andric /// - m_continue_packet == true, m_async_count == 0: 1189dba64beSDimitry Andric /// only continue thread is present 1199dba64beSDimitry Andric /// - m_continue_packet == true, m_async_count > 0: 1209dba64beSDimitry Andric /// continue thread has control, async threads should interrupt it and wait 1219dba64beSDimitry Andric /// for it to set m_continue_packet to false 1229dba64beSDimitry Andric /// - m_continue_packet == false, m_async_count > 0: 1239dba64beSDimitry Andric /// async threads have control, continue thread needs to wait for them to 1249dba64beSDimitry Andric /// finish (m_async_count goes down to 0). 1259dba64beSDimitry Andric /// @{ 1260b57cec5SDimitry Andric std::mutex m_mutex; 1270b57cec5SDimitry Andric std::condition_variable m_cv; 1280b57cec5SDimitry Andric 1299dba64beSDimitry Andric /// Packet with which to resume after an async interrupt. Can be changed by 1309dba64beSDimitry Andric /// an async thread e.g. to inject a signal. 1319dba64beSDimitry Andric std::string m_continue_packet; 1329dba64beSDimitry Andric 1339dba64beSDimitry Andric /// When was the interrupt packet sent. Used to make sure we time out if the 1349dba64beSDimitry Andric /// stub does not respond to interrupt requests. 135fe6060f1SDimitry Andric std::chrono::time_point<std::chrono::steady_clock> m_interrupt_endpoint; 1369dba64beSDimitry Andric 1379dba64beSDimitry Andric /// Number of threads interested in sending. 1389dba64beSDimitry Andric uint32_t m_async_count; 1399dba64beSDimitry Andric 1409dba64beSDimitry Andric /// Whether the continue thread has control. 1419dba64beSDimitry Andric bool m_is_running; 1429dba64beSDimitry Andric 1439dba64beSDimitry Andric /// Whether we should resume after a stop. 1449dba64beSDimitry Andric bool m_should_stop; 1459dba64beSDimitry Andric /// @} 1469dba64beSDimitry Andric 1479dba64beSDimitry Andric /// This handles the synchronization between individual async threads. For 1489dba64beSDimitry Andric /// now they just use a simple mutex. 1490b57cec5SDimitry Andric std::recursive_mutex m_async_mutex; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric bool ShouldStop(const UnixSignals &signals, 1520b57cec5SDimitry Andric StringExtractorGDBRemote &response); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric class ContinueLock { 1550b57cec5SDimitry Andric public: 1560b57cec5SDimitry Andric enum class LockResult { Success, Cancelled, Failed }; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric explicit ContinueLock(GDBRemoteClientBase &comm); 1590b57cec5SDimitry Andric ~ContinueLock(); 1600b57cec5SDimitry Andric explicit operator bool() { return m_acquired; } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric LockResult lock(); 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric void unlock(); 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric private: 1670b57cec5SDimitry Andric GDBRemoteClientBase &m_comm; 1680b57cec5SDimitry Andric bool m_acquired; 1690b57cec5SDimitry Andric }; 1700b57cec5SDimitry Andric }; 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric } // namespace process_gdb_remote 1730b57cec5SDimitry Andric } // namespace lldb_private 1740b57cec5SDimitry Andric 1755ffd83dbSDimitry Andric #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H 176