]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
MFV r362082:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Plugins / Process / gdb-remote / GDBRemoteClientBase.h
1 //===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef liblldb_GDBRemoteClientBase_h_
10 #define liblldb_GDBRemoteClientBase_h_
11
12 #include "GDBRemoteCommunication.h"
13
14 #include <condition_variable>
15
16 namespace lldb_private {
17 namespace process_gdb_remote {
18
19 class GDBRemoteClientBase : public GDBRemoteCommunication {
20 public:
21   struct ContinueDelegate {
22     virtual ~ContinueDelegate();
23     virtual void HandleAsyncStdout(llvm::StringRef out) = 0;
24     virtual void HandleAsyncMisc(llvm::StringRef data) = 0;
25     virtual void HandleStopReply() = 0;
26
27     /// Process asynchronously-received structured data.
28     ///
29     /// \param[in] data
30     ///   The complete data packet, expected to start with JSON-async.
31     virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;
32   };
33
34   GDBRemoteClientBase(const char *comm_name, const char *listener_name);
35
36   bool SendAsyncSignal(int signo);
37
38   bool Interrupt();
39
40   lldb::StateType SendContinuePacketAndWaitForResponse(
41       ContinueDelegate &delegate, const UnixSignals &signals,
42       llvm::StringRef payload, StringExtractorGDBRemote &response);
43
44   PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload,
45                                             StringExtractorGDBRemote &response,
46                                             bool send_async);
47
48   PacketResult SendPacketAndReceiveResponseWithOutputSupport(
49       llvm::StringRef payload, StringExtractorGDBRemote &response,
50       bool send_async,
51       llvm::function_ref<void(llvm::StringRef)> output_callback);
52
53   bool SendvContPacket(llvm::StringRef payload,
54                        StringExtractorGDBRemote &response);
55
56   class Lock {
57   public:
58     Lock(GDBRemoteClientBase &comm, bool interrupt);
59     ~Lock();
60
61     explicit operator bool() { return m_acquired; }
62
63     // Whether we had to interrupt the continue thread to acquire the
64     // connection.
65     bool DidInterrupt() const { return m_did_interrupt; }
66
67   private:
68     std::unique_lock<std::recursive_mutex> m_async_lock;
69     GDBRemoteClientBase &m_comm;
70     bool m_acquired;
71     bool m_did_interrupt;
72
73     void SyncWithContinueThread(bool interrupt);
74   };
75
76 protected:
77   PacketResult
78   SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
79                                      StringExtractorGDBRemote &response);
80
81   virtual void OnRunPacketSent(bool first);
82
83 private:
84   /// Variables handling synchronization between the Continue thread and any
85   /// other threads wishing to send packets over the connection. Either the
86   /// continue thread has control over the connection (m_is_running == true) or
87   /// the connection is free for an arbitrary number of other senders to take
88   /// which indicate their interest by incrementing m_async_count.
89   ///
90   /// Semantics of individual states:
91   ///
92   /// - m_continue_packet == false, m_async_count == 0:
93   ///   connection is free
94   /// - m_continue_packet == true, m_async_count == 0:
95   ///   only continue thread is present
96   /// - m_continue_packet == true, m_async_count > 0:
97   ///   continue thread has control, async threads should interrupt it and wait
98   ///   for it to set m_continue_packet to false
99   /// - m_continue_packet == false, m_async_count > 0:
100   ///   async threads have control, continue thread needs to wait for them to
101   ///   finish (m_async_count goes down to 0).
102   /// @{
103   std::mutex m_mutex;
104   std::condition_variable m_cv;
105
106   /// Packet with which to resume after an async interrupt. Can be changed by
107   /// an async thread e.g. to inject a signal.
108   std::string m_continue_packet;
109
110   /// When was the interrupt packet sent. Used to make sure we time out if the
111   /// stub does not respond to interrupt requests.
112   std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time;
113
114   /// Number of threads interested in sending.
115   uint32_t m_async_count;
116
117   /// Whether the continue thread has control.
118   bool m_is_running;
119
120   /// Whether we should resume after a stop.
121   bool m_should_stop;
122   /// @}
123
124   /// This handles the synchronization between individual async threads. For
125   /// now they just use a simple mutex.
126   std::recursive_mutex m_async_mutex;
127
128   bool ShouldStop(const UnixSignals &signals,
129                   StringExtractorGDBRemote &response);
130
131   class ContinueLock {
132   public:
133     enum class LockResult { Success, Cancelled, Failed };
134
135     explicit ContinueLock(GDBRemoteClientBase &comm);
136     ~ContinueLock();
137     explicit operator bool() { return m_acquired; }
138
139     LockResult lock();
140
141     void unlock();
142
143   private:
144     GDBRemoteClientBase &m_comm;
145     bool m_acquired;
146   };
147 };
148
149 } // namespace process_gdb_remote
150 } // namespace lldb_private
151
152 #endif // liblldb_GDBRemoteCommunicationClient_h_