LLVM  14.0.0git
SimpleRemoteEPCUtils.cpp
Go to the documentation of this file.
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 
15 #include "llvm/Support/Endian.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 
41  "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42 const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
43 
44 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
45 
48 
51  int OutFD) {
52 #if LLVM_ENABLE_THREADS
53  if (InFD == -1)
54  return make_error<StringError>("Invalid input file descriptor " +
55  Twine(InFD),
57  if (OutFD == -1)
58  return make_error<StringError>("Invalid output file descriptor " +
59  Twine(OutFD),
61  std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
62  new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
63  return std::move(FDT);
64 #else
65  return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "
66  "thread support, but llvm was built with "
67  "LLVM_ENABLE_THREADS=Off",
69 #endif
70 }
71 
73 #if LLVM_ENABLE_THREADS
74  ListenerThread.join();
75 #endif
76 }
77 
79 #if LLVM_ENABLE_THREADS
80  ListenerThread = std::thread([this]() { listenLoop(); });
81  return Error::success();
82 #endif
83  llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off");
84 }
85 
87  uint64_t SeqNo,
88  ExecutorAddr TagAddr,
89  ArrayRef<char> ArgBytes) {
90  char HeaderBuffer[FDMsgHeader::Size];
91 
92  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
93  FDMsgHeader::Size + ArgBytes.size();
94  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
95  static_cast<uint64_t>(OpC);
96  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
97  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
98  TagAddr.getValue();
99 
100  std::lock_guard<std::mutex> Lock(M);
101  if (Disconnected)
102  return make_error<StringError>("FD-transport disconnected",
104  if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
105  return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
106  if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
107  return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
108  return Error::success();
109 }
110 
112  if (Disconnected)
113  return; // Return if already disconnected.
114 
115  Disconnected = true;
116  bool CloseOutFD = InFD != OutFD;
117 
118  // Close InFD.
119  while (close(InFD) == -1) {
120  if (errno == EBADF)
121  break;
122  }
123 
124  // Close OutFD.
125  if (CloseOutFD) {
126  while (close(OutFD) == -1) {
127  if (errno == EBADF)
128  break;
129  }
130  }
131 }
132 
134  return make_error<StringError>("Unexpected end-of-file",
136 }
137 
138 Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
139  bool *IsEOF) {
140  assert(Dst && "Attempt to read into null.");
141  ssize_t Completed = 0;
142  while (Completed < static_cast<ssize_t>(Size)) {
143  ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
144  if (Read <= 0) {
145  auto ErrNo = errno;
146  if (Read == 0) {
147  if (Completed == 0 && IsEOF) {
148  *IsEOF = true;
149  return Error::success();
150  } else
151  return makeUnexpectedEOFError();
152  } else if (ErrNo == EAGAIN || ErrNo == EINTR)
153  continue;
154  else {
155  std::lock_guard<std::mutex> Lock(M);
156  if (Disconnected && IsEOF) { // disconnect called, pretend this is EOF.
157  *IsEOF = true;
158  return Error::success();
159  }
160  return errorCodeToError(
161  std::error_code(ErrNo, std::generic_category()));
162  }
163  }
164  Completed += Read;
165  }
166  return Error::success();
167 }
168 
169 int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
170  assert(Src && "Attempt to append from null.");
171  ssize_t Completed = 0;
172  while (Completed < static_cast<ssize_t>(Size)) {
173  ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
174  if (Written < 0) {
175  auto ErrNo = errno;
176  if (ErrNo == EAGAIN || ErrNo == EINTR)
177  continue;
178  else
179  return ErrNo;
180  }
181  Completed += Written;
182  }
183  return 0;
184 }
185 
186 void FDSimpleRemoteEPCTransport::listenLoop() {
187  Error Err = Error::success();
188  do {
189 
190  char HeaderBuffer[FDMsgHeader::Size];
191  // Read the header buffer.
192  {
193  bool IsEOF = false;
194  if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
195  Err = joinErrors(std::move(Err), std::move(Err2));
196  break;
197  }
198  if (IsEOF)
199  break;
200  }
201 
202  // Decode header buffer.
203  uint64_t MsgSize;
205  uint64_t SeqNo;
206  ExecutorAddr TagAddr;
207 
208  MsgSize =
209  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
210  OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
211  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
212  SeqNo =
213  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
214  TagAddr.setValue(
215  *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
216 
217  if (MsgSize < FDMsgHeader::Size) {
218  Err = joinErrors(std::move(Err),
219  make_error<StringError>("Message size too small",
221  break;
222  }
223 
224  // Read the argument bytes.
226  ArgBytes.resize(MsgSize - FDMsgHeader::Size);
227  if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
228  Err = joinErrors(std::move(Err), std::move(Err2));
229  break;
230  }
231 
232  if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
234  break;
235  } else {
236  Err = joinErrors(std::move(Err), Action.takeError());
237  break;
238  }
239  } while (true);
240 
241  // Attempt to close FDs, set Disconnected to true so that subsequent
242  // sendMessage calls fail.
243  disconnect();
244 
245  // Call up to the client to handle the disconnection.
246  C.handleDisconnect(std::move(Err));
247 }
248 
249 } // end namespace orc
250 } // end namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:37
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
llvm::orc::FDSimpleRemoteEPCTransport::sendMessage
Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, ArrayRef< char > ArgBytes) override
Send a SimpleRemoteEPC message.
Definition: SimpleRemoteEPCUtils.cpp:86
llvm::orc::SimpleRemoteEPCOpcode
SimpleRemoteEPCOpcode
Definition: SimpleRemoteEPCUtils.h:37
llvm::lltok::Error
@ Error
Definition: LLToken.h:21
llvm::support::detail::packed_endian_specific_integral
Definition: Endian.h:206
llvm::write
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
Definition: DWP.cpp:535
SimpleRemoteEPCUtils.h
llvm::orc::makeUnexpectedEOFError
static Error makeUnexpectedEOFError()
Definition: SimpleRemoteEPCUtils.cpp:133
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::orc::ExecutorAddr::getValue
uint64_t getValue() const
Definition: ExecutorAddress.h:60
llvm::orc::FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport
~FDSimpleRemoteEPCTransport() override
Definition: SimpleRemoteEPCUtils.cpp:72
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::ArrayRef::data
const T * data() const
Definition: ArrayRef.h:162
llvm::Lock
static sys::Mutex Lock
Definition: NVPTXUtilities.cpp:39
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
llvm::orc::SimpleRemoteEPCDefaultBootstrapSymbolNames::ExecutorSessionObjectName
const char * ExecutorSessionObjectName
Definition: SimpleRemoteEPCUtils.cpp:40
llvm::orc::FDSimpleRemoteEPCTransport::Create
static Expected< std::unique_ptr< FDSimpleRemoteEPCTransport > > Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD)
Create a FDSimpleRemoteEPCTransport using the given FDs for reading (InFD) and writing (OutFD).
Definition: SimpleRemoteEPCUtils.cpp:50
FormatVariadic.h
llvm::pdb::OMFSegDescFlags::Read
@ Read
uint64_t
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:428
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::orc::FDSimpleRemoteEPCTransport::start
Error start() override
Called during setup of the client to indicate that the client is ready to receive messages.
Definition: SimpleRemoteEPCUtils.cpp:78
llvm::ArrayRef< char >
llvm::orc::SimpleRemoteEPCArgBytesVector
SmallVector< char, 128 > SimpleRemoteEPCArgBytesVector
Definition: SimpleRemoteEPCUtils.h:51
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
llvm::orc::SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport
virtual ~SimpleRemoteEPCTransport()
Definition: SimpleRemoteEPCUtils.cpp:47
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::inconvertibleErrorCode
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:77
llvm::support::endian::read
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition: Endian.h:63
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::orc::SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient
virtual ~SimpleRemoteEPCTransportClient()
Definition: SimpleRemoteEPCUtils.cpp:46
llvm::support::ulittle64_t
detail::packed_endian_specific_integral< uint64_t, little, unaligned > ulittle64_t
Definition: Endian.h:274
llvm::orc::SimpleRemoteEPCDefaultBootstrapSymbolNames::DispatchFnName
const char * DispatchFnName
Definition: SimpleRemoteEPCUtils.cpp:42
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
llvm::orc::SimpleRemoteEPCTransportClient
Definition: SimpleRemoteEPCUtils.h:53
Endian.h
llvm::orc::SimpleRemoteEPCTransportClient::EndSession
@ EndSession
Definition: SimpleRemoteEPCUtils.h:55
llvm::orc::FDSimpleRemoteEPCTransport
Uses read/write on FileDescriptors for transport.
Definition: SimpleRemoteEPCUtils.h:102
llvm::orc::FDSimpleRemoteEPCTransport::disconnect
void disconnect() override
Trigger disconnection from the transport.
Definition: SimpleRemoteEPCUtils.cpp:111