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