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: 22 std::mutex &getLock() { return Lock; } 23 24 private: 25 std::mutex Lock; 26 }; 27 28 class QueueChannel : public RPCChannel { 29 public: 30 QueueChannel(Queue &InQueue, Queue &OutQueue) 31 : InQueue(InQueue), OutQueue(OutQueue) {} 32 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 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 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 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 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 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