//===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Message definitions and other utilities for SimpleRemoteEPC and // SimpleRemoteEPCServer. // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FormatVariadic.h" #if !defined(_MSC_VER) && !defined(__MINGW32__) #include #else #include #endif namespace { struct FDMsgHeader { static constexpr unsigned MsgSizeOffset = 0; static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t); static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t); static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t); static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t); }; } // namespace namespace llvm { namespace orc { namespace SimpleRemoteEPCDefaultBootstrapSymbolNames { const char *ExecutorSessionObjectName = "__llvm_orc_SimpleRemoteEPC_dispatch_ctx"; const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn"; } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {} SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {} Expected> FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD) { #if LLVM_ENABLE_THREADS if (InFD == -1) return make_error("Invalid input file descriptor " + Twine(InFD), inconvertibleErrorCode()); if (OutFD == -1) return make_error("Invalid output file descriptor " + Twine(OutFD), inconvertibleErrorCode()); std::unique_ptr FDT( new FDSimpleRemoteEPCTransport(C, InFD, OutFD)); return std::move(FDT); #else return make_error("FD-based SimpleRemoteEPC transport requires " "thread support, but llvm was built with " "LLVM_ENABLE_THREADS=Off", inconvertibleErrorCode()); #endif } FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() { #if LLVM_ENABLE_THREADS ListenerThread.join(); #endif } Error FDSimpleRemoteEPCTransport::start() { #if LLVM_ENABLE_THREADS ListenerThread = std::thread([this]() { listenLoop(); }); return Error::success(); #endif llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off"); } Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, ArrayRef ArgBytes) { char HeaderBuffer[FDMsgHeader::Size]; *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) = FDMsgHeader::Size + ArgBytes.size(); *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) = static_cast(OpC); *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo; *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) = TagAddr.getValue(); std::lock_guard Lock(M); if (Disconnected) return make_error("FD-transport disconnected", inconvertibleErrorCode()); if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size)) return errorCodeToError(std::error_code(ErrNo, std::generic_category())); if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size())) return errorCodeToError(std::error_code(ErrNo, std::generic_category())); return Error::success(); } void FDSimpleRemoteEPCTransport::disconnect() { if (Disconnected) return; // Return if already disconnected. Disconnected = true; bool CloseOutFD = InFD != OutFD; // Close InFD. while (close(InFD) == -1) { if (errno == EBADF) break; } // Close OutFD. if (CloseOutFD) { while (close(OutFD) == -1) { if (errno == EBADF) break; } } } static Error makeUnexpectedEOFError() { return make_error("Unexpected end-of-file", inconvertibleErrorCode()); } Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size, bool *IsEOF) { assert(Dst && "Attempt to read into null."); ssize_t Completed = 0; while (Completed < static_cast(Size)) { ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); if (Read <= 0) { auto ErrNo = errno; if (Read == 0) { if (Completed == 0 && IsEOF) { *IsEOF = true; return Error::success(); } else return makeUnexpectedEOFError(); } else if (ErrNo == EAGAIN || ErrNo == EINTR) continue; else { std::lock_guard Lock(M); if (Disconnected && IsEOF) { // disconnect called, pretend this is EOF. *IsEOF = true; return Error::success(); } return errorCodeToError( std::error_code(ErrNo, std::generic_category())); } } Completed += Read; } return Error::success(); } int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) { assert(Src && "Attempt to append from null."); ssize_t Completed = 0; while (Completed < static_cast(Size)) { ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); if (Written < 0) { auto ErrNo = errno; if (ErrNo == EAGAIN || ErrNo == EINTR) continue; else return ErrNo; } Completed += Written; } return 0; } void FDSimpleRemoteEPCTransport::listenLoop() { Error Err = Error::success(); do { char HeaderBuffer[FDMsgHeader::Size]; // Read the header buffer. { bool IsEOF = false; if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) { Err = joinErrors(std::move(Err), std::move(Err2)); break; } if (IsEOF) break; } // Decode header buffer. uint64_t MsgSize; SimpleRemoteEPCOpcode OpC; uint64_t SeqNo; ExecutorAddr TagAddr; MsgSize = *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)); OpC = static_cast(static_cast( *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)))); SeqNo = *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)); TagAddr.setValue( *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset))); if (MsgSize < FDMsgHeader::Size) { Err = joinErrors(std::move(Err), make_error("Message size too small", inconvertibleErrorCode())); break; } // Read the argument bytes. SimpleRemoteEPCArgBytesVector ArgBytes; ArgBytes.resize(MsgSize - FDMsgHeader::Size); if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) { Err = joinErrors(std::move(Err), std::move(Err2)); break; } if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) { if (*Action == SimpleRemoteEPCTransportClient::EndSession) break; } else { Err = joinErrors(std::move(Err), Action.takeError()); break; } } while (true); // Attempt to close FDs, set Disconnected to true so that subsequent // sendMessage calls fail. disconnect(); // Call up to the client to handle the disconnection. C.handleDisconnect(std::move(Err)); } } // end namespace orc } // end namespace llvm