LLVM 19.0.0git
SimpleRemoteEPCUtils.cpp
Go to the documentation of this file.
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
15#include "llvm/Support/Endian.h"
17
18#if !defined(_MSC_VER) && !defined(__MINGW32__)
19#include <unistd.h>
20#else
21#include <io.h>
22#endif
23
24namespace {
25
26struct 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
36namespace llvm {
37namespace orc {
38namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
39
41 "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
43
44} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
45
48
51 int OutFD) {
52#if LLVM_ENABLE_THREADS
53 if (InFD == -1)
54 return make_error<StringError>("Invalid input file descriptor " +
55 Twine(InFD),
57 if (OutFD == -1)
58 return make_error<StringError>("Invalid output file descriptor " +
59 Twine(OutFD),
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",
69#endif
70}
71
73#if LLVM_ENABLE_THREADS
74 ListenerThread.join();
75#endif
76}
77
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
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",
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
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
134 return make_error<StringError>("Unexpected end-of-file",
136}
137
138Error 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
169int 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
186void 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;
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",
221 break;
222 }
223
224 // Read the argument bytes.
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)) {
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
uint64_t Size
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
const T * data() const
Definition: ArrayRef.h:162
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
Represents an address in the executor process.
uint64_t getValue() const
Uses read/write on FileDescriptors for transport.
void disconnect() override
Trigger disconnection from the transport.
static Expected< std::unique_ptr< FDSimpleRemoteEPCTransport > > Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD)
Create a FDSimpleRemoteEPCTransport using the given FDs for reading (InFD) and writing (OutFD).
Error start() override
Called during setup of the client to indicate that the client is ready to receive messages.
Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, ArrayRef< char > ArgBytes) override
Send a SimpleRemoteEPC message.
virtual Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, SimpleRemoteEPCArgBytesVector ArgBytes)=0
Handle receipt of a message.
virtual void handleDisconnect(Error Err)=0
Handle a disconnection from the underlying transport.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
ManagedStatic< cl::opt< FnT >, OptCreatorT > Action
SmallVector< char, 128 > SimpleRemoteEPCArgBytesVector
static Error makeUnexpectedEOFError()
detail::packed_endian_specific_integral< uint64_t, llvm::endianness::little, unaligned > ulittle64_t
Definition: Endian.h:272
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:90
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:431
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:601
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:103