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_
153