xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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