//===- llvm/ExecutionEngine/Orc/RPCChannel.h --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #include "OrcError.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include #include #include #include #include #include namespace llvm { namespace orc { namespace remote { /// Interface for byte-streams to be used with RPC. class RPCChannel { public: virtual ~RPCChannel() {} /// 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; /// 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; }; /// Notify the channel that we're starting a message send. /// Locks the channel for writing. inline Error startSendMessage(RPCChannel &C) { C.getWriteLock().lock(); return Error::success(); } /// Notify the channel that we're ending a message send. /// Unlocks the channel for writing. inline Error endSendMessage(RPCChannel &C) { C.getWriteLock().unlock(); return Error::success(); } /// Notify the channel that we're starting a message receive. /// Locks the channel for reading. inline Error startReceiveMessage(RPCChannel &C) { C.getReadLock().lock(); return Error::success(); } /// Notify the channel that we're ending a message receive. /// Unlocks the channel for reading. inline Error endReceiveMessage(RPCChannel &C) { C.getReadLock().unlock(); return Error::success(); } /// RPC channel serialization for a variadic list of arguments. template Error serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) { if (auto Err = serialize(C, Arg)) return Err; return serializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. inline Error serializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel deserialization for a variadic list of arguments. template Error deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) { if (auto Err = deserialize(C, Arg)) return Err; return deserializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. inline Error deserializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel serialization for integer primitives. template typename std::enable_if< std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, Error>::type serialize(RPCChannel &C, T V) { support::endian::byte_swap(V); return C.appendBytes(reinterpret_cast(&V), sizeof(T)); } /// RPC channel deserialization for integer primitives. template typename std::enable_if< std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, Error>::type deserialize(RPCChannel &C, T &V) { if (auto Err = C.readBytes(reinterpret_cast(&V), sizeof(T))) return Err; support::endian::byte_swap(V); return Error::success(); } /// RPC channel serialization for enums. template typename std::enable_if::value, Error>::type serialize(RPCChannel &C, T V) { return serialize(C, static_cast::type>(V)); } /// RPC channel deserialization for enums. template typename std::enable_if::value, Error>::type deserialize(RPCChannel &C, T &V) { typename std::underlying_type::type Tmp; Error Err = deserialize(C, Tmp); V = static_cast(Tmp); return Err; } /// RPC channel serialization for bools. inline Error serialize(RPCChannel &C, bool V) { uint8_t VN = V ? 1 : 0; return C.appendBytes(reinterpret_cast(&VN), 1); } /// RPC channel deserialization for bools. inline Error deserialize(RPCChannel &C, bool &V) { uint8_t VN = 0; if (auto Err = C.readBytes(reinterpret_cast(&VN), 1)) return Err; V = (VN != 0); return Error::success(); } /// RPC channel serialization for StringRefs. /// Note: There is no corresponding deseralization for this, as StringRef /// doesn't own its memory and so can't hold the deserialized data. inline Error serialize(RPCChannel &C, StringRef S) { if (auto Err = serialize(C, static_cast(S.size()))) return Err; return C.appendBytes((const char *)S.bytes_begin(), S.size()); } /// RPC channel serialization for std::strings. inline Error serialize(RPCChannel &C, const std::string &S) { return serialize(C, StringRef(S)); } /// RPC channel deserialization for std::strings. inline Error deserialize(RPCChannel &C, std::string &S) { uint64_t Count; if (auto Err = deserialize(C, Count)) return Err; S.resize(Count); return C.readBytes(&S[0], Count); } // Serialization helper for std::tuple. template inline Error serializeTupleHelper(RPCChannel &C, const TupleT &V, llvm::index_sequence _) { return serializeSeq(C, std::get(V)...); } /// RPC channel serialization for std::tuple. template inline Error serialize(RPCChannel &C, const std::tuple &V) { return serializeTupleHelper(C, V, llvm::index_sequence_for()); } // Serialization helper for std::tuple. template inline Error deserializeTupleHelper(RPCChannel &C, TupleT &V, llvm::index_sequence _) { return deserializeSeq(C, std::get(V)...); } /// RPC channel deserialization for std::tuple. template inline Error deserialize(RPCChannel &C, std::tuple &V) { return deserializeTupleHelper(C, V, llvm::index_sequence_for()); } /// RPC channel serialization for ArrayRef. template Error serialize(RPCChannel &C, const ArrayRef &A) { if (auto Err = serialize(C, static_cast(A.size()))) return Err; for (const auto &E : A) if (auto Err = serialize(C, E)) return Err; return Error::success(); } /// RPC channel serialization for std::array. template Error serialize(RPCChannel &C, const std::vector &V) { return serialize(C, ArrayRef(V)); } /// RPC channel deserialization for std::array. template Error deserialize(RPCChannel &C, std::vector &V) { uint64_t Count = 0; if (auto Err = deserialize(C, Count)) return Err; V.resize(Count); for (auto &E : V) if (auto Err = deserialize(C, E)) return Err; return Error::success(); } } // end namespace remote } // end namespace orc } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H