1 //===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===//
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
7 //===----------------------------------------------------------------------===//
9 // Message definitions and other utilities for SimpleRemoteEPC and
10 // SimpleRemoteEPCServer.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/FormatVariadic.h"
18 #if !defined(_MSC_VER) && !defined(__MINGW32__)
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);
38 namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
{
40 const char *ExecutorSessionObjectName
=
41 "__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
42 const char *DispatchFnName
= "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
44 } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
46 SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {}
47 SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {}
49 Expected
<std::unique_ptr
<FDSimpleRemoteEPCTransport
>>
50 FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient
&C
, int InFD
,
52 #if LLVM_ENABLE_THREADS
54 return make_error
<StringError
>("Invalid input file descriptor " +
56 inconvertibleErrorCode());
58 return make_error
<StringError
>("Invalid output file descriptor " +
60 inconvertibleErrorCode());
61 std::unique_ptr
<FDSimpleRemoteEPCTransport
> FDT(
62 new FDSimpleRemoteEPCTransport(C
, InFD
, OutFD
));
63 return std::move(FDT
);
65 return make_error
<StringError
>("FD-based SimpleRemoteEPC transport requires "
66 "thread support, but llvm was built with "
67 "LLVM_ENABLE_THREADS=Off",
68 inconvertibleErrorCode());
72 FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
73 #if LLVM_ENABLE_THREADS
74 ListenerThread
.join();
78 Error
FDSimpleRemoteEPCTransport::start() {
79 #if LLVM_ENABLE_THREADS
80 ListenerThread
= std::thread([this]() { listenLoop(); });
81 return Error::success();
83 llvm_unreachable("Should not be called with LLVM_ENABLE_THREADS=Off");
86 Error
FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC
,
89 ArrayRef
<char> ArgBytes
) {
90 char HeaderBuffer
[FDMsgHeader::Size
];
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
)) =
100 std::lock_guard
<std::mutex
> Lock(M
);
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();
111 void FDSimpleRemoteEPCTransport::disconnect() {
113 return; // Return if already disconnected.
116 bool CloseOutFD
= InFD
!= OutFD
;
119 while (close(InFD
) == -1) {
126 while (close(OutFD
) == -1) {
133 static Error
makeUnexpectedEOFError() {
134 return make_error
<StringError
>("Unexpected end-of-file",
135 inconvertibleErrorCode());
138 Error
FDSimpleRemoteEPCTransport::readBytes(char *Dst
, size_t Size
,
140 assert(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
);
147 if (Completed
== 0 && IsEOF
) {
149 return Error::success();
151 return makeUnexpectedEOFError();
152 } else if (ErrNo
== EAGAIN
|| ErrNo
== EINTR
)
155 std::lock_guard
<std::mutex
> Lock(M
);
156 if (Disconnected
&& IsEOF
) { // disconnect called, pretend this is EOF.
158 return Error::success();
160 return errorCodeToError(
161 std::error_code(ErrNo
, std::generic_category()));
166 return Error::success();
169 int FDSimpleRemoteEPCTransport::writeBytes(const char *Src
, size_t Size
) {
170 assert(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
);
176 if (ErrNo
== EAGAIN
|| ErrNo
== EINTR
)
181 Completed
+= Written
;
186 void FDSimpleRemoteEPCTransport::listenLoop() {
187 Error Err
= Error::success();
190 char HeaderBuffer
[FDMsgHeader::Size
];
191 // Read the header buffer.
194 if (auto Err2
= readBytes(HeaderBuffer
, FDMsgHeader::Size
, &IsEOF
)) {
195 Err
= joinErrors(std::move(Err
), std::move(Err2
));
202 // Decode header buffer.
204 SimpleRemoteEPCOpcode OpC
;
206 ExecutorAddr TagAddr
;
209 *((support::ulittle64_t
*)(HeaderBuffer
+ FDMsgHeader::MsgSizeOffset
));
210 OpC
= static_cast<SimpleRemoteEPCOpcode
>(static_cast<uint64_t>(
211 *((support::ulittle64_t
*)(HeaderBuffer
+ FDMsgHeader::OpCOffset
))));
213 *((support::ulittle64_t
*)(HeaderBuffer
+ FDMsgHeader::SeqNoOffset
));
215 *((support::ulittle64_t
*)(HeaderBuffer
+ FDMsgHeader::TagAddrOffset
)));
217 if (MsgSize
< FDMsgHeader::Size
) {
218 Err
= joinErrors(std::move(Err
),
219 make_error
<StringError
>("Message size too small",
220 inconvertibleErrorCode()));
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
));
232 if (auto Action
= C
.handleMessage(OpC
, SeqNo
, TagAddr
, ArgBytes
)) {
233 if (*Action
== SimpleRemoteEPCTransportClient::EndSession
)
236 Err
= joinErrors(std::move(Err
), Action
.takeError());
241 // Attempt to close FDs, set Disconnected to true so that subsequent
242 // sendMessage calls fail.
245 // Call up to the client to handle the disconnection.
246 C
.handleDisconnect(std::move(Err
));
249 } // end namespace orc
250 } // end namespace llvm