1bb72f073SLang Hames //===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===// 2bb72f073SLang Hames // 3bb72f073SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bb72f073SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5bb72f073SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bb72f073SLang Hames // 7bb72f073SLang Hames //===----------------------------------------------------------------------===// 8bb72f073SLang Hames // 9bb72f073SLang Hames // Message definitions and other utilities for SimpleRemoteEPC and 10bb72f073SLang Hames // SimpleRemoteEPCServer. 11bb72f073SLang Hames // 12bb72f073SLang Hames //===----------------------------------------------------------------------===// 13bb72f073SLang Hames 14bb72f073SLang Hames #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h" 15*89e6a288SDaniil Fukalov #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS 16bb72f073SLang Hames #include "llvm/Support/Endian.h" 17bb72f073SLang Hames 18bb72f073SLang Hames #if !defined(_MSC_VER) && !defined(__MINGW32__) 19bb72f073SLang Hames #include <unistd.h> 20bb72f073SLang Hames #else 21bb72f073SLang Hames #include <io.h> 22bb72f073SLang Hames #endif 23bb72f073SLang Hames 24bb72f073SLang Hames namespace { 25bb72f073SLang Hames 26bb72f073SLang Hames struct FDMsgHeader { 27bb72f073SLang Hames static constexpr unsigned MsgSizeOffset = 0; 28bb72f073SLang Hames static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t); 29bb72f073SLang Hames static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t); 30bb72f073SLang Hames static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t); 31bb72f073SLang Hames static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t); 32bb72f073SLang Hames }; 33bb72f073SLang Hames 34bb72f073SLang Hames } // namespace 35bb72f073SLang Hames 36bb72f073SLang Hames namespace llvm { 37bb72f073SLang Hames namespace orc { 38bb72f073SLang Hames namespace SimpleRemoteEPCDefaultBootstrapSymbolNames { 39bb72f073SLang Hames 40bb72f073SLang Hames const char *ExecutorSessionObjectName = 41bb72f073SLang Hames "__llvm_orc_SimpleRemoteEPC_dispatch_ctx"; 42bb72f073SLang Hames const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn"; 43bb72f073SLang Hames 44bb72f073SLang Hames } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames 45bb72f073SLang Hames 463a3cb929SKazu Hirata SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default; 473a3cb929SKazu Hirata SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default; 48bb72f073SLang Hames 49bb72f073SLang Hames Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>> 50bb72f073SLang Hames FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD, 51bb72f073SLang Hames int OutFD) { 52bb72f073SLang Hames #if LLVM_ENABLE_THREADS 53bb72f073SLang Hames if (InFD == -1) 54bb72f073SLang Hames return make_error<StringError>("Invalid input file descriptor " + 55bb72f073SLang Hames Twine(InFD), 56bb72f073SLang Hames inconvertibleErrorCode()); 57bb72f073SLang Hames if (OutFD == -1) 58bb72f073SLang Hames return make_error<StringError>("Invalid output file descriptor " + 59bb72f073SLang Hames Twine(OutFD), 60bb72f073SLang Hames inconvertibleErrorCode()); 61bb72f073SLang Hames std::unique_ptr<FDSimpleRemoteEPCTransport> FDT( 62bb72f073SLang Hames new FDSimpleRemoteEPCTransport(C, InFD, OutFD)); 63d193d237SLang Hames return std::move(FDT); 64bb72f073SLang Hames #else 65bb72f073SLang Hames return make_error<StringError>("FD-based SimpleRemoteEPC transport requires " 66bb72f073SLang Hames "thread support, but llvm was built with " 67bb72f073SLang Hames "LLVM_ENABLE_THREADS=Off", 68bb72f073SLang Hames inconvertibleErrorCode()); 69bb72f073SLang Hames #endif 70bb72f073SLang Hames } 71bb72f073SLang Hames 72bb72f073SLang Hames FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() { 73bb72f073SLang Hames #if LLVM_ENABLE_THREADS 74bb72f073SLang Hames ListenerThread.join(); 75bb72f073SLang Hames #endif 76bb72f073SLang Hames } 77bb72f073SLang Hames 784b37462aSLang Hames Error FDSimpleRemoteEPCTransport::start() { 794b37462aSLang Hames #if LLVM_ENABLE_THREADS 804b37462aSLang Hames ListenerThread = std::thread([this]() { listenLoop(); }); 814b37462aSLang Hames return Error::success(); 824b37462aSLang Hames #endif 834b37462aSLang Hames llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off"); 844b37462aSLang Hames } 854b37462aSLang Hames 86bb72f073SLang Hames Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC, 87bb72f073SLang Hames uint64_t SeqNo, 88ef391df2SLang Hames ExecutorAddr TagAddr, 89bb72f073SLang Hames ArrayRef<char> ArgBytes) { 90bb72f073SLang Hames char HeaderBuffer[FDMsgHeader::Size]; 91bb72f073SLang Hames 92bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) = 93bb72f073SLang Hames FDMsgHeader::Size + ArgBytes.size(); 94bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) = 95bb72f073SLang Hames static_cast<uint64_t>(OpC); 96bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo; 97bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) = 98bb72f073SLang Hames TagAddr.getValue(); 99bb72f073SLang Hames 100bb72f073SLang Hames std::lock_guard<std::mutex> Lock(M); 1014b37462aSLang Hames if (Disconnected) 102bb72f073SLang Hames return make_error<StringError>("FD-transport disconnected", 103bb72f073SLang Hames inconvertibleErrorCode()); 104bb72f073SLang Hames if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size)) 105bb72f073SLang Hames return errorCodeToError(std::error_code(ErrNo, std::generic_category())); 106bb72f073SLang Hames if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size())) 107bb72f073SLang Hames return errorCodeToError(std::error_code(ErrNo, std::generic_category())); 108bb72f073SLang Hames return Error::success(); 109bb72f073SLang Hames } 110bb72f073SLang Hames 111bb72f073SLang Hames void FDSimpleRemoteEPCTransport::disconnect() { 1124b37462aSLang Hames if (Disconnected) 1134b37462aSLang Hames return; // Return if already disconnected. 114bb72f073SLang Hames 1154b37462aSLang Hames Disconnected = true; 1164b37462aSLang Hames bool CloseOutFD = InFD != OutFD; 117bb72f073SLang Hames 118bb72f073SLang Hames // Close InFD. 1194b37462aSLang Hames while (close(InFD) == -1) { 120bb72f073SLang Hames if (errno == EBADF) 121bb72f073SLang Hames break; 122bb72f073SLang Hames } 123bb72f073SLang Hames 124bb72f073SLang Hames // Close OutFD. 1254b37462aSLang Hames if (CloseOutFD) { 1264b37462aSLang Hames while (close(OutFD) == -1) { 127bb72f073SLang Hames if (errno == EBADF) 128bb72f073SLang Hames break; 129bb72f073SLang Hames } 130bb72f073SLang Hames } 131bb72f073SLang Hames } 132bb72f073SLang Hames 133bb72f073SLang Hames static Error makeUnexpectedEOFError() { 134bb72f073SLang Hames return make_error<StringError>("Unexpected end-of-file", 135bb72f073SLang Hames inconvertibleErrorCode()); 136bb72f073SLang Hames } 137bb72f073SLang Hames 138bb72f073SLang Hames Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size, 139bb72f073SLang Hames bool *IsEOF) { 140d6c9b3ccSLang Hames assert((Size == 0 || Dst) && "Attempt to read into null."); 141bb72f073SLang Hames ssize_t Completed = 0; 142bb72f073SLang Hames while (Completed < static_cast<ssize_t>(Size)) { 143bb72f073SLang Hames ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); 144bb72f073SLang Hames if (Read <= 0) { 145bb72f073SLang Hames auto ErrNo = errno; 146bb72f073SLang Hames if (Read == 0) { 147bb72f073SLang Hames if (Completed == 0 && IsEOF) { 148bb72f073SLang Hames *IsEOF = true; 149bb72f073SLang Hames return Error::success(); 150bb72f073SLang Hames } else 151bb72f073SLang Hames return makeUnexpectedEOFError(); 152bb72f073SLang Hames } else if (ErrNo == EAGAIN || ErrNo == EINTR) 153bb72f073SLang Hames continue; 154bb72f073SLang Hames else { 155bb72f073SLang Hames std::lock_guard<std::mutex> Lock(M); 1564b37462aSLang Hames if (Disconnected && IsEOF) { // disconnect called, pretend this is EOF. 157bb72f073SLang Hames *IsEOF = true; 158bb72f073SLang Hames return Error::success(); 159bb72f073SLang Hames } 160bb72f073SLang Hames return errorCodeToError( 161bb72f073SLang Hames std::error_code(ErrNo, std::generic_category())); 162bb72f073SLang Hames } 163bb72f073SLang Hames } 164bb72f073SLang Hames Completed += Read; 165bb72f073SLang Hames } 166bb72f073SLang Hames return Error::success(); 167bb72f073SLang Hames } 168bb72f073SLang Hames 169bb72f073SLang Hames int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) { 170d6c9b3ccSLang Hames assert((Size == 0 || Src) && "Attempt to append from null."); 171bb72f073SLang Hames ssize_t Completed = 0; 172bb72f073SLang Hames while (Completed < static_cast<ssize_t>(Size)) { 173bb72f073SLang Hames ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); 174bb72f073SLang Hames if (Written < 0) { 175bb72f073SLang Hames auto ErrNo = errno; 176bb72f073SLang Hames if (ErrNo == EAGAIN || ErrNo == EINTR) 177bb72f073SLang Hames continue; 178bb72f073SLang Hames else 179bb72f073SLang Hames return ErrNo; 180bb72f073SLang Hames } 181bb72f073SLang Hames Completed += Written; 182bb72f073SLang Hames } 183bb72f073SLang Hames return 0; 184bb72f073SLang Hames } 185bb72f073SLang Hames 186bb72f073SLang Hames void FDSimpleRemoteEPCTransport::listenLoop() { 187bb72f073SLang Hames Error Err = Error::success(); 188bb72f073SLang Hames do { 189bb72f073SLang Hames 190bb72f073SLang Hames char HeaderBuffer[FDMsgHeader::Size]; 191bb72f073SLang Hames // Read the header buffer. 192bb72f073SLang Hames { 19303710492SLang Hames bool IsEOF = false; 194bb72f073SLang Hames if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) { 195bb72f073SLang Hames Err = joinErrors(std::move(Err), std::move(Err2)); 196bb72f073SLang Hames break; 197bb72f073SLang Hames } 198bb72f073SLang Hames if (IsEOF) 199bb72f073SLang Hames break; 200bb72f073SLang Hames } 201bb72f073SLang Hames 202bb72f073SLang Hames // Decode header buffer. 203bb72f073SLang Hames uint64_t MsgSize; 204bb72f073SLang Hames SimpleRemoteEPCOpcode OpC; 205bb72f073SLang Hames uint64_t SeqNo; 206ef391df2SLang Hames ExecutorAddr TagAddr; 207bb72f073SLang Hames 208bb72f073SLang Hames MsgSize = 209bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)); 210bb72f073SLang Hames OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>( 211bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)))); 212bb72f073SLang Hames SeqNo = 213bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)); 214bb72f073SLang Hames TagAddr.setValue( 215bb72f073SLang Hames *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset))); 216bb72f073SLang Hames 217bb72f073SLang Hames if (MsgSize < FDMsgHeader::Size) { 218bb72f073SLang Hames Err = joinErrors(std::move(Err), 219767b328eSStefan Gränitz make_error<StringError>("Message size too small", 220bb72f073SLang Hames inconvertibleErrorCode())); 221bb72f073SLang Hames break; 222bb72f073SLang Hames } 223bb72f073SLang Hames 224bb72f073SLang Hames // Read the argument bytes. 225bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes; 226bb72f073SLang Hames ArgBytes.resize(MsgSize - FDMsgHeader::Size); 227bb72f073SLang Hames if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) { 228bb72f073SLang Hames Err = joinErrors(std::move(Err), std::move(Err2)); 229bb72f073SLang Hames break; 230bb72f073SLang Hames } 231bb72f073SLang Hames 232bb72f073SLang Hames if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) { 233bb72f073SLang Hames if (*Action == SimpleRemoteEPCTransportClient::EndSession) 234bb72f073SLang Hames break; 235bb72f073SLang Hames } else { 236bb72f073SLang Hames Err = joinErrors(std::move(Err), Action.takeError()); 237bb72f073SLang Hames break; 238bb72f073SLang Hames } 239bb72f073SLang Hames } while (true); 240bb72f073SLang Hames 24117a0858fSLang Hames // Attempt to close FDs, set Disconnected to true so that subsequent 24217a0858fSLang Hames // sendMessage calls fail. 24317a0858fSLang Hames disconnect(); 24417a0858fSLang Hames 24517a0858fSLang Hames // Call up to the client to handle the disconnection. 246bb72f073SLang Hames C.handleDisconnect(std::move(Err)); 247bb72f073SLang Hames } 248bb72f073SLang Hames 249bb72f073SLang Hames } // end namespace orc 250bb72f073SLang Hames } // end namespace llvm 251