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, InFD: FD, OutFD: 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(Arg: V.Name, Args: V.Required); |
174 | } |
175 | |
176 | static size_t serialize(SPSOutputBuffer &OB, |
177 | const RemoteSymbolLookupSetElement &V) { |
178 | return SPSArgList<SPSString, bool>::serialize(OB, Arg: V.Name, Args: V.Required); |
179 | } |
180 | |
181 | static size_t deserialize(SPSInputBuffer &IB, |
182 | RemoteSymbolLookupSetElement &V) { |
183 | return SPSArgList<SPSString, bool>::deserialize(IB, Arg&: V.Name, Args&: 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(Arg: V.H, Args: V.Symbols); |
192 | } |
193 | |
194 | static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) { |
195 | return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, Arg: V.H, |
196 | Args: V.Symbols); |
197 | } |
198 | |
199 | static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) { |
200 | return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize( |
201 | IB, Arg&: V.H, Args&: 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 | Arg: SI.TargetTriple, Args: SI.PageSize, Args: SI.BootstrapMap, Args: SI.BootstrapSymbols); |
212 | } |
213 | |
214 | static bool serialize(SPSOutputBuffer &OB, |
215 | const SimpleRemoteEPCExecutorInfo &SI) { |
216 | return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize( |
217 | OB, Arg: SI.TargetTriple, Args: SI.PageSize, Args: SI.BootstrapMap, Args: SI.BootstrapSymbols); |
218 | } |
219 | |
220 | static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) { |
221 | return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize( |
222 | IB, Arg&: SI.TargetTriple, Args&: SI.PageSize, Args&: SI.BootstrapMap, Args&: 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 | |