SimpleRemoteEPCUtils.cpp 8.0 KB

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