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