1 //===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===//
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 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/FormatVariadic.h"
17
18 #if !defined(_MSC_VER) && !defined(__MINGW32__)
19 #include <unistd.h>
20 #else
21 #include <io.h>
22 #endif
23
24 namespace {
25
26 struct FDMsgHeader {
27 static constexpr unsigned MsgSizeOffset = 0;
28 static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t);
29 static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t);
30 static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t);
31 static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t);
32 };
33
34 } // namespace
35
36 namespace llvm {
37 namespace orc {
38 namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
39
40 const char *ExecutorSessionObjectName =
41 "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42 const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
43
44 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
45
46 SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default;
47 SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default;
48
49 Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
Create(SimpleRemoteEPCTransportClient & C,int InFD,int OutFD)50 FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,
51 int OutFD) {
52 #if LLVM_ENABLE_THREADS
53 if (InFD == -1)
54 return make_error<StringError>("Invalid input file descriptor " +
55 Twine(InFD),
56 inconvertibleErrorCode());
57 if (OutFD == -1)
58 return make_error<StringError>("Invalid output file descriptor " +
59 Twine(OutFD),
60 inconvertibleErrorCode());
61 std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
62 new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
63 return std::move(FDT);
64 #else
65 return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "
66 "thread support, but llvm was built with "
67 "LLVM_ENABLE_THREADS=Off",
68 inconvertibleErrorCode());
69 #endif
70 }
71
~FDSimpleRemoteEPCTransport()72 FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
73 #if LLVM_ENABLE_THREADS
74 ListenerThread.join();
75 #endif
76 }
77
start()78 Error FDSimpleRemoteEPCTransport::start() {
79 #if LLVM_ENABLE_THREADS
80 ListenerThread = std::thread([this]() { listenLoop(); });
81 return Error::success();
82 #endif
83 llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off");
84 }
85
sendMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,ArrayRef<char> ArgBytes)86 Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
87 uint64_t SeqNo,
88 ExecutorAddr TagAddr,
89 ArrayRef<char> ArgBytes) {
90 char HeaderBuffer[FDMsgHeader::Size];
91
92 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
93 FDMsgHeader::Size + ArgBytes.size();
94 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
95 static_cast<uint64_t>(OpC);
96 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
97 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
98 TagAddr.getValue();
99
100 std::lock_guard<std::mutex> Lock(M);
101 if (Disconnected)
102 return make_error<StringError>("FD-transport disconnected",
103 inconvertibleErrorCode());
104 if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
105 return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
106 if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
107 return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
108 return Error::success();
109 }
110
disconnect()111 void FDSimpleRemoteEPCTransport::disconnect() {
112 if (Disconnected)
113 return; // Return if already disconnected.
114
115 Disconnected = true;
116 bool CloseOutFD = InFD != OutFD;
117
118 // Close InFD.
119 while (close(InFD) == -1) {
120 if (errno == EBADF)
121 break;
122 }
123
124 // Close OutFD.
125 if (CloseOutFD) {
126 while (close(OutFD) == -1) {
127 if (errno == EBADF)
128 break;
129 }
130 }
131 }
132
makeUnexpectedEOFError()133 static Error makeUnexpectedEOFError() {
134 return make_error<StringError>("Unexpected end-of-file",
135 inconvertibleErrorCode());
136 }
137
readBytes(char * Dst,size_t Size,bool * IsEOF)138 Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
139 bool *IsEOF) {
140 assert((Size == 0 || Dst) && "Attempt to read into null.");
141 ssize_t Completed = 0;
142 while (Completed < static_cast<ssize_t>(Size)) {
143 ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
144 if (Read <= 0) {
145 auto ErrNo = errno;
146 if (Read == 0) {
147 if (Completed == 0 && IsEOF) {
148 *IsEOF = true;
149 return Error::success();
150 } else
151 return makeUnexpectedEOFError();
152 } else if (ErrNo == EAGAIN || ErrNo == EINTR)
153 continue;
154 else {
155 std::lock_guard<std::mutex> Lock(M);
156 if (Disconnected && IsEOF) { // disconnect called, pretend this is EOF.
157 *IsEOF = true;
158 return Error::success();
159 }
160 return errorCodeToError(
161 std::error_code(ErrNo, std::generic_category()));
162 }
163 }
164 Completed += Read;
165 }
166 return Error::success();
167 }
168
writeBytes(const char * Src,size_t Size)169 int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
170 assert((Size == 0 || Src) && "Attempt to append from null.");
171 ssize_t Completed = 0;
172 while (Completed < static_cast<ssize_t>(Size)) {
173 ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
174 if (Written < 0) {
175 auto ErrNo = errno;
176 if (ErrNo == EAGAIN || ErrNo == EINTR)
177 continue;
178 else
179 return ErrNo;
180 }
181 Completed += Written;
182 }
183 return 0;
184 }
185
listenLoop()186 void FDSimpleRemoteEPCTransport::listenLoop() {
187 Error Err = Error::success();
188 do {
189
190 char HeaderBuffer[FDMsgHeader::Size];
191 // Read the header buffer.
192 {
193 bool IsEOF = false;
194 if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
195 Err = joinErrors(std::move(Err), std::move(Err2));
196 break;
197 }
198 if (IsEOF)
199 break;
200 }
201
202 // Decode header buffer.
203 uint64_t MsgSize;
204 SimpleRemoteEPCOpcode OpC;
205 uint64_t SeqNo;
206 ExecutorAddr TagAddr;
207
208 MsgSize =
209 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
210 OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
211 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
212 SeqNo =
213 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
214 TagAddr.setValue(
215 *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
216
217 if (MsgSize < FDMsgHeader::Size) {
218 Err = joinErrors(std::move(Err),
219 make_error<StringError>("Message size too small",
220 inconvertibleErrorCode()));
221 break;
222 }
223
224 // Read the argument bytes.
225 SimpleRemoteEPCArgBytesVector ArgBytes;
226 ArgBytes.resize(MsgSize - FDMsgHeader::Size);
227 if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
228 Err = joinErrors(std::move(Err), std::move(Err2));
229 break;
230 }
231
232 if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
233 if (*Action == SimpleRemoteEPCTransportClient::EndSession)
234 break;
235 } else {
236 Err = joinErrors(std::move(Err), Action.takeError());
237 break;
238 }
239 } while (true);
240
241 // Attempt to close FDs, set Disconnected to true so that subsequent
242 // sendMessage calls fail.
243 disconnect();
244
245 // Call up to the client to handle the disconnection.
246 C.handleDisconnect(std::move(Err));
247 }
248
249 } // end namespace orc
250 } // end namespace llvm
251