• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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