251 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Message definitions and other utilities for SimpleRemoteEPC and10// SimpleRemoteEPCServer.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"15#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS16#include "llvm/Support/Endian.h"17 18#if !defined(_MSC_VER) && !defined(__MINGW32__)19#include <unistd.h>20#else21#include <io.h>22#endif23 24namespace {25 26struct 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} // namespace35 36namespace llvm {37namespace orc {38namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {39 40const char *ExecutorSessionObjectName =41 "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";42const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";43 44} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames45 46SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default;47SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default;48 49Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>50FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,51 int OutFD) {52#if LLVM_ENABLE_THREADS53 if (InFD == -1)54 return make_error<StringError>("Invalid input file descriptor " +55 Twine(InFD),56 inconvertibleErrorCode());57 if (OutFD == -1)58 return make_error<StringError>("Invalid output file descriptor " +59 Twine(OutFD),60 inconvertibleErrorCode());61 std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(62 new FDSimpleRemoteEPCTransport(C, InFD, OutFD));63 return std::move(FDT);64#else65 return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "66 "thread support, but llvm was built with "67 "LLVM_ENABLE_THREADS=Off",68 inconvertibleErrorCode());69#endif70}71 72FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {73#if LLVM_ENABLE_THREADS74 ListenerThread.join();75#endif76}77 78Error FDSimpleRemoteEPCTransport::start() {79#if LLVM_ENABLE_THREADS80 ListenerThread = std::thread([this]() { listenLoop(); });81 return Error::success();82#endif83 llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off");84}85 86Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,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",103 inconvertibleErrorCode());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 111void FDSimpleRemoteEPCTransport::disconnect() {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 133static Error makeUnexpectedEOFError() {134 return make_error<StringError>("Unexpected end-of-file",135 inconvertibleErrorCode());136}137 138Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,139 bool *IsEOF) {140 assert((Size == 0 || 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 } else151 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 169int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {170 assert((Size == 0 || 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 else179 return ErrNo;180 }181 Completed += Written;182 }183 return 0;184}185 186void 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;204 SimpleRemoteEPCOpcode OpC;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",220 inconvertibleErrorCode()));221 break;222 }223 224 // Read the argument bytes.225 SimpleRemoteEPCArgBytesVector ArgBytes;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)) {233 if (*Action == SimpleRemoteEPCTransportClient::EndSession)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 subsequent242 // 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 orc250} // end namespace llvm251