1 //===- llvm/ExecutionEngine/Orc/RPCChannel.h --------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
11 #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
12
13 #include "OrcError.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/Error.h"
19 #include <cstddef>
20 #include <cstdint>
21 #include <mutex>
22 #include <string>
23 #include <tuple>
24 #include <vector>
25
26 namespace llvm {
27 namespace orc {
28 namespace remote {
29
30 /// Interface for byte-streams to be used with RPC.
31 class RPCChannel {
32 public:
~RPCChannel()33 virtual ~RPCChannel() {}
34
35 /// Read Size bytes from the stream into *Dst.
36 virtual Error readBytes(char *Dst, unsigned Size) = 0;
37
38 /// Read size bytes from *Src and append them to the stream.
39 virtual Error appendBytes(const char *Src, unsigned Size) = 0;
40
41 /// Flush the stream if possible.
42 virtual Error send() = 0;
43
44 /// Get the lock for stream reading.
getReadLock()45 std::mutex &getReadLock() { return readLock; }
46
47 /// Get the lock for stream writing.
getWriteLock()48 std::mutex &getWriteLock() { return writeLock; }
49
50 private:
51 std::mutex readLock, writeLock;
52 };
53
54 /// Notify the channel that we're starting a message send.
55 /// Locks the channel for writing.
startSendMessage(RPCChannel & C)56 inline Error startSendMessage(RPCChannel &C) {
57 C.getWriteLock().lock();
58 return Error::success();
59 }
60
61 /// Notify the channel that we're ending a message send.
62 /// Unlocks the channel for writing.
endSendMessage(RPCChannel & C)63 inline Error endSendMessage(RPCChannel &C) {
64 C.getWriteLock().unlock();
65 return Error::success();
66 }
67
68 /// Notify the channel that we're starting a message receive.
69 /// Locks the channel for reading.
startReceiveMessage(RPCChannel & C)70 inline Error startReceiveMessage(RPCChannel &C) {
71 C.getReadLock().lock();
72 return Error::success();
73 }
74
75 /// Notify the channel that we're ending a message receive.
76 /// Unlocks the channel for reading.
endReceiveMessage(RPCChannel & C)77 inline Error endReceiveMessage(RPCChannel &C) {
78 C.getReadLock().unlock();
79 return Error::success();
80 }
81
82 /// RPC channel serialization for a variadic list of arguments.
83 template <typename T, typename... Ts>
serializeSeq(RPCChannel & C,const T & Arg,const Ts &...Args)84 Error serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) {
85 if (auto Err = serialize(C, Arg))
86 return Err;
87 return serializeSeq(C, Args...);
88 }
89
90 /// RPC channel serialization for an (empty) variadic list of arguments.
serializeSeq(RPCChannel & C)91 inline Error serializeSeq(RPCChannel &C) { return Error::success(); }
92
93 /// RPC channel deserialization for a variadic list of arguments.
94 template <typename T, typename... Ts>
deserializeSeq(RPCChannel & C,T & Arg,Ts &...Args)95 Error deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) {
96 if (auto Err = deserialize(C, Arg))
97 return Err;
98 return deserializeSeq(C, Args...);
99 }
100
101 /// RPC channel serialization for an (empty) variadic list of arguments.
deserializeSeq(RPCChannel & C)102 inline Error deserializeSeq(RPCChannel &C) { return Error::success(); }
103
104 /// RPC channel serialization for integer primitives.
105 template <typename T>
106 typename std::enable_if<
107 std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
108 std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
109 std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
110 std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
111 Error>::type
serialize(RPCChannel & C,T V)112 serialize(RPCChannel &C, T V) {
113 support::endian::byte_swap<T, support::big>(V);
114 return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
115 }
116
117 /// RPC channel deserialization for integer primitives.
118 template <typename T>
119 typename std::enable_if<
120 std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
121 std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
122 std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
123 std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
124 Error>::type
deserialize(RPCChannel & C,T & V)125 deserialize(RPCChannel &C, T &V) {
126 if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
127 return Err;
128 support::endian::byte_swap<T, support::big>(V);
129 return Error::success();
130 }
131
132 /// RPC channel serialization for enums.
133 template <typename T>
134 typename std::enable_if<std::is_enum<T>::value, Error>::type
serialize(RPCChannel & C,T V)135 serialize(RPCChannel &C, T V) {
136 return serialize(C, static_cast<typename std::underlying_type<T>::type>(V));
137 }
138
139 /// RPC channel deserialization for enums.
140 template <typename T>
141 typename std::enable_if<std::is_enum<T>::value, Error>::type
deserialize(RPCChannel & C,T & V)142 deserialize(RPCChannel &C, T &V) {
143 typename std::underlying_type<T>::type Tmp;
144 Error Err = deserialize(C, Tmp);
145 V = static_cast<T>(Tmp);
146 return Err;
147 }
148
149 /// RPC channel serialization for bools.
serialize(RPCChannel & C,bool V)150 inline Error serialize(RPCChannel &C, bool V) {
151 uint8_t VN = V ? 1 : 0;
152 return C.appendBytes(reinterpret_cast<const char *>(&VN), 1);
153 }
154
155 /// RPC channel deserialization for bools.
deserialize(RPCChannel & C,bool & V)156 inline Error deserialize(RPCChannel &C, bool &V) {
157 uint8_t VN = 0;
158 if (auto Err = C.readBytes(reinterpret_cast<char *>(&VN), 1))
159 return Err;
160
161 V = (VN != 0);
162 return Error::success();
163 }
164
165 /// RPC channel serialization for StringRefs.
166 /// Note: There is no corresponding deseralization for this, as StringRef
167 /// doesn't own its memory and so can't hold the deserialized data.
serialize(RPCChannel & C,StringRef S)168 inline Error serialize(RPCChannel &C, StringRef S) {
169 if (auto Err = serialize(C, static_cast<uint64_t>(S.size())))
170 return Err;
171 return C.appendBytes((const char *)S.bytes_begin(), S.size());
172 }
173
174 /// RPC channel serialization for std::strings.
serialize(RPCChannel & C,const std::string & S)175 inline Error serialize(RPCChannel &C, const std::string &S) {
176 return serialize(C, StringRef(S));
177 }
178
179 /// RPC channel deserialization for std::strings.
deserialize(RPCChannel & C,std::string & S)180 inline Error deserialize(RPCChannel &C, std::string &S) {
181 uint64_t Count;
182 if (auto Err = deserialize(C, Count))
183 return Err;
184 S.resize(Count);
185 return C.readBytes(&S[0], Count);
186 }
187
188 // Serialization helper for std::tuple.
189 template <typename TupleT, size_t... Is>
serializeTupleHelper(RPCChannel & C,const TupleT & V,llvm::index_sequence<Is...> _)190 inline Error serializeTupleHelper(RPCChannel &C, const TupleT &V,
191 llvm::index_sequence<Is...> _) {
192 return serializeSeq(C, std::get<Is>(V)...);
193 }
194
195 /// RPC channel serialization for std::tuple.
196 template <typename... ArgTs>
serialize(RPCChannel & C,const std::tuple<ArgTs...> & V)197 inline Error serialize(RPCChannel &C, const std::tuple<ArgTs...> &V) {
198 return serializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());
199 }
200
201 // Serialization helper for std::tuple.
202 template <typename TupleT, size_t... Is>
deserializeTupleHelper(RPCChannel & C,TupleT & V,llvm::index_sequence<Is...> _)203 inline Error deserializeTupleHelper(RPCChannel &C, TupleT &V,
204 llvm::index_sequence<Is...> _) {
205 return deserializeSeq(C, std::get<Is>(V)...);
206 }
207
208 /// RPC channel deserialization for std::tuple.
209 template <typename... ArgTs>
deserialize(RPCChannel & C,std::tuple<ArgTs...> & V)210 inline Error deserialize(RPCChannel &C, std::tuple<ArgTs...> &V) {
211 return deserializeTupleHelper(C, V, llvm::index_sequence_for<ArgTs...>());
212 }
213
214 /// RPC channel serialization for ArrayRef<T>.
serialize(RPCChannel & C,const ArrayRef<T> & A)215 template <typename T> Error serialize(RPCChannel &C, const ArrayRef<T> &A) {
216 if (auto Err = serialize(C, static_cast<uint64_t>(A.size())))
217 return Err;
218
219 for (const auto &E : A)
220 if (auto Err = serialize(C, E))
221 return Err;
222
223 return Error::success();
224 }
225
226 /// RPC channel serialization for std::array<T>.
serialize(RPCChannel & C,const std::vector<T> & V)227 template <typename T> Error serialize(RPCChannel &C, const std::vector<T> &V) {
228 return serialize(C, ArrayRef<T>(V));
229 }
230
231 /// RPC channel deserialization for std::array<T>.
deserialize(RPCChannel & C,std::vector<T> & V)232 template <typename T> Error deserialize(RPCChannel &C, std::vector<T> &V) {
233 uint64_t Count = 0;
234 if (auto Err = deserialize(C, Count))
235 return Err;
236
237 V.resize(Count);
238 for (auto &E : V)
239 if (auto Err = deserialize(C, E))
240 return Err;
241
242 return Error::success();
243 }
244
245 } // end namespace remote
246 } // end namespace orc
247 } // end namespace llvm
248
249 #endif // LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
250