xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h (revision dda2819751e49c83612958492e38917049128b41)
1061da546Spatrick //===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9*dda28197Spatrick #ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
10*dda28197Spatrick #define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
11061da546Spatrick 
12061da546Spatrick #include "GDBRemoteCommunication.h"
13061da546Spatrick 
14061da546Spatrick #include <condition_variable>
15061da546Spatrick 
16061da546Spatrick namespace lldb_private {
17061da546Spatrick namespace process_gdb_remote {
18061da546Spatrick 
19061da546Spatrick class GDBRemoteClientBase : public GDBRemoteCommunication {
20061da546Spatrick public:
21061da546Spatrick   struct ContinueDelegate {
22061da546Spatrick     virtual ~ContinueDelegate();
23061da546Spatrick     virtual void HandleAsyncStdout(llvm::StringRef out) = 0;
24061da546Spatrick     virtual void HandleAsyncMisc(llvm::StringRef data) = 0;
25061da546Spatrick     virtual void HandleStopReply() = 0;
26061da546Spatrick 
27061da546Spatrick     /// Process asynchronously-received structured data.
28061da546Spatrick     ///
29061da546Spatrick     /// \param[in] data
30061da546Spatrick     ///   The complete data packet, expected to start with JSON-async.
31061da546Spatrick     virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;
32061da546Spatrick   };
33061da546Spatrick 
34061da546Spatrick   GDBRemoteClientBase(const char *comm_name, const char *listener_name);
35061da546Spatrick 
36061da546Spatrick   bool SendAsyncSignal(int signo);
37061da546Spatrick 
38061da546Spatrick   bool Interrupt();
39061da546Spatrick 
40061da546Spatrick   lldb::StateType SendContinuePacketAndWaitForResponse(
41061da546Spatrick       ContinueDelegate &delegate, const UnixSignals &signals,
42061da546Spatrick       llvm::StringRef payload, StringExtractorGDBRemote &response);
43061da546Spatrick 
44061da546Spatrick   PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload,
45061da546Spatrick                                             StringExtractorGDBRemote &response,
46061da546Spatrick                                             bool send_async);
47061da546Spatrick 
48061da546Spatrick   PacketResult SendPacketAndReceiveResponseWithOutputSupport(
49061da546Spatrick       llvm::StringRef payload, StringExtractorGDBRemote &response,
50061da546Spatrick       bool send_async,
51061da546Spatrick       llvm::function_ref<void(llvm::StringRef)> output_callback);
52061da546Spatrick 
53061da546Spatrick   bool SendvContPacket(llvm::StringRef payload,
54061da546Spatrick                        StringExtractorGDBRemote &response);
55061da546Spatrick 
56061da546Spatrick   class Lock {
57061da546Spatrick   public:
58061da546Spatrick     Lock(GDBRemoteClientBase &comm, bool interrupt);
59061da546Spatrick     ~Lock();
60061da546Spatrick 
61061da546Spatrick     explicit operator bool() { return m_acquired; }
62061da546Spatrick 
63061da546Spatrick     // Whether we had to interrupt the continue thread to acquire the
64061da546Spatrick     // connection.
65061da546Spatrick     bool DidInterrupt() const { return m_did_interrupt; }
66061da546Spatrick 
67061da546Spatrick   private:
68061da546Spatrick     std::unique_lock<std::recursive_mutex> m_async_lock;
69061da546Spatrick     GDBRemoteClientBase &m_comm;
70061da546Spatrick     bool m_acquired;
71061da546Spatrick     bool m_did_interrupt;
72061da546Spatrick 
73061da546Spatrick     void SyncWithContinueThread(bool interrupt);
74061da546Spatrick   };
75061da546Spatrick 
76061da546Spatrick protected:
77061da546Spatrick   PacketResult
78061da546Spatrick   SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
79061da546Spatrick                                      StringExtractorGDBRemote &response);
80061da546Spatrick 
81061da546Spatrick   virtual void OnRunPacketSent(bool first);
82061da546Spatrick 
83061da546Spatrick private:
84061da546Spatrick   /// Variables handling synchronization between the Continue thread and any
85061da546Spatrick   /// other threads wishing to send packets over the connection. Either the
86061da546Spatrick   /// continue thread has control over the connection (m_is_running == true) or
87061da546Spatrick   /// the connection is free for an arbitrary number of other senders to take
88061da546Spatrick   /// which indicate their interest by incrementing m_async_count.
89061da546Spatrick   ///
90061da546Spatrick   /// Semantics of individual states:
91061da546Spatrick   ///
92061da546Spatrick   /// - m_continue_packet == false, m_async_count == 0:
93061da546Spatrick   ///   connection is free
94061da546Spatrick   /// - m_continue_packet == true, m_async_count == 0:
95061da546Spatrick   ///   only continue thread is present
96061da546Spatrick   /// - m_continue_packet == true, m_async_count > 0:
97061da546Spatrick   ///   continue thread has control, async threads should interrupt it and wait
98061da546Spatrick   ///   for it to set m_continue_packet to false
99061da546Spatrick   /// - m_continue_packet == false, m_async_count > 0:
100061da546Spatrick   ///   async threads have control, continue thread needs to wait for them to
101061da546Spatrick   ///   finish (m_async_count goes down to 0).
102061da546Spatrick   /// @{
103061da546Spatrick   std::mutex m_mutex;
104061da546Spatrick   std::condition_variable m_cv;
105061da546Spatrick 
106061da546Spatrick   /// Packet with which to resume after an async interrupt. Can be changed by
107061da546Spatrick   /// an async thread e.g. to inject a signal.
108061da546Spatrick   std::string m_continue_packet;
109061da546Spatrick 
110061da546Spatrick   /// When was the interrupt packet sent. Used to make sure we time out if the
111061da546Spatrick   /// stub does not respond to interrupt requests.
112061da546Spatrick   std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time;
113061da546Spatrick 
114061da546Spatrick   /// Number of threads interested in sending.
115061da546Spatrick   uint32_t m_async_count;
116061da546Spatrick 
117061da546Spatrick   /// Whether the continue thread has control.
118061da546Spatrick   bool m_is_running;
119061da546Spatrick 
120061da546Spatrick   /// Whether we should resume after a stop.
121061da546Spatrick   bool m_should_stop;
122061da546Spatrick   /// @}
123061da546Spatrick 
124061da546Spatrick   /// This handles the synchronization between individual async threads. For
125061da546Spatrick   /// now they just use a simple mutex.
126061da546Spatrick   std::recursive_mutex m_async_mutex;
127061da546Spatrick 
128061da546Spatrick   bool ShouldStop(const UnixSignals &signals,
129061da546Spatrick                   StringExtractorGDBRemote &response);
130061da546Spatrick 
131061da546Spatrick   class ContinueLock {
132061da546Spatrick   public:
133061da546Spatrick     enum class LockResult { Success, Cancelled, Failed };
134061da546Spatrick 
135061da546Spatrick     explicit ContinueLock(GDBRemoteClientBase &comm);
136061da546Spatrick     ~ContinueLock();
137061da546Spatrick     explicit operator bool() { return m_acquired; }
138061da546Spatrick 
139061da546Spatrick     LockResult lock();
140061da546Spatrick 
141061da546Spatrick     void unlock();
142061da546Spatrick 
143061da546Spatrick   private:
144061da546Spatrick     GDBRemoteClientBase &m_comm;
145061da546Spatrick     bool m_acquired;
146061da546Spatrick   };
147061da546Spatrick };
148061da546Spatrick 
149061da546Spatrick } // namespace process_gdb_remote
150061da546Spatrick } // namespace lldb_private
151061da546Spatrick 
152*dda28197Spatrick #endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECLIENTBASE_H
153