1 //===--- SimpleRemoteEPCUtils.h - Utils for Simple Remote EPC ---*- 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 // Message definitions and other utilities for SimpleRemoteEPC and
10 // SimpleRemoteEPCServer.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
16 
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
21 #include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
22 #include "llvm/Support/Error.h"
23 
24 #include <atomic>
25 #include <mutex>
26 #include <string>
27 #include <thread>
28 
29 namespace llvm {
30 namespace orc {
31 
32 namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
33 extern const char *ExecutorSessionObjectName;
34 extern const char *DispatchFnName;
35 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
36 
37 enum class SimpleRemoteEPCOpcode : uint8_t {
38   Setup,
39   Hangup,
40   Result,
41   CallWrapper,
42   LastOpC = CallWrapper
43 };
44 
45 struct SimpleRemoteEPCExecutorInfo {
46   std::string TargetTriple;
47   uint64_t PageSize;
48   StringMap<std::vector<char>> BootstrapMap;
49   StringMap<ExecutorAddr> BootstrapSymbols;
50 };
51 
52 using SimpleRemoteEPCArgBytesVector = SmallVector<char, 128>;
53 
54 class SimpleRemoteEPCTransportClient {
55 public:
56   enum HandleMessageAction { ContinueSession, EndSession };
57 
58   virtual ~SimpleRemoteEPCTransportClient();
59 
60   /// Handle receipt of a message.
61   ///
62   /// Returns an Error if the message cannot be handled, 'EndSession' if the
63   /// client will not accept any further messages, and 'ContinueSession'
64   /// otherwise.
65   virtual Expected<HandleMessageAction>
66   handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr,
67                 SimpleRemoteEPCArgBytesVector ArgBytes) = 0;
68 
69   /// Handle a disconnection from the underlying transport. No further messages
70   /// should be sent to handleMessage after this is called.
71   /// Err may contain an Error value indicating unexpected disconnection. This
72   /// allows clients to log such errors, but no attempt should be made at
73   /// recovery (which should be handled inside the transport class, if it is
74   /// supported at all).
75   virtual void handleDisconnect(Error Err) = 0;
76 };
77 
78 class SimpleRemoteEPCTransport {
79 public:
80   virtual ~SimpleRemoteEPCTransport();
81 
82   /// Called during setup of the client to indicate that the client is ready
83   /// to receive messages.
84   ///
85   /// Transport objects should not access the client until this method is
86   /// called.
87   virtual Error start() = 0;
88 
89   /// Send a SimpleRemoteEPC message.
90   ///
91   /// This function may be called concurrently. Subclasses should implement
92   /// locking if required for the underlying transport.
93   virtual Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
94                             ExecutorAddr TagAddr, ArrayRef<char> ArgBytes) = 0;
95 
96   /// Trigger disconnection from the transport. The implementation should
97   /// respond by calling handleDisconnect on the client once disconnection
98   /// is complete. May be called more than once and from different threads.
99   virtual void disconnect() = 0;
100 };
101 
102 /// Uses read/write on FileDescriptors for transport.
103 class FDSimpleRemoteEPCTransport : public SimpleRemoteEPCTransport {
104 public:
105   /// Create a FDSimpleRemoteEPCTransport using the given FDs for
106   /// reading (InFD) and writing (OutFD).
107   static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
108   Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD);
109 
110   /// Create a FDSimpleRemoteEPCTransport using the given FD for both
111   /// reading and writing.
112   static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
113   Create(SimpleRemoteEPCTransportClient &C, int FD) {
114     return Create(C, FD, FD);
115   }
116 
117   ~FDSimpleRemoteEPCTransport() override;
118 
119   Error start() override;
120 
121   Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
122                     ExecutorAddr TagAddr, ArrayRef<char> ArgBytes) override;
123 
124   void disconnect() override;
125 
126 private:
127   FDSimpleRemoteEPCTransport(SimpleRemoteEPCTransportClient &C, int InFD,
128                              int OutFD)
129       : C(C), InFD(InFD), OutFD(OutFD) {}
130 
131   Error readBytes(char *Dst, size_t Size, bool *IsEOF = nullptr);
132   int writeBytes(const char *Src, size_t Size);
133   void listenLoop();
134 
135   std::mutex M;
136   SimpleRemoteEPCTransportClient &C;
137   std::thread ListenerThread;
138   int InFD, OutFD;
139   std::atomic<bool> Disconnected{false};
140 };
141 
142 struct RemoteSymbolLookupSetElement {
143   std::string Name;
144   bool Required;
145 };
146 
147 using RemoteSymbolLookupSet = std::vector<RemoteSymbolLookupSetElement>;
148 
149 struct RemoteSymbolLookup {
150   uint64_t H;
151   RemoteSymbolLookupSet Symbols;
152 };
153 
154 namespace shared {
155 
156 using SPSRemoteSymbolLookupSetElement = SPSTuple<SPSString, bool>;
157 
158 using SPSRemoteSymbolLookupSet = SPSSequence<SPSRemoteSymbolLookupSetElement>;
159 
160 using SPSRemoteSymbolLookup = SPSTuple<uint64_t, SPSRemoteSymbolLookupSet>;
161 
162 /// Tuple containing target triple, page size, and bootstrap symbols.
163 using SPSSimpleRemoteEPCExecutorInfo =
164     SPSTuple<SPSString, uint64_t,
165              SPSSequence<SPSTuple<SPSString, SPSSequence<char>>>,
166              SPSSequence<SPSTuple<SPSString, SPSExecutorAddr>>>;
167 
168 template <>
169 class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
170                              RemoteSymbolLookupSetElement> {
171 public:
172   static size_t size(const RemoteSymbolLookupSetElement &V) {
173     return SPSArgList<SPSString, bool>::size(V.Name, V.Required);
174   }
175 
176   static size_t serialize(SPSOutputBuffer &OB,
177                           const RemoteSymbolLookupSetElement &V) {
178     return SPSArgList<SPSString, bool>::serialize(OB, V.Name, V.Required);
179   }
180 
181   static size_t deserialize(SPSInputBuffer &IB,
182                             RemoteSymbolLookupSetElement &V) {
183     return SPSArgList<SPSString, bool>::deserialize(IB, V.Name, V.Required);
184   }
185 };
186 
187 template <>
188 class SPSSerializationTraits<SPSRemoteSymbolLookup, RemoteSymbolLookup> {
189 public:
190   static size_t size(const RemoteSymbolLookup &V) {
191     return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::size(V.H, V.Symbols);
192   }
193 
194   static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) {
195     return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, V.H,
196                                                                      V.Symbols);
197   }
198 
199   static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) {
200     return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize(
201         IB, V.H, V.Symbols);
202   }
203 };
204 
205 template <>
206 class SPSSerializationTraits<SPSSimpleRemoteEPCExecutorInfo,
207                              SimpleRemoteEPCExecutorInfo> {
208 public:
209   static size_t size(const SimpleRemoteEPCExecutorInfo &SI) {
210     return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::size(
211         SI.TargetTriple, SI.PageSize, SI.BootstrapMap, SI.BootstrapSymbols);
212   }
213 
214   static bool serialize(SPSOutputBuffer &OB,
215                         const SimpleRemoteEPCExecutorInfo &SI) {
216     return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize(
217         OB, SI.TargetTriple, SI.PageSize, SI.BootstrapMap, SI.BootstrapSymbols);
218   }
219 
220   static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) {
221     return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize(
222         IB, SI.TargetTriple, SI.PageSize, SI.BootstrapMap, SI.BootstrapSymbols);
223   }
224 };
225 
226 using SPSLoadDylibSignature = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr,
227                                                            SPSString, uint64_t);
228 
229 using SPSLookupSymbolsSignature =
230     SPSExpected<SPSSequence<SPSSequence<SPSExecutorAddr>>>(
231         SPSExecutorAddr, SPSSequence<SPSRemoteSymbolLookup>);
232 
233 } // end namespace shared
234 } // end namespace orc
235 } // end namespace llvm
236 
237 #endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
238