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