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