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