1349cc55cSDimitry Andric //===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // Message definitions and other utilities for SimpleRemoteEPC and
10349cc55cSDimitry Andric // SimpleRemoteEPCServer.
11349cc55cSDimitry Andric //
12349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
13349cc55cSDimitry Andric
14349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
15349cc55cSDimitry Andric #include "llvm/Support/Endian.h"
16349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h"
17349cc55cSDimitry Andric
18349cc55cSDimitry Andric #if !defined(_MSC_VER) && !defined(__MINGW32__)
19349cc55cSDimitry Andric #include <unistd.h>
20349cc55cSDimitry Andric #else
21349cc55cSDimitry Andric #include <io.h>
22349cc55cSDimitry Andric #endif
23349cc55cSDimitry Andric
24349cc55cSDimitry Andric namespace {
25349cc55cSDimitry Andric
26349cc55cSDimitry Andric struct FDMsgHeader {
27349cc55cSDimitry Andric static constexpr unsigned MsgSizeOffset = 0;
28349cc55cSDimitry Andric static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t);
29349cc55cSDimitry Andric static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t);
30349cc55cSDimitry Andric static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t);
31349cc55cSDimitry Andric static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t);
32349cc55cSDimitry Andric };
33349cc55cSDimitry Andric
34349cc55cSDimitry Andric } // namespace
35349cc55cSDimitry Andric
36349cc55cSDimitry Andric namespace llvm {
37349cc55cSDimitry Andric namespace orc {
38349cc55cSDimitry Andric namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
39349cc55cSDimitry Andric
40349cc55cSDimitry Andric const char *ExecutorSessionObjectName =
41349cc55cSDimitry Andric "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42349cc55cSDimitry Andric const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
43349cc55cSDimitry Andric
44349cc55cSDimitry Andric } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
45349cc55cSDimitry Andric
4681ad6265SDimitry Andric SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default;
4781ad6265SDimitry Andric SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default;
48349cc55cSDimitry Andric
49349cc55cSDimitry Andric Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
Create(SimpleRemoteEPCTransportClient & C,int InFD,int OutFD)50349cc55cSDimitry Andric FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,
51349cc55cSDimitry Andric int OutFD) {
52349cc55cSDimitry Andric #if LLVM_ENABLE_THREADS
53349cc55cSDimitry Andric if (InFD == -1)
54349cc55cSDimitry Andric return make_error<StringError>("Invalid input file descriptor " +
55349cc55cSDimitry Andric Twine(InFD),
56349cc55cSDimitry Andric inconvertibleErrorCode());
57349cc55cSDimitry Andric if (OutFD == -1)
58349cc55cSDimitry Andric return make_error<StringError>("Invalid output file descriptor " +
59349cc55cSDimitry Andric Twine(OutFD),
60349cc55cSDimitry Andric inconvertibleErrorCode());
61349cc55cSDimitry Andric std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
62349cc55cSDimitry Andric new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
63349cc55cSDimitry Andric return std::move(FDT);
64349cc55cSDimitry Andric #else
65349cc55cSDimitry Andric return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "
66349cc55cSDimitry Andric "thread support, but llvm was built with "
67349cc55cSDimitry Andric "LLVM_ENABLE_THREADS=Off",
68349cc55cSDimitry Andric inconvertibleErrorCode());
69349cc55cSDimitry Andric #endif
70349cc55cSDimitry Andric }
71349cc55cSDimitry Andric
~FDSimpleRemoteEPCTransport()72349cc55cSDimitry Andric FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
73349cc55cSDimitry Andric #if LLVM_ENABLE_THREADS
74349cc55cSDimitry Andric ListenerThread.join();
75349cc55cSDimitry Andric #endif
76349cc55cSDimitry Andric }
77349cc55cSDimitry Andric
start()78349cc55cSDimitry Andric Error FDSimpleRemoteEPCTransport::start() {
79349cc55cSDimitry Andric #if LLVM_ENABLE_THREADS
80349cc55cSDimitry Andric ListenerThread = std::thread([this]() { listenLoop(); });
81349cc55cSDimitry Andric return Error::success();
82349cc55cSDimitry Andric #endif
83349cc55cSDimitry Andric llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off");
84349cc55cSDimitry Andric }
85349cc55cSDimitry Andric
sendMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,ArrayRef<char> ArgBytes)86349cc55cSDimitry Andric Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
87349cc55cSDimitry Andric uint64_t SeqNo,
88349cc55cSDimitry Andric ExecutorAddr TagAddr,
89349cc55cSDimitry Andric ArrayRef<char> ArgBytes) {
90349cc55cSDimitry Andric char HeaderBuffer[FDMsgHeader::Size];
91349cc55cSDimitry Andric
92349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
93349cc55cSDimitry Andric FDMsgHeader::Size + ArgBytes.size();
94349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
95349cc55cSDimitry Andric static_cast<uint64_t>(OpC);
96349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
97349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
98349cc55cSDimitry Andric TagAddr.getValue();
99349cc55cSDimitry Andric
100349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M);
101349cc55cSDimitry Andric if (Disconnected)
102349cc55cSDimitry Andric return make_error<StringError>("FD-transport disconnected",
103349cc55cSDimitry Andric inconvertibleErrorCode());
104349cc55cSDimitry Andric if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
105349cc55cSDimitry Andric return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
106349cc55cSDimitry Andric if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
107349cc55cSDimitry Andric return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
108349cc55cSDimitry Andric return Error::success();
109349cc55cSDimitry Andric }
110349cc55cSDimitry Andric
disconnect()111349cc55cSDimitry Andric void FDSimpleRemoteEPCTransport::disconnect() {
112349cc55cSDimitry Andric if (Disconnected)
113349cc55cSDimitry Andric return; // Return if already disconnected.
114349cc55cSDimitry Andric
115349cc55cSDimitry Andric Disconnected = true;
116349cc55cSDimitry Andric bool CloseOutFD = InFD != OutFD;
117349cc55cSDimitry Andric
118349cc55cSDimitry Andric // Close InFD.
119349cc55cSDimitry Andric while (close(InFD) == -1) {
120349cc55cSDimitry Andric if (errno == EBADF)
121349cc55cSDimitry Andric break;
122349cc55cSDimitry Andric }
123349cc55cSDimitry Andric
124349cc55cSDimitry Andric // Close OutFD.
125349cc55cSDimitry Andric if (CloseOutFD) {
126349cc55cSDimitry Andric while (close(OutFD) == -1) {
127349cc55cSDimitry Andric if (errno == EBADF)
128349cc55cSDimitry Andric break;
129349cc55cSDimitry Andric }
130349cc55cSDimitry Andric }
131349cc55cSDimitry Andric }
132349cc55cSDimitry Andric
makeUnexpectedEOFError()133349cc55cSDimitry Andric static Error makeUnexpectedEOFError() {
134349cc55cSDimitry Andric return make_error<StringError>("Unexpected end-of-file",
135349cc55cSDimitry Andric inconvertibleErrorCode());
136349cc55cSDimitry Andric }
137349cc55cSDimitry Andric
readBytes(char * Dst,size_t Size,bool * IsEOF)138349cc55cSDimitry Andric Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
139349cc55cSDimitry Andric bool *IsEOF) {
140*bdd1243dSDimitry Andric assert((Size == 0 || Dst) && "Attempt to read into null.");
141349cc55cSDimitry Andric ssize_t Completed = 0;
142349cc55cSDimitry Andric while (Completed < static_cast<ssize_t>(Size)) {
143349cc55cSDimitry Andric ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
144349cc55cSDimitry Andric if (Read <= 0) {
145349cc55cSDimitry Andric auto ErrNo = errno;
146349cc55cSDimitry Andric if (Read == 0) {
147349cc55cSDimitry Andric if (Completed == 0 && IsEOF) {
148349cc55cSDimitry Andric *IsEOF = true;
149349cc55cSDimitry Andric return Error::success();
150349cc55cSDimitry Andric } else
151349cc55cSDimitry Andric return makeUnexpectedEOFError();
152349cc55cSDimitry Andric } else if (ErrNo == EAGAIN || ErrNo == EINTR)
153349cc55cSDimitry Andric continue;
154349cc55cSDimitry Andric else {
155349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M);
156349cc55cSDimitry Andric if (Disconnected && IsEOF) { // disconnect called, pretend this is EOF.
157349cc55cSDimitry Andric *IsEOF = true;
158349cc55cSDimitry Andric return Error::success();
159349cc55cSDimitry Andric }
160349cc55cSDimitry Andric return errorCodeToError(
161349cc55cSDimitry Andric std::error_code(ErrNo, std::generic_category()));
162349cc55cSDimitry Andric }
163349cc55cSDimitry Andric }
164349cc55cSDimitry Andric Completed += Read;
165349cc55cSDimitry Andric }
166349cc55cSDimitry Andric return Error::success();
167349cc55cSDimitry Andric }
168349cc55cSDimitry Andric
writeBytes(const char * Src,size_t Size)169349cc55cSDimitry Andric int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
170*bdd1243dSDimitry Andric assert((Size == 0 || Src) && "Attempt to append from null.");
171349cc55cSDimitry Andric ssize_t Completed = 0;
172349cc55cSDimitry Andric while (Completed < static_cast<ssize_t>(Size)) {
173349cc55cSDimitry Andric ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
174349cc55cSDimitry Andric if (Written < 0) {
175349cc55cSDimitry Andric auto ErrNo = errno;
176349cc55cSDimitry Andric if (ErrNo == EAGAIN || ErrNo == EINTR)
177349cc55cSDimitry Andric continue;
178349cc55cSDimitry Andric else
179349cc55cSDimitry Andric return ErrNo;
180349cc55cSDimitry Andric }
181349cc55cSDimitry Andric Completed += Written;
182349cc55cSDimitry Andric }
183349cc55cSDimitry Andric return 0;
184349cc55cSDimitry Andric }
185349cc55cSDimitry Andric
listenLoop()186349cc55cSDimitry Andric void FDSimpleRemoteEPCTransport::listenLoop() {
187349cc55cSDimitry Andric Error Err = Error::success();
188349cc55cSDimitry Andric do {
189349cc55cSDimitry Andric
190349cc55cSDimitry Andric char HeaderBuffer[FDMsgHeader::Size];
191349cc55cSDimitry Andric // Read the header buffer.
192349cc55cSDimitry Andric {
193349cc55cSDimitry Andric bool IsEOF = false;
194349cc55cSDimitry Andric if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
195349cc55cSDimitry Andric Err = joinErrors(std::move(Err), std::move(Err2));
196349cc55cSDimitry Andric break;
197349cc55cSDimitry Andric }
198349cc55cSDimitry Andric if (IsEOF)
199349cc55cSDimitry Andric break;
200349cc55cSDimitry Andric }
201349cc55cSDimitry Andric
202349cc55cSDimitry Andric // Decode header buffer.
203349cc55cSDimitry Andric uint64_t MsgSize;
204349cc55cSDimitry Andric SimpleRemoteEPCOpcode OpC;
205349cc55cSDimitry Andric uint64_t SeqNo;
206349cc55cSDimitry Andric ExecutorAddr TagAddr;
207349cc55cSDimitry Andric
208349cc55cSDimitry Andric MsgSize =
209349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
210349cc55cSDimitry Andric OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
211349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
212349cc55cSDimitry Andric SeqNo =
213349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
214349cc55cSDimitry Andric TagAddr.setValue(
215349cc55cSDimitry Andric *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
216349cc55cSDimitry Andric
217349cc55cSDimitry Andric if (MsgSize < FDMsgHeader::Size) {
218349cc55cSDimitry Andric Err = joinErrors(std::move(Err),
219349cc55cSDimitry Andric make_error<StringError>("Message size too small",
220349cc55cSDimitry Andric inconvertibleErrorCode()));
221349cc55cSDimitry Andric break;
222349cc55cSDimitry Andric }
223349cc55cSDimitry Andric
224349cc55cSDimitry Andric // Read the argument bytes.
225349cc55cSDimitry Andric SimpleRemoteEPCArgBytesVector ArgBytes;
226349cc55cSDimitry Andric ArgBytes.resize(MsgSize - FDMsgHeader::Size);
227349cc55cSDimitry Andric if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
228349cc55cSDimitry Andric Err = joinErrors(std::move(Err), std::move(Err2));
229349cc55cSDimitry Andric break;
230349cc55cSDimitry Andric }
231349cc55cSDimitry Andric
232349cc55cSDimitry Andric if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
233349cc55cSDimitry Andric if (*Action == SimpleRemoteEPCTransportClient::EndSession)
234349cc55cSDimitry Andric break;
235349cc55cSDimitry Andric } else {
236349cc55cSDimitry Andric Err = joinErrors(std::move(Err), Action.takeError());
237349cc55cSDimitry Andric break;
238349cc55cSDimitry Andric }
239349cc55cSDimitry Andric } while (true);
240349cc55cSDimitry Andric
241349cc55cSDimitry Andric // Attempt to close FDs, set Disconnected to true so that subsequent
242349cc55cSDimitry Andric // sendMessage calls fail.
243349cc55cSDimitry Andric disconnect();
244349cc55cSDimitry Andric
245349cc55cSDimitry Andric // Call up to the client to handle the disconnection.
246349cc55cSDimitry Andric C.handleDisconnect(std::move(Err));
247349cc55cSDimitry Andric }
248349cc55cSDimitry Andric
249349cc55cSDimitry Andric } // end namespace orc
250349cc55cSDimitry Andric } // end namespace llvm
251