[ORC] Propagate errors to handlers when sendMessage fails.
[llvm-project.git] / llvm / lib / ExecutionEngine / Orc / Shared / SimpleRemoteEPCUtils.cpp
blob64fc717b7b56cc8d0c4b4e81430287641dfecc25
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.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/FormatVariadic.h"
18 #if !defined(_MSC_VER) && !defined(__MINGW32__)
19 #include <unistd.h>
20 #else
21 #include <io.h>
22 #endif
24 namespace {
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);
34 } // namespace
36 namespace llvm {
37 namespace orc {
38 namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
40 const char *ExecutorSessionObjectName =
41 "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42 const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
44 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
46 SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {}
47 SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {}
49 Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
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
72 FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
73 #if LLVM_ENABLE_THREADS
74 ListenerThread.join();
75 #endif
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");
86 Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
87 uint64_t SeqNo,
88 ExecutorAddr TagAddr,
89 ArrayRef<char> ArgBytes) {
90 char HeaderBuffer[FDMsgHeader::Size];
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();
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();
111 void FDSimpleRemoteEPCTransport::disconnect() {
112 if (Disconnected)
113 return; // Return if already disconnected.
115 Disconnected = true;
116 bool CloseOutFD = InFD != OutFD;
118 // Close InFD.
119 while (close(InFD) == -1) {
120 if (errno == EBADF)
121 break;
124 // Close OutFD.
125 if (CloseOutFD) {
126 while (close(OutFD) == -1) {
127 if (errno == EBADF)
128 break;
133 static Error makeUnexpectedEOFError() {
134 return make_error<StringError>("Unexpected end-of-file",
135 inconvertibleErrorCode());
138 Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
139 bool *IsEOF) {
140 assert(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();
160 return errorCodeToError(
161 std::error_code(ErrNo, std::generic_category()));
164 Completed += Read;
166 return Error::success();
169 int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
170 assert(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;
181 Completed += Written;
183 return 0;
186 void FDSimpleRemoteEPCTransport::listenLoop() {
187 Error Err = Error::success();
188 do {
190 char HeaderBuffer[FDMsgHeader::Size];
191 // Read the header buffer.
193 bool IsEOF = false;
194 if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
195 Err = joinErrors(std::move(Err), std::move(Err2));
196 break;
198 if (IsEOF)
199 break;
202 // Decode header buffer.
203 uint64_t MsgSize;
204 SimpleRemoteEPCOpcode OpC;
205 uint64_t SeqNo;
206 ExecutorAddr TagAddr;
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)));
217 if (MsgSize < FDMsgHeader::Size) {
218 Err = joinErrors(std::move(Err),
219 make_error<StringError>("Message size too small",
220 inconvertibleErrorCode()));
221 break;
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;
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;
239 } while (true);
241 // Attempt to close FDs, set Disconnected to true so that subsequent
242 // sendMessage calls fail.
243 disconnect();
245 // Call up to the client to handle the disconnection.
246 C.handleDisconnect(std::move(Err));
249 } // end namespace orc
250 } // end namespace llvm