Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
39642 views
//===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H9#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H1011#include "GDBRemoteCommunication.h"1213#include <condition_variable>1415namespace lldb_private {16namespace process_gdb_remote {1718class GDBRemoteClientBase : public GDBRemoteCommunication, public Broadcaster {19public:20enum {21eBroadcastBitRunPacketSent = (1u << 0),22};2324struct ContinueDelegate {25virtual ~ContinueDelegate();26virtual void HandleAsyncStdout(llvm::StringRef out) = 0;27virtual void HandleAsyncMisc(llvm::StringRef data) = 0;28virtual void HandleStopReply() = 0;2930/// Process asynchronously-received structured data.31///32/// \param[in] data33/// The complete data packet, expected to start with JSON-async.34virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;35};3637GDBRemoteClientBase(const char *comm_name);3839bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout);4041bool Interrupt(std::chrono::seconds interrupt_timeout);4243lldb::StateType SendContinuePacketAndWaitForResponse(44ContinueDelegate &delegate, const UnixSignals &signals,45llvm::StringRef payload, std::chrono::seconds interrupt_timeout,46StringExtractorGDBRemote &response);4748// If interrupt_timeout == 0 seconds, don't interrupt the target.49// Only send the packet if the target is stopped.50// If you want to use this mode, use the fact that the timeout is defaulted51// so it's clear from the call-site that you are using no-interrupt.52// If it is non-zero, interrupt the target if it is running, and53// send the packet.54// It the target doesn't respond within the given timeout, it returns55// ErrorReplyTimeout.56PacketResult SendPacketAndWaitForResponse(57llvm::StringRef payload, StringExtractorGDBRemote &response,58std::chrono::seconds interrupt_timeout = std::chrono::seconds(0));5960PacketResult ReadPacketWithOutputSupport(61StringExtractorGDBRemote &response, Timeout<std::micro> timeout,62bool sync_on_timeout,63llvm::function_ref<void(llvm::StringRef)> output_callback);6465PacketResult SendPacketAndReceiveResponseWithOutputSupport(66llvm::StringRef payload, StringExtractorGDBRemote &response,67std::chrono::seconds interrupt_timeout,68llvm::function_ref<void(llvm::StringRef)> output_callback);6970class Lock {71public:72// If interrupt_timeout == 0 seconds, only take the lock if the target is73// not running. If using this option, use the fact that the74// interrupt_timeout is defaulted so it will be obvious at the call site75// that you are choosing this mode. If it is non-zero, interrupt the target76// if it is running, waiting for the given timeout for the interrupt to77// succeed.78Lock(GDBRemoteClientBase &comm,79std::chrono::seconds interrupt_timeout = std::chrono::seconds(0));80~Lock();8182explicit operator bool() { return m_acquired; }8384// Whether we had to interrupt the continue thread to acquire the85// connection.86bool DidInterrupt() const { return m_did_interrupt; }8788private:89std::unique_lock<std::recursive_mutex> m_async_lock;90GDBRemoteClientBase &m_comm;91std::chrono::seconds m_interrupt_timeout;92bool m_acquired;93bool m_did_interrupt;9495void SyncWithContinueThread();96};9798protected:99PacketResult100SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,101StringExtractorGDBRemote &response);102103virtual void OnRunPacketSent(bool first);104105private:106/// Variables handling synchronization between the Continue thread and any107/// other threads wishing to send packets over the connection. Either the108/// continue thread has control over the connection (m_is_running == true) or109/// the connection is free for an arbitrary number of other senders to take110/// which indicate their interest by incrementing m_async_count.111///112/// Semantics of individual states:113///114/// - m_continue_packet == false, m_async_count == 0:115/// connection is free116/// - m_continue_packet == true, m_async_count == 0:117/// only continue thread is present118/// - m_continue_packet == true, m_async_count > 0:119/// continue thread has control, async threads should interrupt it and wait120/// for it to set m_continue_packet to false121/// - m_continue_packet == false, m_async_count > 0:122/// async threads have control, continue thread needs to wait for them to123/// finish (m_async_count goes down to 0).124/// @{125std::mutex m_mutex;126std::condition_variable m_cv;127128/// Packet with which to resume after an async interrupt. Can be changed by129/// an async thread e.g. to inject a signal.130std::string m_continue_packet;131132/// When was the interrupt packet sent. Used to make sure we time out if the133/// stub does not respond to interrupt requests.134std::chrono::time_point<std::chrono::steady_clock> m_interrupt_endpoint;135136/// Number of threads interested in sending.137uint32_t m_async_count;138139/// Whether the continue thread has control.140bool m_is_running;141142/// Whether we should resume after a stop.143bool m_should_stop;144/// @}145146/// This handles the synchronization between individual async threads. For147/// now they just use a simple mutex.148std::recursive_mutex m_async_mutex;149150bool ShouldStop(const UnixSignals &signals,151StringExtractorGDBRemote &response);152153class ContinueLock {154public:155enum class LockResult { Success, Cancelled, Failed };156157explicit ContinueLock(GDBRemoteClientBase &comm);158~ContinueLock();159explicit operator bool() { return m_acquired; }160161LockResult lock();162163void unlock();164165private:166GDBRemoteClientBase &m_comm;167bool m_acquired;168};169};170171} // namespace process_gdb_remote172} // namespace lldb_private173174#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H175176177