xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp (revision bb27e4564355243e479cab40885d6e0f7f640572)
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 
14 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/FormatVariadic.h"
17 
18 #if !defined(_MSC_VER) && !defined(__MINGW32__)
19 #include <unistd.h>
20 #else
21 #include <io.h>
22 #endif
23 
24 namespace {
25 
26 struct 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 
36 namespace llvm {
37 namespace orc {
38 namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
39 
40 const char *ExecutorSessionObjectName =
41     "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42 const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
43 
44 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
45 
46 SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {}
47 SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {}
48 
49 Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
50 FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,
51                                    int OutFD) {
52   if (InFD == -1)
53     return make_error<StringError>("Invalid input file descriptor " +
54                                        Twine(InFD),
55                                    inconvertibleErrorCode());
56   if (OutFD == -1)
57     return make_error<StringError>("Invalid output file descriptor " +
58                                        Twine(OutFD),
59                                    inconvertibleErrorCode());
60   std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
61       new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
62   return FDT;
63 }
64 
65 FDSimpleRemoteEPCTransport::FDSimpleRemoteEPCTransport(
66     SimpleRemoteEPCTransportClient &C, int InFD, int OutFD)
67     : C(C), InFD(InFD), OutFD(OutFD) {
68   ListenerThread = std::thread([this]() { listenLoop(); });
69 }
70 
71 FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
72   ListenerThread.join();
73 }
74 
75 Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
76                                               uint64_t SeqNo,
77                                               ExecutorAddress TagAddr,
78                                               ArrayRef<char> ArgBytes) {
79   char HeaderBuffer[FDMsgHeader::Size];
80 
81   *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
82       FDMsgHeader::Size + ArgBytes.size();
83   *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
84       static_cast<uint64_t>(OpC);
85   *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
86   *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
87       TagAddr.getValue();
88 
89   std::lock_guard<std::mutex> Lock(M);
90   if (OutFD == -1)
91     return make_error<StringError>("FD-transport disconnected",
92                                    inconvertibleErrorCode());
93   if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
94     return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
95   if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
96     return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
97   return Error::success();
98 }
99 
100 void FDSimpleRemoteEPCTransport::disconnect() {
101   int CloseInFD = -1, CloseOutFD = -1;
102   {
103     std::lock_guard<std::mutex> Lock(M);
104     std::swap(InFD, CloseInFD);
105     std::swap(OutFD, CloseOutFD);
106   }
107 
108   // If CloseOutFD == CloseInFD then set CloseOutFD to -1 up-front so that we
109   // don't double-close.
110   if (CloseOutFD == CloseInFD)
111     CloseOutFD = -1;
112 
113   // Close InFD.
114   if (CloseInFD != -1)
115     while (close(CloseInFD) == -1) {
116       if (errno == EBADF)
117         break;
118     }
119 
120   // Close OutFD.
121   if (CloseOutFD != -1) {
122     while (close(CloseOutFD) == -1) {
123       if (errno == EBADF)
124         break;
125     }
126   }
127 }
128 
129 static Error makeUnexpectedEOFError() {
130   return make_error<StringError>("Unexpected end-of-file",
131                                  inconvertibleErrorCode());
132 }
133 
134 Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
135                                             bool *IsEOF) {
136   assert(Dst && "Attempt to read into null.");
137   ssize_t Completed = 0;
138   while (Completed < static_cast<ssize_t>(Size)) {
139     ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
140     if (Read <= 0) {
141       auto ErrNo = errno;
142       if (Read == 0) {
143         if (Completed == 0 && IsEOF) {
144           *IsEOF = true;
145           return Error::success();
146         } else
147           return makeUnexpectedEOFError();
148       } else if (ErrNo == EAGAIN || ErrNo == EINTR)
149         continue;
150       else {
151         std::lock_guard<std::mutex> Lock(M);
152         if (InFD == -1 && IsEOF) { // Disconnected locally. Pretend this is EOF.
153           *IsEOF = true;
154           return Error::success();
155         }
156         return errorCodeToError(
157             std::error_code(ErrNo, std::generic_category()));
158       }
159     }
160     Completed += Read;
161   }
162   return Error::success();
163 }
164 
165 int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
166   assert(Src && "Attempt to append from null.");
167   ssize_t Completed = 0;
168   while (Completed < static_cast<ssize_t>(Size)) {
169     ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
170     if (Written < 0) {
171       auto ErrNo = errno;
172       if (ErrNo == EAGAIN || ErrNo == EINTR)
173         continue;
174       else
175         return ErrNo;
176     }
177     Completed += Written;
178   }
179   return 0;
180 }
181 
182 void FDSimpleRemoteEPCTransport::listenLoop() {
183   Error Err = Error::success();
184   do {
185 
186     char HeaderBuffer[FDMsgHeader::Size];
187     // Read the header buffer.
188     {
189       bool IsEOF;
190       if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
191         Err = joinErrors(std::move(Err), std::move(Err2));
192         break;
193       }
194       if (IsEOF)
195         break;
196     }
197 
198     // Decode header buffer.
199     uint64_t MsgSize;
200     SimpleRemoteEPCOpcode OpC;
201     uint64_t SeqNo;
202     ExecutorAddress TagAddr;
203 
204     MsgSize =
205         *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
206     OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
207         *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
208     SeqNo =
209         *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
210     TagAddr.setValue(
211         *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
212 
213     if (MsgSize < FDMsgHeader::Size) {
214       Err = joinErrors(std::move(Err),
215                        make_error<StringError>("Mesasge size too small",
216                                                inconvertibleErrorCode()));
217       break;
218     }
219 
220     // Read the argument bytes.
221     SimpleRemoteEPCArgBytesVector ArgBytes;
222     ArgBytes.resize(MsgSize - FDMsgHeader::Size);
223     if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
224       Err = joinErrors(std::move(Err), std::move(Err2));
225       break;
226     }
227 
228     if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
229       if (*Action == SimpleRemoteEPCTransportClient::EndSession)
230         break;
231     } else {
232       Err = joinErrors(std::move(Err), Action.takeError());
233       break;
234     }
235   } while (true);
236 
237   C.handleDisconnect(std::move(Err));
238 }
239 
240 } // end namespace orc
241 } // end namespace llvm
242