[ORC] Remove ORC RPC.
With the removal of OrcRPCExecutorProcessControl and OrcRPCTPCServer in
6aeed7b19c the ORC RPC library no longer has any in-tree users.
Clients needing serialization for ORC should move to Simple Packed
Serialization (usually by adopting SimpleRemoteEPC for remote JITing).
This commit is contained in:
@@ -1,79 +0,0 @@
|
||||
//===- FDRawByteChannel.h - File descriptor based byte-channel -*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// File descriptor based RawByteChannel.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_FDRAWBYTECHANNEL_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_FDRAWBYTECHANNEL_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
/// Serialization channel that reads from and writes from file descriptors.
|
||||
class FDRawByteChannel final : public RawByteChannel {
|
||||
public:
|
||||
FDRawByteChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
|
||||
|
||||
llvm::Error readBytes(char *Dst, unsigned Size) override {
|
||||
assert(Dst && "Attempt to read into null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
|
||||
if (Read <= 0) {
|
||||
auto ErrNo = errno;
|
||||
if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
else
|
||||
return llvm::errorCodeToError(
|
||||
std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
Completed += Read;
|
||||
}
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error appendBytes(const char *Src, unsigned Size) override {
|
||||
assert(Src && "Attempt to append from null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
|
||||
if (Written < 0) {
|
||||
auto ErrNo = errno;
|
||||
if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
else
|
||||
return llvm::errorCodeToError(
|
||||
std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
Completed += Written;
|
||||
}
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error send() override { return llvm::Error::success(); }
|
||||
|
||||
private:
|
||||
int InFD, OutFD;
|
||||
};
|
||||
|
||||
} // namespace shared
|
||||
} // namespace orc
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_FDRAWBYTECHANNEL_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,183 +0,0 @@
|
||||
//===- RawByteChannel.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_RAWBYTECHANNEL_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_RAWBYTECHANNEL_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/Serialization.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
/// Interface for byte-streams to be used with ORC Serialization.
|
||||
class RawByteChannel {
|
||||
public:
|
||||
virtual ~RawByteChannel() = default;
|
||||
|
||||
/// Read Size bytes from the stream into *Dst.
|
||||
virtual Error readBytes(char *Dst, unsigned Size) = 0;
|
||||
|
||||
/// Read size bytes from *Src and append them to the stream.
|
||||
virtual Error appendBytes(const char *Src, unsigned Size) = 0;
|
||||
|
||||
/// Flush the stream if possible.
|
||||
virtual Error send() = 0;
|
||||
|
||||
/// Notify the channel that we're starting a message send.
|
||||
/// Locks the channel for writing.
|
||||
template <typename FunctionIdT, typename SequenceIdT>
|
||||
Error startSendMessage(const FunctionIdT &FnId, const SequenceIdT &SeqNo) {
|
||||
writeLock.lock();
|
||||
if (auto Err = serializeSeq(*this, FnId, SeqNo)) {
|
||||
writeLock.unlock();
|
||||
return Err;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Notify the channel that we're ending a message send.
|
||||
/// Unlocks the channel for writing.
|
||||
Error endSendMessage() {
|
||||
writeLock.unlock();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Notify the channel that we're starting a message receive.
|
||||
/// Locks the channel for reading.
|
||||
template <typename FunctionIdT, typename SequenceNumberT>
|
||||
Error startReceiveMessage(FunctionIdT &FnId, SequenceNumberT &SeqNo) {
|
||||
readLock.lock();
|
||||
if (auto Err = deserializeSeq(*this, FnId, SeqNo)) {
|
||||
readLock.unlock();
|
||||
return Err;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Notify the channel that we're ending a message receive.
|
||||
/// Unlocks the channel for reading.
|
||||
Error endReceiveMessage() {
|
||||
readLock.unlock();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Get the lock for stream reading.
|
||||
std::mutex &getReadLock() { return readLock; }
|
||||
|
||||
/// Get the lock for stream writing.
|
||||
std::mutex &getWriteLock() { return writeLock; }
|
||||
|
||||
private:
|
||||
std::mutex readLock, writeLock;
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<
|
||||
ChannelT, T, T,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<RawByteChannel, ChannelT>::value &&
|
||||
(std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value ||
|
||||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
|
||||
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
|
||||
std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
|
||||
std::is_same<T, char>::value)>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, T V) {
|
||||
support::endian::byte_swap<T, support::big>(V);
|
||||
return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
|
||||
};
|
||||
|
||||
static Error deserialize(ChannelT &C, T &V) {
|
||||
if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
|
||||
return Err;
|
||||
support::endian::byte_swap<T, support::big>(V);
|
||||
return Error::success();
|
||||
};
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, bool, bool,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, bool V) {
|
||||
uint8_t Tmp = V ? 1 : 0;
|
||||
if (auto Err = C.appendBytes(reinterpret_cast<const char *>(&Tmp), 1))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, bool &V) {
|
||||
uint8_t Tmp = 0;
|
||||
if (auto Err = C.readBytes(reinterpret_cast<char *>(&Tmp), 1))
|
||||
return Err;
|
||||
V = Tmp != 0;
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, std::string, StringRef,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
/// Serialization channel serialization for std::strings.
|
||||
static Error serialize(RawByteChannel &C, StringRef S) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(S.size())))
|
||||
return Err;
|
||||
return C.appendBytes((const char *)S.data(), S.size());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<
|
||||
ChannelT, std::string, T,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value &&
|
||||
(std::is_same<T, const char *>::value ||
|
||||
std::is_same<T, char *>::value)>> {
|
||||
public:
|
||||
static Error serialize(RawByteChannel &C, const char *S) {
|
||||
return SerializationTraits<ChannelT, std::string, StringRef>::serialize(C,
|
||||
S);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, std::string, std::string,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
/// Serialization channel serialization for std::strings.
|
||||
static Error serialize(RawByteChannel &C, const std::string &S) {
|
||||
return SerializationTraits<ChannelT, std::string, StringRef>::serialize(C,
|
||||
S);
|
||||
}
|
||||
|
||||
/// Serialization channel deserialization for std::strings.
|
||||
static Error deserialize(RawByteChannel &C, std::string &S) {
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
S.resize(Count);
|
||||
return C.readBytes(&S[0], Count);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_RAWBYTECHANNEL_H
|
||||
@@ -1,769 +0,0 @@
|
||||
//===- Serialization.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SERIALIZATION_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SERIALIZATION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/OrcError.h"
|
||||
#include "llvm/Support/thread.h"
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
template <typename T> class SerializationTypeName;
|
||||
|
||||
/// TypeNameSequence is a utility for rendering sequences of types to a string
|
||||
/// by rendering each type, separated by ", ".
|
||||
template <typename... ArgTs> class SerializationTypeNameSequence {};
|
||||
|
||||
/// Render an empty TypeNameSequence to an ostream.
|
||||
template <typename OStream>
|
||||
OStream &operator<<(OStream &OS, const SerializationTypeNameSequence<> &V) {
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Render a TypeNameSequence of a single type to an ostream.
|
||||
template <typename OStream, typename ArgT>
|
||||
OStream &operator<<(OStream &OS, const SerializationTypeNameSequence<ArgT> &V) {
|
||||
OS << SerializationTypeName<ArgT>::getName();
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Render a TypeNameSequence of more than one type to an ostream.
|
||||
template <typename OStream, typename ArgT1, typename ArgT2, typename... ArgTs>
|
||||
OStream &
|
||||
operator<<(OStream &OS,
|
||||
const SerializationTypeNameSequence<ArgT1, ArgT2, ArgTs...> &V) {
|
||||
OS << SerializationTypeName<ArgT1>::getName() << ", "
|
||||
<< SerializationTypeNameSequence<ArgT2, ArgTs...>();
|
||||
return OS;
|
||||
}
|
||||
|
||||
template <> class SerializationTypeName<void> {
|
||||
public:
|
||||
static const char *getName() { return "void"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<int8_t> {
|
||||
public:
|
||||
static const char *getName() { return "int8_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<uint8_t> {
|
||||
public:
|
||||
static const char *getName() { return "uint8_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<int16_t> {
|
||||
public:
|
||||
static const char *getName() { return "int16_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<uint16_t> {
|
||||
public:
|
||||
static const char *getName() { return "uint16_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<int32_t> {
|
||||
public:
|
||||
static const char *getName() { return "int32_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<uint32_t> {
|
||||
public:
|
||||
static const char *getName() { return "uint32_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<int64_t> {
|
||||
public:
|
||||
static const char *getName() { return "int64_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<uint64_t> {
|
||||
public:
|
||||
static const char *getName() { return "uint64_t"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<bool> {
|
||||
public:
|
||||
static const char *getName() { return "bool"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<std::string> {
|
||||
public:
|
||||
static const char *getName() { return "std::string"; }
|
||||
};
|
||||
|
||||
template <> class SerializationTypeName<Error> {
|
||||
public:
|
||||
static const char *getName() { return "Error"; }
|
||||
};
|
||||
|
||||
template <typename T> class SerializationTypeName<Expected<T>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "Expected<" << SerializationTypeNameSequence<T>() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
class SerializationTypeName<std::pair<T1, T2>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "std::pair<" << SerializationTypeNameSequence<T1, T2>() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... ArgTs> class SerializationTypeName<std::tuple<ArgTs...>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "std::tuple<" << SerializationTypeNameSequence<ArgTs...>() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class SerializationTypeName<Optional<T>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "Optional<" << SerializationTypeName<T>::getName() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class SerializationTypeName<std::vector<T>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "std::vector<" << SerializationTypeName<T>::getName() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class SerializationTypeName<std::set<T>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "std::set<" << SerializationTypeName<T>::getName() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V> class SerializationTypeName<std::map<K, V>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "std::map<" << SerializationTypeNameSequence<K, V>() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
/// The SerializationTraits<ChannelT, T> class describes how to serialize and
|
||||
/// deserialize an instance of type T to/from an abstract channel of type
|
||||
/// ChannelT. It also provides a representation of the type's name via the
|
||||
/// getName method.
|
||||
///
|
||||
/// Specializations of this class should provide the following functions:
|
||||
///
|
||||
/// @code{.cpp}
|
||||
///
|
||||
/// static const char* getName();
|
||||
/// static Error serialize(ChannelT&, const T&);
|
||||
/// static Error deserialize(ChannelT&, T&);
|
||||
///
|
||||
/// @endcode
|
||||
///
|
||||
/// The third argument of SerializationTraits is intended to support SFINAE.
|
||||
/// E.g.:
|
||||
///
|
||||
/// @code{.cpp}
|
||||
///
|
||||
/// class MyVirtualChannel { ... };
|
||||
///
|
||||
/// template <DerivedChannelT>
|
||||
/// class SerializationTraits<DerivedChannelT, bool,
|
||||
/// std::enable_if_t<
|
||||
/// std::is_base_of<VirtChannel, DerivedChannel>::value
|
||||
/// >> {
|
||||
/// public:
|
||||
/// static const char* getName() { ... };
|
||||
/// }
|
||||
///
|
||||
/// @endcode
|
||||
template <typename ChannelT, typename WireType,
|
||||
typename ConcreteType = WireType, typename = void>
|
||||
class SerializationTraits;
|
||||
|
||||
template <typename ChannelT> class SequenceTraits {
|
||||
public:
|
||||
static Error emitSeparator(ChannelT &C) { return Error::success(); }
|
||||
static Error consumeSeparator(ChannelT &C) { return Error::success(); }
|
||||
};
|
||||
|
||||
/// Utility class for serializing sequences of values of varying types.
|
||||
/// Specializations of this class contain 'serialize' and 'deserialize' methods
|
||||
/// for the given channel. The ArgTs... list will determine the "over-the-wire"
|
||||
/// types to be serialized. The serialize and deserialize methods take a list
|
||||
/// CArgTs... ("caller arg types") which must be the same length as ArgTs...,
|
||||
/// but may be different types from ArgTs, provided that for each CArgT there
|
||||
/// is a SerializationTraits specialization
|
||||
/// SerializeTraits<ChannelT, ArgT, CArgT> with methods that can serialize the
|
||||
/// caller argument to over-the-wire value.
|
||||
template <typename ChannelT, typename... ArgTs> class SequenceSerialization;
|
||||
|
||||
template <typename ChannelT> class SequenceSerialization<ChannelT> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C) { return Error::success(); }
|
||||
static Error deserialize(ChannelT &C) { return Error::success(); }
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename ArgT>
|
||||
class SequenceSerialization<ChannelT, ArgT> {
|
||||
public:
|
||||
template <typename CArgT> static Error serialize(ChannelT &C, CArgT &&CArg) {
|
||||
return SerializationTraits<ChannelT, ArgT, std::decay_t<CArgT>>::serialize(
|
||||
C, std::forward<CArgT>(CArg));
|
||||
}
|
||||
|
||||
template <typename CArgT> static Error deserialize(ChannelT &C, CArgT &CArg) {
|
||||
return SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename ArgT, typename... ArgTs>
|
||||
class SequenceSerialization<ChannelT, ArgT, ArgTs...> {
|
||||
public:
|
||||
template <typename CArgT, typename... CArgTs>
|
||||
static Error serialize(ChannelT &C, CArgT &&CArg, CArgTs &&...CArgs) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, ArgT, std::decay_t<CArgT>>::serialize(
|
||||
C, std::forward<CArgT>(CArg)))
|
||||
return Err;
|
||||
if (auto Err = SequenceTraits<ChannelT>::emitSeparator(C))
|
||||
return Err;
|
||||
return SequenceSerialization<ChannelT, ArgTs...>::serialize(
|
||||
C, std::forward<CArgTs>(CArgs)...);
|
||||
}
|
||||
|
||||
template <typename CArgT, typename... CArgTs>
|
||||
static Error deserialize(ChannelT &C, CArgT &CArg, CArgTs &...CArgs) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg))
|
||||
return Err;
|
||||
if (auto Err = SequenceTraits<ChannelT>::consumeSeparator(C))
|
||||
return Err;
|
||||
return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, CArgs...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename... ArgTs>
|
||||
Error serializeSeq(ChannelT &C, ArgTs &&...Args) {
|
||||
return SequenceSerialization<ChannelT, std::decay_t<ArgTs>...>::serialize(
|
||||
C, std::forward<ArgTs>(Args)...);
|
||||
}
|
||||
|
||||
template <typename ChannelT, typename... ArgTs>
|
||||
Error deserializeSeq(ChannelT &C, ArgTs &...Args) {
|
||||
return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, Args...);
|
||||
}
|
||||
|
||||
template <typename ChannelT> class SerializationTraits<ChannelT, Error> {
|
||||
public:
|
||||
using WrappedErrorSerializer =
|
||||
std::function<Error(ChannelT &C, const ErrorInfoBase &)>;
|
||||
|
||||
using WrappedErrorDeserializer =
|
||||
std::function<Error(ChannelT &C, Error &Err)>;
|
||||
|
||||
template <typename ErrorInfoT, typename SerializeFtor,
|
||||
typename DeserializeFtor>
|
||||
static void registerErrorType(std::string Name, SerializeFtor Serialize,
|
||||
DeserializeFtor Deserialize) {
|
||||
assert(!Name.empty() &&
|
||||
"The empty string is reserved for the Success value");
|
||||
|
||||
const std::string *KeyName = nullptr;
|
||||
{
|
||||
// We're abusing the stability of std::map here: We take a reference to
|
||||
// the key of the deserializers map to save us from duplicating the string
|
||||
// in the serializer. This should be changed to use a stringpool if we
|
||||
// switch to a map type that may move keys in memory.
|
||||
std::lock_guard<std::recursive_mutex> Lock(DeserializersMutex);
|
||||
auto I = Deserializers.insert(
|
||||
Deserializers.begin(),
|
||||
std::make_pair(std::move(Name), std::move(Deserialize)));
|
||||
KeyName = &I->first;
|
||||
}
|
||||
|
||||
{
|
||||
assert(KeyName != nullptr && "No keyname pointer");
|
||||
std::lock_guard<std::recursive_mutex> Lock(SerializersMutex);
|
||||
Serializers[ErrorInfoT::classID()] =
|
||||
[KeyName, Serialize = std::move(Serialize)](
|
||||
ChannelT &C, const ErrorInfoBase &EIB) -> Error {
|
||||
assert(EIB.dynamicClassID() == ErrorInfoT::classID() &&
|
||||
"Serializer called for wrong error type");
|
||||
if (auto Err = serializeSeq(C, *KeyName))
|
||||
return Err;
|
||||
return Serialize(C, static_cast<const ErrorInfoT &>(EIB));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static Error serialize(ChannelT &C, Error &&Err) {
|
||||
std::lock_guard<std::recursive_mutex> Lock(SerializersMutex);
|
||||
|
||||
if (!Err)
|
||||
return serializeSeq(C, std::string());
|
||||
|
||||
return handleErrors(std::move(Err), [&C](const ErrorInfoBase &EIB) {
|
||||
auto SI = Serializers.find(EIB.dynamicClassID());
|
||||
if (SI == Serializers.end())
|
||||
return serializeAsStringError(C, EIB);
|
||||
return (SI->second)(C, EIB);
|
||||
});
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, Error &Err) {
|
||||
std::lock_guard<std::recursive_mutex> Lock(DeserializersMutex);
|
||||
|
||||
std::string Key;
|
||||
if (auto Err = deserializeSeq(C, Key))
|
||||
return Err;
|
||||
|
||||
if (Key.empty()) {
|
||||
ErrorAsOutParameter EAO(&Err);
|
||||
Err = Error::success();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
auto DI = Deserializers.find(Key);
|
||||
assert(DI != Deserializers.end() && "No deserializer for error type");
|
||||
return (DI->second)(C, Err);
|
||||
}
|
||||
|
||||
private:
|
||||
static Error serializeAsStringError(ChannelT &C, const ErrorInfoBase &EIB) {
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrMsgStream(ErrMsg);
|
||||
EIB.log(ErrMsgStream);
|
||||
}
|
||||
return serialize(C, make_error<StringError>(std::move(ErrMsg),
|
||||
inconvertibleErrorCode()));
|
||||
}
|
||||
|
||||
static std::recursive_mutex SerializersMutex;
|
||||
static std::recursive_mutex DeserializersMutex;
|
||||
static std::map<const void *, WrappedErrorSerializer> Serializers;
|
||||
static std::map<std::string, WrappedErrorDeserializer> Deserializers;
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
std::recursive_mutex SerializationTraits<ChannelT, Error>::SerializersMutex;
|
||||
|
||||
template <typename ChannelT>
|
||||
std::recursive_mutex SerializationTraits<ChannelT, Error>::DeserializersMutex;
|
||||
|
||||
template <typename ChannelT>
|
||||
std::map<const void *,
|
||||
typename SerializationTraits<ChannelT, Error>::WrappedErrorSerializer>
|
||||
SerializationTraits<ChannelT, Error>::Serializers;
|
||||
|
||||
template <typename ChannelT>
|
||||
std::map<std::string, typename SerializationTraits<
|
||||
ChannelT, Error>::WrappedErrorDeserializer>
|
||||
SerializationTraits<ChannelT, Error>::Deserializers;
|
||||
|
||||
/// Registers a serializer and deserializer for the given error type on the
|
||||
/// given channel type.
|
||||
template <typename ChannelT, typename ErrorInfoT, typename SerializeFtor,
|
||||
typename DeserializeFtor>
|
||||
void registerErrorSerialization(std::string Name, SerializeFtor &&Serialize,
|
||||
DeserializeFtor &&Deserialize) {
|
||||
SerializationTraits<ChannelT, Error>::template registerErrorType<ErrorInfoT>(
|
||||
std::move(Name), std::forward<SerializeFtor>(Serialize),
|
||||
std::forward<DeserializeFtor>(Deserialize));
|
||||
}
|
||||
|
||||
/// Registers serialization/deserialization for StringError.
|
||||
template <typename ChannelT> void registerStringError() {
|
||||
static bool AlreadyRegistered = false;
|
||||
if (!AlreadyRegistered) {
|
||||
registerErrorSerialization<ChannelT, StringError>(
|
||||
"StringError",
|
||||
[](ChannelT &C, const StringError &SE) {
|
||||
return serializeSeq(C, SE.getMessage());
|
||||
},
|
||||
[](ChannelT &C, Error &Err) -> Error {
|
||||
ErrorAsOutParameter EAO(&Err);
|
||||
std::string Msg;
|
||||
if (auto E2 = deserializeSeq(C, Msg))
|
||||
return E2;
|
||||
Err = make_error<StringError>(
|
||||
std::move(Msg),
|
||||
orcError(OrcErrorCode::UnknownErrorCodeFromRemote));
|
||||
return Error::success();
|
||||
});
|
||||
AlreadyRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// SerializationTraits for Expected<T1> from an Expected<T2>.
|
||||
template <typename ChannelT, typename T1, typename T2>
|
||||
class SerializationTraits<ChannelT, Expected<T1>, Expected<T2>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, Expected<T2> &&ValOrErr) {
|
||||
if (ValOrErr) {
|
||||
if (auto Err = serializeSeq(C, true))
|
||||
return Err;
|
||||
return SerializationTraits<ChannelT, T1, T2>::serialize(C, *ValOrErr);
|
||||
}
|
||||
if (auto Err = serializeSeq(C, false))
|
||||
return Err;
|
||||
return serializeSeq(C, ValOrErr.takeError());
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, Expected<T2> &ValOrErr) {
|
||||
ExpectedAsOutParameter<T2> EAO(&ValOrErr);
|
||||
bool HasValue;
|
||||
if (auto Err = deserializeSeq(C, HasValue))
|
||||
return Err;
|
||||
if (HasValue)
|
||||
return SerializationTraits<ChannelT, T1, T2>::deserialize(C, *ValOrErr);
|
||||
Error Err = Error::success();
|
||||
if (auto E2 = deserializeSeq(C, Err))
|
||||
return E2;
|
||||
ValOrErr = std::move(Err);
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
/// SerializationTraits for Expected<T1> from a T2.
|
||||
template <typename ChannelT, typename T1, typename T2>
|
||||
class SerializationTraits<ChannelT, Expected<T1>, T2> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, T2 &&Val) {
|
||||
return serializeSeq(C, Expected<T2>(std::forward<T2>(Val)));
|
||||
}
|
||||
};
|
||||
|
||||
/// SerializationTraits for Expected<T1> from an Error.
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, Expected<T>, Error> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, Error &&Err) {
|
||||
return serializeSeq(C, Expected<T>(std::move(Err)));
|
||||
}
|
||||
};
|
||||
|
||||
/// SerializationTraits default specialization for std::pair.
|
||||
template <typename ChannelT, typename T1, typename T2, typename T3, typename T4>
|
||||
class SerializationTraits<ChannelT, std::pair<T1, T2>, std::pair<T3, T4>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, const std::pair<T3, T4> &V) {
|
||||
if (auto Err = SerializationTraits<ChannelT, T1, T3>::serialize(C, V.first))
|
||||
return Err;
|
||||
return SerializationTraits<ChannelT, T2, T4>::serialize(C, V.second);
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, std::pair<T3, T4> &V) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, T1, T3>::deserialize(C, V.first))
|
||||
return Err;
|
||||
return SerializationTraits<ChannelT, T2, T4>::deserialize(C, V.second);
|
||||
}
|
||||
};
|
||||
|
||||
/// SerializationTraits default specialization for std::tuple.
|
||||
template <typename ChannelT, typename... ArgTs>
|
||||
class SerializationTraits<ChannelT, std::tuple<ArgTs...>> {
|
||||
public:
|
||||
/// RPC channel serialization for std::tuple.
|
||||
static Error serialize(ChannelT &C, const std::tuple<ArgTs...> &V) {
|
||||
return serializeTupleHelper(C, V, std::index_sequence_for<ArgTs...>());
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for std::tuple.
|
||||
static Error deserialize(ChannelT &C, std::tuple<ArgTs...> &V) {
|
||||
return deserializeTupleHelper(C, V, std::index_sequence_for<ArgTs...>());
|
||||
}
|
||||
|
||||
private:
|
||||
// Serialization helper for std::tuple.
|
||||
template <size_t... Is>
|
||||
static Error serializeTupleHelper(ChannelT &C, const std::tuple<ArgTs...> &V,
|
||||
std::index_sequence<Is...> _) {
|
||||
return serializeSeq(C, std::get<Is>(V)...);
|
||||
}
|
||||
|
||||
// Serialization helper for std::tuple.
|
||||
template <size_t... Is>
|
||||
static Error deserializeTupleHelper(ChannelT &C, std::tuple<ArgTs...> &V,
|
||||
std::index_sequence<Is...> _) {
|
||||
return deserializeSeq(C, std::get<Is>(V)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, Optional<T>> {
|
||||
public:
|
||||
/// Serialize an Optional<T>.
|
||||
static Error serialize(ChannelT &C, const Optional<T> &O) {
|
||||
if (auto Err = serializeSeq(C, O != None))
|
||||
return Err;
|
||||
if (O)
|
||||
if (auto Err = serializeSeq(C, *O))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Deserialize an Optional<T>.
|
||||
static Error deserialize(ChannelT &C, Optional<T> &O) {
|
||||
bool HasValue = false;
|
||||
if (auto Err = deserializeSeq(C, HasValue))
|
||||
return Err;
|
||||
if (HasValue)
|
||||
if (auto Err = deserializeSeq(C, *O))
|
||||
return Err;
|
||||
return Error::success();
|
||||
};
|
||||
};
|
||||
|
||||
/// SerializationTraits default specialization for std::vector.
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, std::vector<T>> {
|
||||
public:
|
||||
/// Serialize a std::vector<T> from std::vector<T>.
|
||||
static Error serialize(ChannelT &C, const std::vector<T> &V) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
|
||||
return Err;
|
||||
|
||||
for (const auto &E : V)
|
||||
if (auto Err = serializeSeq(C, E))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Deserialize a std::vector<T> to a std::vector<T>.
|
||||
static Error deserialize(ChannelT &C, std::vector<T> &V) {
|
||||
assert(V.empty() &&
|
||||
"Expected default-constructed vector to deserialize into");
|
||||
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
|
||||
V.resize(Count);
|
||||
for (auto &E : V)
|
||||
if (auto Err = deserializeSeq(C, E))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
/// Enable vector serialization from an ArrayRef.
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, std::vector<T>, ArrayRef<T>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, ArrayRef<T> V) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
|
||||
return Err;
|
||||
|
||||
for (const auto &E : V)
|
||||
if (auto Err = serializeSeq(C, E))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T, typename T2>
|
||||
class SerializationTraits<ChannelT, std::set<T>, std::set<T2>> {
|
||||
public:
|
||||
/// Serialize a std::set<T> from std::set<T2>.
|
||||
static Error serialize(ChannelT &C, const std::set<T2> &S) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(S.size())))
|
||||
return Err;
|
||||
|
||||
for (const auto &E : S)
|
||||
if (auto Err = SerializationTraits<ChannelT, T, T2>::serialize(C, E))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Deserialize a std::set<T> to a std::set<T>.
|
||||
static Error deserialize(ChannelT &C, std::set<T2> &S) {
|
||||
assert(S.empty() && "Expected default-constructed set to deserialize into");
|
||||
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
|
||||
while (Count-- != 0) {
|
||||
T2 Val;
|
||||
if (auto Err = SerializationTraits<ChannelT, T, T2>::deserialize(C, Val))
|
||||
return Err;
|
||||
|
||||
auto Added = S.insert(Val).second;
|
||||
if (!Added)
|
||||
return make_error<StringError>("Duplicate element in deserialized set",
|
||||
orcError(OrcErrorCode::UnknownORCError));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename K, typename V, typename K2, typename V2>
|
||||
class SerializationTraits<ChannelT, std::map<K, V>, std::map<K2, V2>> {
|
||||
public:
|
||||
/// Serialize a std::map<K, V> from std::map<K2, V2>.
|
||||
static Error serialize(ChannelT &C, const std::map<K2, V2> &M) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))
|
||||
return Err;
|
||||
|
||||
for (const auto &E : M) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))
|
||||
return Err;
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::serialize(C, E.second))
|
||||
return Err;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Deserialize a std::map<K, V> to a std::map<K, V>.
|
||||
static Error deserialize(ChannelT &C, std::map<K2, V2> &M) {
|
||||
assert(M.empty() && "Expected default-constructed map to deserialize into");
|
||||
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
|
||||
while (Count-- != 0) {
|
||||
std::pair<K2, V2> Val;
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::deserialize(C, Val.first))
|
||||
return Err;
|
||||
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::deserialize(C, Val.second))
|
||||
return Err;
|
||||
|
||||
auto Added = M.insert(Val).second;
|
||||
if (!Added)
|
||||
return make_error<StringError>("Duplicate element in deserialized map",
|
||||
orcError(OrcErrorCode::UnknownORCError));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename K, typename V, typename K2, typename V2>
|
||||
class SerializationTraits<ChannelT, std::map<K, V>, DenseMap<K2, V2>> {
|
||||
public:
|
||||
/// Serialize a std::map<K, V> from DenseMap<K2, V2>.
|
||||
static Error serialize(ChannelT &C, const DenseMap<K2, V2> &M) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))
|
||||
return Err;
|
||||
|
||||
for (auto &E : M) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))
|
||||
return Err;
|
||||
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::serialize(C, E.second))
|
||||
return Err;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Serialize a std::map<K, V> from DenseMap<K2, V2>.
|
||||
static Error deserialize(ChannelT &C, DenseMap<K2, V2> &M) {
|
||||
assert(M.empty() && "Expected default-constructed map to deserialize into");
|
||||
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
|
||||
while (Count-- != 0) {
|
||||
std::pair<K2, V2> Val;
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::deserialize(C, Val.first))
|
||||
return Err;
|
||||
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::deserialize(C, Val.second))
|
||||
return Err;
|
||||
|
||||
auto Added = M.insert(Val).second;
|
||||
if (!Added)
|
||||
return make_error<StringError>("Duplicate element in deserialized map",
|
||||
orcError(OrcErrorCode::UnknownORCError));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SERIALIZATION_H
|
||||
@@ -1,7 +1,6 @@
|
||||
add_llvm_component_library(LLVMOrcShared
|
||||
OrcError.cpp
|
||||
OrcRTBridge.cpp
|
||||
RPCError.cpp
|
||||
SimpleRemoteEPCUtils.cpp
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
//===--------------- RPCError.cpp - RPCERror implementation ---------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// RPC Error type implmentations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
char llvm::orc::shared::RPCFatalError::ID = 0;
|
||||
char llvm::orc::shared::ConnectionClosed::ID = 0;
|
||||
char llvm::orc::shared::ResponseAbandoned::ID = 0;
|
||||
char llvm::orc::shared::CouldNotNegotiate::ID = 0;
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
std::error_code ConnectionClosed::convertToErrorCode() const {
|
||||
return orcError(OrcErrorCode::RPCConnectionClosed);
|
||||
}
|
||||
|
||||
void ConnectionClosed::log(raw_ostream &OS) const {
|
||||
OS << "RPC connection already closed";
|
||||
}
|
||||
|
||||
std::error_code ResponseAbandoned::convertToErrorCode() const {
|
||||
return orcError(OrcErrorCode::RPCResponseAbandoned);
|
||||
}
|
||||
|
||||
void ResponseAbandoned::log(raw_ostream &OS) const {
|
||||
OS << "RPC response abandoned";
|
||||
}
|
||||
|
||||
CouldNotNegotiate::CouldNotNegotiate(std::string Signature)
|
||||
: Signature(std::move(Signature)) {}
|
||||
|
||||
std::error_code CouldNotNegotiate::convertToErrorCode() const {
|
||||
return orcError(OrcErrorCode::RPCCouldNotNegotiateFunction);
|
||||
}
|
||||
|
||||
void CouldNotNegotiate::log(raw_ostream &OS) const {
|
||||
OS << "Could not negotiate RPC function " << Signature;
|
||||
}
|
||||
|
||||
} // end namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
@@ -11,7 +11,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
|
||||
@@ -66,9 +65,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
ExitOnErr(Server->waitForDisconnect());
|
||||
|
||||
close(InFD);
|
||||
close(OutFD);
|
||||
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
@@ -27,9 +27,7 @@ add_llvm_unittest(OrcJITTests
|
||||
ObjectLinkingLayerTest.cpp
|
||||
OrcCAPITest.cpp
|
||||
OrcTestCommon.cpp
|
||||
QueueChannel.cpp
|
||||
ResourceTrackerTest.cpp
|
||||
RPCUtilsTest.cpp
|
||||
RTDyldObjectLinkingLayerTest.cpp
|
||||
SimpleExecutorMemoryManagerTest.cpp
|
||||
SimplePackedSerializationTest.cpp
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//===-------- QueueChannel.cpp - Unit tests the remote executors ----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "QueueChannel.h"
|
||||
|
||||
char llvm::QueueChannelError::ID;
|
||||
char llvm::QueueChannelClosedError::ID;
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
//===----------------------- Queue.h - RPC Queue ------------------*-c++-*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_UNITTESTS_EXECUTIONENGINE_ORC_QUEUECHANNEL_H
|
||||
#define LLVM_UNITTESTS_EXECUTIONENGINE_ORC_QUEUECHANNEL_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class QueueChannelError : public ErrorInfo<QueueChannelError> {
|
||||
public:
|
||||
static char ID;
|
||||
};
|
||||
|
||||
class QueueChannelClosedError
|
||||
: public ErrorInfo<QueueChannelClosedError, QueueChannelError> {
|
||||
public:
|
||||
static char ID;
|
||||
std::error_code convertToErrorCode() const override {
|
||||
return inconvertibleErrorCode();
|
||||
}
|
||||
|
||||
void log(raw_ostream &OS) const override {
|
||||
OS << "Queue closed";
|
||||
}
|
||||
};
|
||||
|
||||
class Queue : public std::queue<char> {
|
||||
public:
|
||||
using ErrorInjector = std::function<Error()>;
|
||||
|
||||
Queue()
|
||||
: ReadError([]() { return Error::success(); }),
|
||||
WriteError([]() { return Error::success(); }) {}
|
||||
|
||||
Queue(const Queue&) = delete;
|
||||
Queue& operator=(const Queue&) = delete;
|
||||
Queue(Queue&&) = delete;
|
||||
Queue& operator=(Queue&&) = delete;
|
||||
|
||||
std::mutex &getMutex() { return M; }
|
||||
std::condition_variable &getCondVar() { return CV; }
|
||||
Error checkReadError() { return ReadError(); }
|
||||
Error checkWriteError() { return WriteError(); }
|
||||
void setReadError(ErrorInjector NewReadError) {
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(M);
|
||||
ReadError = std::move(NewReadError);
|
||||
}
|
||||
CV.notify_one();
|
||||
}
|
||||
void setWriteError(ErrorInjector NewWriteError) {
|
||||
std::lock_guard<std::mutex> Lock(M);
|
||||
WriteError = std::move(NewWriteError);
|
||||
}
|
||||
private:
|
||||
std::mutex M;
|
||||
std::condition_variable CV;
|
||||
std::function<Error()> ReadError, WriteError;
|
||||
};
|
||||
|
||||
class QueueChannel : public orc::shared::RawByteChannel {
|
||||
public:
|
||||
QueueChannel(std::shared_ptr<Queue> InQueue,
|
||||
std::shared_ptr<Queue> OutQueue)
|
||||
: InQueue(InQueue), OutQueue(OutQueue) {}
|
||||
|
||||
QueueChannel(const QueueChannel&) = delete;
|
||||
QueueChannel& operator=(const QueueChannel&) = delete;
|
||||
QueueChannel(QueueChannel&&) = delete;
|
||||
QueueChannel& operator=(QueueChannel&&) = delete;
|
||||
|
||||
template <typename FunctionIdT, typename SequenceIdT>
|
||||
Error startSendMessage(const FunctionIdT &FnId, const SequenceIdT &SeqNo) {
|
||||
++InFlightOutgoingMessages;
|
||||
return orc::shared::RawByteChannel::startSendMessage(FnId, SeqNo);
|
||||
}
|
||||
|
||||
Error endSendMessage() {
|
||||
--InFlightOutgoingMessages;
|
||||
++CompletedOutgoingMessages;
|
||||
return orc::shared::RawByteChannel::endSendMessage();
|
||||
}
|
||||
|
||||
template <typename FunctionIdT, typename SequenceNumberT>
|
||||
Error startReceiveMessage(FunctionIdT &FnId, SequenceNumberT &SeqNo) {
|
||||
++InFlightIncomingMessages;
|
||||
return orc::shared::RawByteChannel::startReceiveMessage(FnId, SeqNo);
|
||||
}
|
||||
|
||||
Error endReceiveMessage() {
|
||||
--InFlightIncomingMessages;
|
||||
++CompletedIncomingMessages;
|
||||
return orc::shared::RawByteChannel::endReceiveMessage();
|
||||
}
|
||||
|
||||
Error readBytes(char *Dst, unsigned Size) override {
|
||||
std::unique_lock<std::mutex> Lock(InQueue->getMutex());
|
||||
while (Size) {
|
||||
{
|
||||
Error Err = InQueue->checkReadError();
|
||||
while (!Err && InQueue->empty()) {
|
||||
InQueue->getCondVar().wait(Lock);
|
||||
Err = InQueue->checkReadError();
|
||||
}
|
||||
if (Err)
|
||||
return Err;
|
||||
}
|
||||
*Dst++ = InQueue->front();
|
||||
--Size;
|
||||
++NumRead;
|
||||
InQueue->pop();
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error appendBytes(const char *Src, unsigned Size) override {
|
||||
std::unique_lock<std::mutex> Lock(OutQueue->getMutex());
|
||||
while (Size--) {
|
||||
if (Error Err = OutQueue->checkWriteError())
|
||||
return Err;
|
||||
OutQueue->push(*Src++);
|
||||
++NumWritten;
|
||||
}
|
||||
OutQueue->getCondVar().notify_one();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error send() override {
|
||||
++SendCalls;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void close() {
|
||||
auto ChannelClosed = []() { return make_error<QueueChannelClosedError>(); };
|
||||
InQueue->setReadError(ChannelClosed);
|
||||
InQueue->setWriteError(ChannelClosed);
|
||||
OutQueue->setReadError(ChannelClosed);
|
||||
OutQueue->setWriteError(ChannelClosed);
|
||||
}
|
||||
|
||||
uint64_t NumWritten = 0;
|
||||
uint64_t NumRead = 0;
|
||||
std::atomic<size_t> InFlightIncomingMessages{0};
|
||||
std::atomic<size_t> CompletedIncomingMessages{0};
|
||||
std::atomic<size_t> InFlightOutgoingMessages{0};
|
||||
std::atomic<size_t> CompletedOutgoingMessages{0};
|
||||
std::atomic<size_t> SendCalls{0};
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<Queue> InQueue;
|
||||
std::shared_ptr<Queue> OutQueue;
|
||||
};
|
||||
|
||||
inline std::pair<std::unique_ptr<QueueChannel>, std::unique_ptr<QueueChannel>>
|
||||
createPairedQueueChannels() {
|
||||
auto Q1 = std::make_shared<Queue>();
|
||||
auto Q2 = std::make_shared<Queue>();
|
||||
auto C1 = std::make_unique<QueueChannel>(Q1, Q2);
|
||||
auto C2 = std::make_unique<QueueChannel>(Q2, Q1);
|
||||
return std::make_pair(std::move(C1), std::move(C2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,890 +0,0 @@
|
||||
//===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
||||
#include "QueueChannel.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
using namespace llvm::orc::shared;
|
||||
|
||||
class RPCFoo {};
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
template <> class SerializationTypeName<RPCFoo> {
|
||||
public:
|
||||
static const char *getName() { return "RPCFoo"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> {
|
||||
public:
|
||||
static Error serialize(QueueChannel&, const RPCFoo&) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error deserialize(QueueChannel&, RPCFoo&) {
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
class RPCBar {};
|
||||
|
||||
class DummyError : public ErrorInfo<DummyError> {
|
||||
public:
|
||||
|
||||
static char ID;
|
||||
|
||||
DummyError(uint32_t Val) : Val(Val) {}
|
||||
|
||||
std::error_code convertToErrorCode() const override {
|
||||
// Use a nonsense error code - we want to verify that errors
|
||||
// transmitted over the network are replaced with
|
||||
// OrcErrorCode::UnknownErrorCodeFromRemote.
|
||||
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
|
||||
}
|
||||
|
||||
void log(raw_ostream &OS) const override {
|
||||
OS << "Dummy error " << Val;
|
||||
}
|
||||
|
||||
uint32_t getValue() const { return Val; }
|
||||
|
||||
public:
|
||||
uint32_t Val;
|
||||
};
|
||||
|
||||
char DummyError::ID = 0;
|
||||
|
||||
template <typename ChannelT>
|
||||
void registerDummyErrorSerialization() {
|
||||
static bool AlreadyRegistered = false;
|
||||
if (!AlreadyRegistered) {
|
||||
SerializationTraits<ChannelT, Error>::
|
||||
template registerErrorType<DummyError>(
|
||||
"DummyError",
|
||||
[](ChannelT &C, const DummyError &DE) {
|
||||
return serializeSeq(C, DE.getValue());
|
||||
},
|
||||
[](ChannelT &C, Error &Err) -> Error {
|
||||
ErrorAsOutParameter EAO(&Err);
|
||||
uint32_t Val;
|
||||
if (auto Err = deserializeSeq(C, Val))
|
||||
return Err;
|
||||
Err = make_error<DummyError>(Val);
|
||||
return Error::success();
|
||||
});
|
||||
AlreadyRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
template <> class SerializationTraits<QueueChannel, RPCFoo, RPCBar> {
|
||||
public:
|
||||
static Error serialize(QueueChannel &, const RPCBar &) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error deserialize(QueueChannel &, RPCBar &) {
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
namespace DummyRPCAPI {
|
||||
|
||||
class VoidBool : public RPCFunction<VoidBool, void(bool)> {
|
||||
public:
|
||||
static const char *getName() { return "VoidBool"; }
|
||||
};
|
||||
|
||||
class IntInt : public RPCFunction<IntInt, int32_t(int32_t)> {
|
||||
public:
|
||||
static const char *getName() { return "IntInt"; }
|
||||
};
|
||||
|
||||
class VoidString : public RPCFunction<VoidString, void(std::string)> {
|
||||
public:
|
||||
static const char *getName() { return "VoidString"; }
|
||||
};
|
||||
|
||||
class AllTheTypes
|
||||
: public RPCFunction<AllTheTypes,
|
||||
void(int8_t, uint8_t, int16_t, uint16_t, int32_t,
|
||||
uint32_t, int64_t, uint64_t, bool, std::string,
|
||||
std::vector<int>, std::set<int>,
|
||||
std::map<int, bool>)> {
|
||||
public:
|
||||
static const char *getName() { return "AllTheTypes"; }
|
||||
};
|
||||
|
||||
class CustomType : public RPCFunction<CustomType, RPCFoo(RPCFoo)> {
|
||||
public:
|
||||
static const char *getName() { return "CustomType"; }
|
||||
};
|
||||
|
||||
class ErrorFunc : public RPCFunction<ErrorFunc, Error()> {
|
||||
public:
|
||||
static const char *getName() { return "ErrorFunc"; }
|
||||
};
|
||||
|
||||
class ExpectedFunc : public RPCFunction<ExpectedFunc, Expected<uint32_t>()> {
|
||||
public:
|
||||
static const char *getName() { return "ExpectedFunc"; }
|
||||
};
|
||||
}
|
||||
|
||||
class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> {
|
||||
public:
|
||||
DummyRPCEndpoint(QueueChannel &C)
|
||||
: SingleThreadedRPCEndpoint(C, true) {}
|
||||
};
|
||||
|
||||
|
||||
void freeVoidBool(bool B) {
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestFreeFunctionHandler) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Server(*Channels.first);
|
||||
Server.addHandler<DummyRPCAPI::VoidBool>(freeVoidBool);
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestCallAsyncVoidBool) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::VoidBool>(
|
||||
[](bool B) {
|
||||
EXPECT_EQ(B, true)
|
||||
<< "Server void(bool) received unexpected result";
|
||||
});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the VoidBool call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
// Make an async call.
|
||||
auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
|
||||
[](Error Err) {
|
||||
EXPECT_FALSE(!!Err) << "Async void(bool) response handler failed";
|
||||
return Error::success();
|
||||
}, true);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result of the void(bool) call.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
|
||||
// The client should have made two calls to send: One implicit call to
|
||||
// negotiate the VoidBool function key, and a second to make the VoidBool
|
||||
// call.
|
||||
EXPECT_EQ(Channels.first->SendCalls, 2U)
|
||||
<< "Expected one send call to have been made by client";
|
||||
|
||||
// The server should have made two calls to send: One to send the response to
|
||||
// the negotiate call, and another to send the response to the VoidBool call.
|
||||
EXPECT_EQ(Channels.second->SendCalls, 2U)
|
||||
<< "Expected two send calls to have been made by server";
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestCallAsyncIntInt) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::IntInt>(
|
||||
[](int X) -> int {
|
||||
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
||||
return 2 * X;
|
||||
});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the int(int) call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
||||
[](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
EXPECT_EQ(*Result, 42)
|
||||
<< "Async int(int) response handler received incorrect result";
|
||||
return Error::success();
|
||||
}, 21);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestAsyncVoidBoolHandler) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addAsyncHandler<DummyRPCAPI::VoidBool>(
|
||||
[](std::function<Error(Error)> SendResult,
|
||||
bool B) {
|
||||
EXPECT_EQ(B, true) << "Server void(bool) receieved unexpected result";
|
||||
cantFail(SendResult(Error::success()));
|
||||
return Error::success();
|
||||
});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the VoidBool call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
auto Err = Client.callAsync<DummyRPCAPI::VoidBool>(
|
||||
[](Error Result) {
|
||||
EXPECT_FALSE(!!Result) << "Async void(bool) response handler failed";
|
||||
return Error::success();
|
||||
}, true);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestAsyncIntIntHandler) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addAsyncHandler<DummyRPCAPI::IntInt>(
|
||||
[](std::function<Error(Expected<int32_t>)> SendResult,
|
||||
int32_t X) {
|
||||
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
||||
return SendResult(2 * X);
|
||||
});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the VoidBool call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
||||
[](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
EXPECT_EQ(*Result, 42)
|
||||
<< "Async int(int) response handler received incorrect result";
|
||||
return Error::success();
|
||||
}, 21);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestAsyncIntIntHandlerMethod) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
class Dummy {
|
||||
public:
|
||||
Error handler(std::function<Error(Expected<int32_t>)> SendResult,
|
||||
int32_t X) {
|
||||
EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result";
|
||||
return SendResult(2 * X);
|
||||
}
|
||||
};
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Dummy D;
|
||||
Server.addAsyncHandler<DummyRPCAPI::IntInt>(D, &Dummy::handler);
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the VoidBool call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
auto Err = Client.callAsync<DummyRPCAPI::IntInt>(
|
||||
[](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
EXPECT_EQ(*Result, 42)
|
||||
<< "Async int(int) response handler received incorrect result";
|
||||
return Error::success();
|
||||
}, 21);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestCallAsyncVoidString) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::VoidString>(
|
||||
[](const std::string &S) {
|
||||
EXPECT_EQ(S, "hello")
|
||||
<< "Server void(std::string) received unexpected result";
|
||||
});
|
||||
|
||||
// Poke the server to handle the negotiate call.
|
||||
for (int I = 0; I < 4; ++I) {
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
// Make an call using a std::string.
|
||||
auto Err = Client.callB<DummyRPCAPI::VoidString>(std::string("hello"));
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
|
||||
}
|
||||
|
||||
{
|
||||
// Make an call using a std::string.
|
||||
auto Err = Client.callB<DummyRPCAPI::VoidString>(StringRef("hello"));
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(std::string)";
|
||||
}
|
||||
|
||||
{
|
||||
// Make an call using a std::string.
|
||||
auto Err = Client.callB<DummyRPCAPI::VoidString>("hello");
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(string)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestSerialization) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::AllTheTypes>([&](int8_t S8, uint8_t U8,
|
||||
int16_t S16, uint16_t U16,
|
||||
int32_t S32, uint32_t U32,
|
||||
int64_t S64, uint64_t U64,
|
||||
bool B, std::string S,
|
||||
std::vector<int> V,
|
||||
std::set<int> S2,
|
||||
std::map<int, bool> M) {
|
||||
EXPECT_EQ(S8, -101) << "int8_t serialization broken";
|
||||
EXPECT_EQ(U8, 250) << "uint8_t serialization broken";
|
||||
EXPECT_EQ(S16, -10000) << "int16_t serialization broken";
|
||||
EXPECT_EQ(U16, 10000) << "uint16_t serialization broken";
|
||||
EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken";
|
||||
EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken";
|
||||
EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken";
|
||||
EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken";
|
||||
EXPECT_EQ(B, true) << "bool serialization broken";
|
||||
EXPECT_EQ(S, "foo") << "std::string serialization broken";
|
||||
EXPECT_EQ(V, std::vector<int>({42, 7}))
|
||||
<< "std::vector serialization broken";
|
||||
EXPECT_EQ(S2, std::set<int>({7, 42})) << "std::set serialization broken";
|
||||
EXPECT_EQ(M, (std::map<int, bool>({{7, false}, {42, true}})))
|
||||
<< "std::map serialization broken";
|
||||
return Error::success();
|
||||
});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the AllTheTypes call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
// Make an async call.
|
||||
std::vector<int> V({42, 7});
|
||||
std::set<int> S({7, 42});
|
||||
std::map<int, bool> M({{7, false}, {42, true}});
|
||||
auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>(
|
||||
[](Error Err) {
|
||||
EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed";
|
||||
return Error::success();
|
||||
},
|
||||
static_cast<int8_t>(-101), static_cast<uint8_t>(250),
|
||||
static_cast<int16_t>(-10000), static_cast<uint16_t>(10000),
|
||||
static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000),
|
||||
static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000),
|
||||
true, std::string("foo"), V, S, M);
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result of the AllTheTypes call.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from AllTheTypes";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestCustomType) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::CustomType>(
|
||||
[](RPCFoo F) {});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the CustomType call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
// Make an async call.
|
||||
auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
|
||||
[](Expected<RPCFoo> FOrErr) {
|
||||
EXPECT_TRUE(!!FOrErr)
|
||||
<< "Async RPCFoo(RPCFoo) response handler failed";
|
||||
return Error::success();
|
||||
}, RPCFoo());
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result of the RPCFoo() call.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err)
|
||||
<< "Client failed to handle response from RPCFoo(RPCFoo)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestWithAltCustomType) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::CustomType>(
|
||||
[](RPCBar F) {});
|
||||
|
||||
{
|
||||
// Poke the server to handle the negotiate call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the server to handle the CustomType call.
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
// Make an async call.
|
||||
auto Err = Client.callAsync<DummyRPCAPI::CustomType>(
|
||||
[](Expected<RPCBar> FOrErr) {
|
||||
EXPECT_TRUE(!!FOrErr)
|
||||
<< "Async RPCFoo(RPCFoo) response handler failed";
|
||||
return Error::success();
|
||||
}, RPCBar());
|
||||
EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)";
|
||||
}
|
||||
|
||||
{
|
||||
// Poke the client to process the result of the RPCFoo() call.
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err)
|
||||
<< "Client failed to handle response from RPCFoo(RPCFoo)";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, ReturnErrorSuccess) {
|
||||
registerDummyErrorSerialization<QueueChannel>();
|
||||
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::ErrorFunc>(
|
||||
[]() {
|
||||
return Error::success();
|
||||
});
|
||||
|
||||
// Handle the negotiate plus one call.
|
||||
for (unsigned I = 0; I != 2; ++I)
|
||||
cantFail(Server.handleOne());
|
||||
});
|
||||
|
||||
cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
|
||||
[&](Error Err) {
|
||||
EXPECT_FALSE(!!Err) << "Expected success value";
|
||||
return Error::success();
|
||||
}));
|
||||
|
||||
cantFail(Client.handleOne());
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, ReturnErrorFailure) {
|
||||
registerDummyErrorSerialization<QueueChannel>();
|
||||
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::ErrorFunc>(
|
||||
[]() {
|
||||
return make_error<DummyError>(42);
|
||||
});
|
||||
|
||||
// Handle the negotiate plus one call.
|
||||
for (unsigned I = 0; I != 2; ++I)
|
||||
cantFail(Server.handleOne());
|
||||
});
|
||||
|
||||
cantFail(Client.callAsync<DummyRPCAPI::ErrorFunc>(
|
||||
[&](Error Err) {
|
||||
EXPECT_TRUE(Err.isA<DummyError>())
|
||||
<< "Incorrect error type";
|
||||
return handleErrors(
|
||||
std::move(Err),
|
||||
[](const DummyError &DE) {
|
||||
EXPECT_EQ(DE.getValue(), 42ULL)
|
||||
<< "Incorrect DummyError serialization";
|
||||
});
|
||||
}));
|
||||
|
||||
cantFail(Client.handleOne());
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, ReturnExpectedSuccess) {
|
||||
registerDummyErrorSerialization<QueueChannel>();
|
||||
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::ExpectedFunc>(
|
||||
[]() -> uint32_t {
|
||||
return 42;
|
||||
});
|
||||
|
||||
// Handle the negotiate plus one call.
|
||||
for (unsigned I = 0; I != 2; ++I)
|
||||
cantFail(Server.handleOne());
|
||||
});
|
||||
|
||||
cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
|
||||
[&](Expected<uint32_t> ValOrErr) {
|
||||
EXPECT_TRUE(!!ValOrErr)
|
||||
<< "Expected success value";
|
||||
EXPECT_EQ(*ValOrErr, 42ULL)
|
||||
<< "Incorrect Expected<uint32_t> deserialization";
|
||||
return Error::success();
|
||||
}));
|
||||
|
||||
cantFail(Client.handleOne());
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, ReturnExpectedFailure) {
|
||||
registerDummyErrorSerialization<QueueChannel>();
|
||||
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::ExpectedFunc>(
|
||||
[]() -> Expected<uint32_t> {
|
||||
return make_error<DummyError>(7);
|
||||
});
|
||||
|
||||
// Handle the negotiate plus one call.
|
||||
for (unsigned I = 0; I != 2; ++I)
|
||||
cantFail(Server.handleOne());
|
||||
});
|
||||
|
||||
cantFail(Client.callAsync<DummyRPCAPI::ExpectedFunc>(
|
||||
[&](Expected<uint32_t> ValOrErr) {
|
||||
EXPECT_FALSE(!!ValOrErr)
|
||||
<< "Expected failure value";
|
||||
auto Err = ValOrErr.takeError();
|
||||
EXPECT_TRUE(Err.isA<DummyError>())
|
||||
<< "Incorrect error type";
|
||||
return handleErrors(
|
||||
std::move(Err),
|
||||
[](const DummyError &DE) {
|
||||
EXPECT_EQ(DE.getValue(), 7ULL)
|
||||
<< "Incorrect DummyError serialization";
|
||||
});
|
||||
}));
|
||||
|
||||
cantFail(Client.handleOne());
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestParallelCallGroup) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread([&]() {
|
||||
Server.addHandler<DummyRPCAPI::IntInt>(
|
||||
[](int X) -> int {
|
||||
return 2 * X;
|
||||
});
|
||||
|
||||
// Handle the negotiate, plus three calls.
|
||||
for (unsigned I = 0; I != 4; ++I) {
|
||||
auto Err = Server.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)";
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
int A, B, C;
|
||||
ParallelCallGroup PCG;
|
||||
|
||||
{
|
||||
auto Err = PCG.call(
|
||||
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
||||
[&A](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
A = *Result;
|
||||
return Error::success();
|
||||
}, 1);
|
||||
EXPECT_FALSE(!!Err) << "First parallel call failed for int(int)";
|
||||
}
|
||||
|
||||
{
|
||||
auto Err = PCG.call(
|
||||
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
||||
[&B](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
B = *Result;
|
||||
return Error::success();
|
||||
}, 2);
|
||||
EXPECT_FALSE(!!Err) << "Second parallel call failed for int(int)";
|
||||
}
|
||||
|
||||
{
|
||||
auto Err = PCG.call(
|
||||
rpcAsyncDispatch<DummyRPCAPI::IntInt>(Client),
|
||||
[&C](Expected<int> Result) {
|
||||
EXPECT_TRUE(!!Result) << "Async int(int) response handler failed";
|
||||
C = *Result;
|
||||
return Error::success();
|
||||
}, 3);
|
||||
EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)";
|
||||
}
|
||||
|
||||
// Handle the three int(int) results.
|
||||
for (unsigned I = 0; I != 3; ++I) {
|
||||
auto Err = Client.handleOne();
|
||||
EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)";
|
||||
}
|
||||
|
||||
PCG.wait();
|
||||
|
||||
EXPECT_EQ(A, 2) << "First parallel call returned bogus result";
|
||||
EXPECT_EQ(B, 4) << "Second parallel call returned bogus result";
|
||||
EXPECT_EQ(C, 6) << "Third parallel call returned bogus result";
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestAPICalls) {
|
||||
|
||||
using DummyCalls1 = APICalls<DummyRPCAPI::VoidBool, DummyRPCAPI::IntInt>;
|
||||
using DummyCalls2 = APICalls<DummyRPCAPI::AllTheTypes>;
|
||||
using DummyCalls3 = APICalls<DummyCalls1, DummyRPCAPI::CustomType>;
|
||||
using DummyCallsAll = APICalls<DummyCalls1, DummyCalls2, DummyRPCAPI::CustomType>;
|
||||
|
||||
static_assert(DummyCalls1::Contains<DummyRPCAPI::VoidBool>::value,
|
||||
"Contains<Func> template should return true here");
|
||||
static_assert(!DummyCalls1::Contains<DummyRPCAPI::CustomType>::value,
|
||||
"Contains<Func> template should return false here");
|
||||
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Client(*Channels.first);
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
std::thread ServerThread(
|
||||
[&]() {
|
||||
Server.addHandler<DummyRPCAPI::VoidBool>([](bool b) { });
|
||||
Server.addHandler<DummyRPCAPI::IntInt>([](int x) { return x; });
|
||||
Server.addHandler<DummyRPCAPI::CustomType>([](RPCFoo F) {});
|
||||
|
||||
for (unsigned I = 0; I < 4; ++I) {
|
||||
auto Err = Server.handleOne();
|
||||
(void)!!Err;
|
||||
}
|
||||
});
|
||||
|
||||
{
|
||||
auto Err = DummyCalls1::negotiate(Client);
|
||||
EXPECT_FALSE(!!Err) << "DummyCalls1::negotiate failed";
|
||||
}
|
||||
|
||||
{
|
||||
auto Err = DummyCalls3::negotiate(Client);
|
||||
EXPECT_FALSE(!!Err) << "DummyCalls3::negotiate failed";
|
||||
}
|
||||
|
||||
{
|
||||
auto Err = DummyCallsAll::negotiate(Client);
|
||||
EXPECT_TRUE(Err.isA<CouldNotNegotiate>())
|
||||
<< "Expected CouldNotNegotiate error for attempted negotiate of "
|
||||
"unsupported function";
|
||||
consumeError(std::move(Err));
|
||||
}
|
||||
|
||||
ServerThread.join();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestRemoveHandler) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
Server.addHandler<DummyRPCAPI::VoidBool>(
|
||||
[](bool B) {
|
||||
llvm_unreachable("Server void(bool) received unexpected result");
|
||||
});
|
||||
|
||||
Server.removeHandler<DummyRPCAPI::VoidBool>();
|
||||
}
|
||||
|
||||
TEST(DummyRPC, TestClearHandlers) {
|
||||
auto Channels = createPairedQueueChannels();
|
||||
DummyRPCEndpoint Server(*Channels.second);
|
||||
|
||||
Server.addHandler<DummyRPCAPI::VoidBool>(
|
||||
[](bool B) {
|
||||
llvm_unreachable("Server void(bool) received unexpected result");
|
||||
});
|
||||
|
||||
Server.clearHandlers();
|
||||
}
|
||||
Reference in New Issue
Block a user