• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
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 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
11 #include "llvm/ExecutionEngine/Orc/RPCUtils.h"
12 #include "gtest/gtest.h"
13 
14 #include <queue>
15 
16 using namespace llvm;
17 using namespace llvm::orc;
18 using namespace llvm::orc::remote;
19 
20 class Queue : public std::queue<char> {
21 public:
getLock()22   std::mutex &getLock() { return Lock; }
23 
24 private:
25   std::mutex Lock;
26 };
27 
28 class QueueChannel : public RPCChannel {
29 public:
QueueChannel(Queue & InQueue,Queue & OutQueue)30   QueueChannel(Queue &InQueue, Queue &OutQueue)
31       : InQueue(InQueue), OutQueue(OutQueue) {}
32 
readBytes(char * Dst,unsigned Size)33   Error readBytes(char *Dst, unsigned Size) override {
34     while (Size != 0) {
35       // If there's nothing to read then yield.
36       while (InQueue.empty())
37         std::this_thread::yield();
38 
39       // Lock the channel and read what we can.
40       std::lock_guard<std::mutex> Lock(InQueue.getLock());
41       while (!InQueue.empty() && Size) {
42         *Dst++ = InQueue.front();
43         --Size;
44         InQueue.pop();
45       }
46     }
47     return Error::success();
48   }
49 
appendBytes(const char * Src,unsigned Size)50   Error appendBytes(const char *Src, unsigned Size) override {
51     std::lock_guard<std::mutex> Lock(OutQueue.getLock());
52     while (Size--)
53       OutQueue.push(*Src++);
54     return Error::success();
55   }
56 
send()57   Error send() override { return Error::success(); }
58 
59 private:
60   Queue &InQueue;
61   Queue &OutQueue;
62 };
63 
64 class DummyRPC : public testing::Test, public RPC<QueueChannel> {
65 public:
66   enum FuncId : uint32_t {
67     VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId,
68     IntIntId,
69     AllTheTypesId
70   };
71 
72   typedef Function<VoidBoolId, void(bool)> VoidBool;
73   typedef Function<IntIntId, int32_t(int32_t)> IntInt;
74   typedef Function<AllTheTypesId,
75                    void(int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
76                         int64_t, uint64_t, bool, std::string, std::vector<int>)>
77       AllTheTypes;
78 };
79 
TEST_F(DummyRPC,TestAsyncVoidBool)80 TEST_F(DummyRPC, TestAsyncVoidBool) {
81   Queue Q1, Q2;
82   QueueChannel C1(Q1, Q2);
83   QueueChannel C2(Q2, Q1);
84 
85   // Make an async call.
86   auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true);
87   EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
88 
89   {
90     // Expect a call to Proc1.
91     auto EC = expect<VoidBool>(C2, [&](bool &B) {
92       EXPECT_EQ(B, true) << "Bool serialization broken";
93       return Error::success();
94     });
95     EXPECT_FALSE(EC) << "Simple expect over queue failed";
96   }
97 
98   {
99     // Wait for the result.
100     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
101     EXPECT_FALSE(EC) << "Could not read result.";
102   }
103 
104   // Verify that the function returned ok.
105   auto Val = ResOrErr->first.get();
106   EXPECT_TRUE(Val) << "Remote void function failed to execute.";
107 }
108 
TEST_F(DummyRPC,TestAsyncIntInt)109 TEST_F(DummyRPC, TestAsyncIntInt) {
110   Queue Q1, Q2;
111   QueueChannel C1(Q1, Q2);
112   QueueChannel C2(Q2, Q1);
113 
114   // Make an async call.
115   auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21);
116   EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
117 
118   {
119     // Expect a call to Proc1.
120     auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> {
121       EXPECT_EQ(I, 21) << "Bool serialization broken";
122       return 2 * I;
123     });
124     EXPECT_FALSE(EC) << "Simple expect over queue failed";
125   }
126 
127   {
128     // Wait for the result.
129     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
130     EXPECT_FALSE(EC) << "Could not read result.";
131   }
132 
133   // Verify that the function returned ok.
134   auto Val = ResOrErr->first.get();
135   EXPECT_TRUE(!!Val) << "Remote int function failed to execute.";
136   EXPECT_EQ(*Val, 42) << "Remote int function return wrong value.";
137 }
138 
TEST_F(DummyRPC,TestSerialization)139 TEST_F(DummyRPC, TestSerialization) {
140   Queue Q1, Q2;
141   QueueChannel C1(Q1, Q2);
142   QueueChannel C2(Q2, Q1);
143 
144   // Make a call to Proc1.
145   std::vector<int> v({42, 7});
146   auto ResOrErr = callAsyncWithSeq<AllTheTypes>(
147       C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000,
148       10000000000, true, "foo", v);
149   EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed";
150 
151   {
152     // Expect a call to Proc1.
153     auto EC = expect<AllTheTypes>(
154         C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16,
155                 int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t &u64,
156                 bool &b, std::string &s, std::vector<int> &v) {
157 
158           EXPECT_EQ(s8, -101) << "int8_t serialization broken";
159           EXPECT_EQ(u8, 250) << "uint8_t serialization broken";
160           EXPECT_EQ(s16, -10000) << "int16_t serialization broken";
161           EXPECT_EQ(u16, 10000) << "uint16_t serialization broken";
162           EXPECT_EQ(s32, -1000000000) << "int32_t serialization broken";
163           EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization broken";
164           EXPECT_EQ(s64, -10000000000) << "int64_t serialization broken";
165           EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization broken";
166           EXPECT_EQ(b, true) << "bool serialization broken";
167           EXPECT_EQ(s, "foo") << "std::string serialization broken";
168           EXPECT_EQ(v, std::vector<int>({42, 7}))
169               << "std::vector serialization broken";
170           return Error::success();
171         });
172     EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
173   }
174 
175   {
176     // Wait for the result.
177     auto EC = waitForResult(C1, ResOrErr->second, handleNone);
178     EXPECT_FALSE(EC) << "Could not read result.";
179   }
180 
181   // Verify that the function returned ok.
182   auto Val = ResOrErr->first.get();
183   EXPECT_TRUE(Val) << "Remote void function failed to execute.";
184 }
185 
186 // Test the synchronous call API.
187 // FIXME: Re-enable once deadlock encountered on S390 has been debugged / fixed,
188 //        see http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/3459
189 // TEST_F(DummyRPC, TestSynchronousCall) {
190 //   Queue Q1, Q2;
191 //   QueueChannel C1(Q1, Q2);
192 //   QueueChannel C2(Q2, Q1);
193 //
194 //   auto ServerResult =
195 //     std::async(std::launch::async,
196 //       [&]() {
197 //         return expect<IntInt>(C2, [&](int32_t V) { return V; });
198 //       });
199 //
200 //   auto ValOrErr = callST<IntInt>(C1, 42);
201 //
202 //   EXPECT_FALSE(!!ServerResult.get())
203 //     << "Server returned an error.";
204 //   EXPECT_TRUE(!!ValOrErr)
205 //     << "callST returned an error.";
206 //   EXPECT_EQ(*ValOrErr, 42)
207 //     << "Incorrect callST<IntInt> result";
208 // }
209