xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp (revision 1f4d91ecb8529678a3d3919d7523743bd21942ca)
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"
15*89e6a288SDaniil Fukalov #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
16bb72f073SLang Hames #include "llvm/Support/Endian.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 
463a3cb929SKazu Hirata SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default;
473a3cb929SKazu Hirata SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default;
48bb72f073SLang Hames 
49bb72f073SLang Hames Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
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 
72bb72f073SLang Hames FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
73bb72f073SLang Hames #if LLVM_ENABLE_THREADS
74bb72f073SLang Hames   ListenerThread.join();
75bb72f073SLang Hames #endif
76bb72f073SLang Hames }
77bb72f073SLang Hames 
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 
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 
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 
133bb72f073SLang Hames static Error makeUnexpectedEOFError() {
134bb72f073SLang Hames   return make_error<StringError>("Unexpected end-of-file",
135bb72f073SLang Hames                                  inconvertibleErrorCode());
136bb72f073SLang Hames }
137bb72f073SLang Hames 
138bb72f073SLang Hames Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
139bb72f073SLang Hames                                             bool *IsEOF) {
140d6c9b3ccSLang Hames   assert((Size == 0 || 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 
169bb72f073SLang Hames int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
170d6c9b3ccSLang Hames   assert((Size == 0 || 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 
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