diff options
| author | 2017-01-24 08:32:59 +0000 | |
|---|---|---|
| committer | 2017-01-24 08:32:59 +0000 | |
| commit | 53d771aafdbe5b919f264f53cba3788e2c4cffd2 (patch) | |
| tree | 7eca39498be0ff1e3a6daf583cd9ca5886bb2636 /gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp | |
| parent | In preparation of compiling our kernels with -ffreestanding, explicitly map (diff) | |
| download | wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.tar.xz wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.zip | |
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp')
| -rw-r--r-- | gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp | 546 |
1 files changed, 422 insertions, 124 deletions
diff --git a/gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp index 7d55641e4ce..186c3d40848 100644 --- a/gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp +++ b/gnu/llvm/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ExecutionEngine/Orc/RPCChannel.h" +#include "llvm/ExecutionEngine/Orc/RawByteChannel.h" #include "llvm/ExecutionEngine/Orc/RPCUtils.h" #include "gtest/gtest.h" @@ -15,42 +15,39 @@ using namespace llvm; using namespace llvm::orc; -using namespace llvm::orc::remote; +using namespace llvm::orc::rpc; class Queue : public std::queue<char> { public: - std::mutex &getLock() { return Lock; } - + std::mutex &getMutex() { return M; } + std::condition_variable &getCondVar() { return CV; } private: - std::mutex Lock; + std::mutex M; + std::condition_variable CV; }; -class QueueChannel : public RPCChannel { +class QueueChannel : public RawByteChannel { public: QueueChannel(Queue &InQueue, Queue &OutQueue) : InQueue(InQueue), OutQueue(OutQueue) {} Error readBytes(char *Dst, unsigned Size) override { - while (Size != 0) { - // If there's nothing to read then yield. + std::unique_lock<std::mutex> Lock(InQueue.getMutex()); + while (Size) { while (InQueue.empty()) - std::this_thread::yield(); - - // Lock the channel and read what we can. - std::lock_guard<std::mutex> Lock(InQueue.getLock()); - while (!InQueue.empty() && Size) { - *Dst++ = InQueue.front(); - --Size; - InQueue.pop(); - } + InQueue.getCondVar().wait(Lock); + *Dst++ = InQueue.front(); + --Size; + InQueue.pop(); } return Error::success(); } Error appendBytes(const char *Src, unsigned Size) override { - std::lock_guard<std::mutex> Lock(OutQueue.getLock()); + std::unique_lock<std::mutex> Lock(OutQueue.getMutex()); while (Size--) OutQueue.push(*Src++); + OutQueue.getCondVar().notify_one(); return Error::success(); } @@ -61,148 +58,449 @@ private: Queue &OutQueue; }; -class DummyRPC : public testing::Test, public RPC<QueueChannel> { -public: - enum FuncId : uint32_t { - VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId, - IntIntId, - AllTheTypesId +class RPCFoo {}; + +namespace llvm { +namespace orc { +namespace rpc { + + template <> + class RPCTypeName<RPCFoo> { + public: + static const char* getName() { return "RPCFoo"; } + }; + + template <> + class SerializationTraits<QueueChannel, RPCFoo, RPCFoo> { + public: + static Error serialize(QueueChannel&, const RPCFoo&) { + return Error::success(); + } + + static Error deserialize(QueueChannel&, RPCFoo&) { + return Error::success(); + } }; - typedef Function<VoidBoolId, void(bool)> VoidBool; - typedef Function<IntIntId, int32_t(int32_t)> IntInt; - typedef Function<AllTheTypesId, - void(int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, - int64_t, uint64_t, bool, std::string, std::vector<int>)> - AllTheTypes; +} // end namespace rpc +} // end namespace orc +} // end namespace llvm + +class RPCBar {}; + +namespace llvm { +namespace orc { +namespace rpc { + + template <> + class SerializationTraits<QueueChannel, RPCFoo, RPCBar> { + public: + static Error serialize(QueueChannel&, const RPCBar&) { + return Error::success(); + } + + static Error deserialize(QueueChannel&, RPCBar&) { + return Error::success(); + } }; -TEST_F(DummyRPC, TestAsyncVoidBool) { +} // end namespace rpc +} // end namespace orc +} // end namespace llvm + +namespace DummyRPCAPI { + + class VoidBool : public Function<VoidBool, void(bool)> { + public: + static const char* getName() { return "VoidBool"; } + }; + + class IntInt : public Function<IntInt, int32_t(int32_t)> { + public: + static const char* getName() { return "IntInt"; } + }; + + class AllTheTypes + : public Function<AllTheTypes, + void(int8_t, uint8_t, int16_t, uint16_t, int32_t, + uint32_t, int64_t, uint64_t, bool, std::string, + std::vector<int>)> { + public: + static const char* getName() { return "AllTheTypes"; } + }; + + class CustomType : public Function<CustomType, RPCFoo(RPCFoo)> { + public: + static const char* getName() { return "CustomType"; } + }; + +} + +class DummyRPCEndpoint : public SingleThreadedRPCEndpoint<QueueChannel> { +public: + DummyRPCEndpoint(Queue &Q1, Queue &Q2) + : SingleThreadedRPCEndpoint(C, true), C(Q1, Q2) {} +private: + QueueChannel C; +}; + + +TEST(DummyRPC, TestAsyncVoidBool) { Queue Q1, Q2; - QueueChannel C1(Q1, Q2); - QueueChannel C2(Q2, Q1); + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); - // Make an async call. - auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true); - EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed"; + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::VoidBool>( + [](bool B) { + EXPECT_EQ(B, true) + << "Server void(bool) received unexpected result"; + }); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the VoidBool call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; + } + }); { - // Expect a call to Proc1. - auto EC = expect<VoidBool>(C2, [&](bool &B) { - EXPECT_EQ(B, true) << "Bool serialization broken"; - return Error::success(); - }); - EXPECT_FALSE(EC) << "Simple expect over queue failed"; + // Make an async call. + auto Err = Client.callAsync<DummyRPCAPI::VoidBool>( + [](Error Err) { + EXPECT_FALSE(!!Err) << "Async void(bool) response handler failed"; + return Error::success(); + }, true); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for void(bool)"; } { - // Wait for the result. - auto EC = waitForResult(C1, ResOrErr->second, handleNone); - EXPECT_FALSE(EC) << "Could not read result."; + // Poke the client to process the result of the void(bool) call. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; } - // Verify that the function returned ok. - auto Val = ResOrErr->first.get(); - EXPECT_TRUE(Val) << "Remote void function failed to execute."; + ServerThread.join(); } -TEST_F(DummyRPC, TestAsyncIntInt) { +TEST(DummyRPC, TestAsyncIntInt) { Queue Q1, Q2; - QueueChannel C1(Q1, Q2); - QueueChannel C2(Q2, Q1); + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); - // Make an async call. - auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21); - EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed"; + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::IntInt>( + [](int X) -> int { + EXPECT_EQ(X, 21) << "Server int(int) receieved unexpected result"; + return 2 * X; + }); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the int(int) call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)"; + } + }); + + { + auto Err = Client.callAsync<DummyRPCAPI::IntInt>( + [](Expected<int> Result) { + EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; + EXPECT_EQ(*Result, 42) + << "Async int(int) response handler received incorrect result"; + return Error::success(); + }, 21); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for int(int)"; + } { - // Expect a call to Proc1. - auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> { - EXPECT_EQ(I, 21) << "Bool serialization broken"; - return 2 * I; + // Poke the client to process the result. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; + } + + ServerThread.join(); +} + +TEST(DummyRPC, TestSerialization) { + Queue Q1, Q2; + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); + + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::AllTheTypes>( + [&](int8_t S8, uint8_t U8, int16_t S16, uint16_t U16, + int32_t S32, uint32_t U32, int64_t S64, uint64_t U64, + bool B, std::string S, std::vector<int> V) { + + EXPECT_EQ(S8, -101) << "int8_t serialization broken"; + EXPECT_EQ(U8, 250) << "uint8_t serialization broken"; + EXPECT_EQ(S16, -10000) << "int16_t serialization broken"; + EXPECT_EQ(U16, 10000) << "uint16_t serialization broken"; + EXPECT_EQ(S32, -1000000000) << "int32_t serialization broken"; + EXPECT_EQ(U32, 1000000000ULL) << "uint32_t serialization broken"; + EXPECT_EQ(S64, -10000000000) << "int64_t serialization broken"; + EXPECT_EQ(U64, 10000000000ULL) << "uint64_t serialization broken"; + EXPECT_EQ(B, true) << "bool serialization broken"; + EXPECT_EQ(S, "foo") << "std::string serialization broken"; + EXPECT_EQ(V, std::vector<int>({42, 7})) + << "std::vector serialization broken"; + return Error::success(); + }); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the AllTheTypes call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to void(bool)"; + } }); - EXPECT_FALSE(EC) << "Simple expect over queue failed"; + + + { + // Make an async call. + std::vector<int> v({42, 7}); + auto Err = Client.callAsync<DummyRPCAPI::AllTheTypes>( + [](Error Err) { + EXPECT_FALSE(!!Err) << "Async AllTheTypes response handler failed"; + return Error::success(); + }, + static_cast<int8_t>(-101), static_cast<uint8_t>(250), + static_cast<int16_t>(-10000), static_cast<uint16_t>(10000), + static_cast<int32_t>(-1000000000), static_cast<uint32_t>(1000000000), + static_cast<int64_t>(-10000000000), static_cast<uint64_t>(10000000000), + true, std::string("foo"), v); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for AllTheTypes"; } { - // Wait for the result. - auto EC = waitForResult(C1, ResOrErr->second, handleNone); - EXPECT_FALSE(EC) << "Could not read result."; + // Poke the client to process the result of the AllTheTypes call. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) << "Client failed to handle response from AllTheTypes"; } - // Verify that the function returned ok. - auto Val = ResOrErr->first.get(); - EXPECT_TRUE(!!Val) << "Remote int function failed to execute."; - EXPECT_EQ(*Val, 42) << "Remote int function return wrong value."; + ServerThread.join(); } -TEST_F(DummyRPC, TestSerialization) { +TEST(DummyRPC, TestCustomType) { Queue Q1, Q2; - QueueChannel C1(Q1, Q2); - QueueChannel C2(Q2, Q1); + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); - // Make a call to Proc1. - std::vector<int> v({42, 7}); - auto ResOrErr = callAsyncWithSeq<AllTheTypes>( - C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000, - 10000000000, true, "foo", v); - EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed"; + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::CustomType>( + [](RPCFoo F) {}); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the CustomType call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)"; + } + }); { - // Expect a call to Proc1. - auto EC = expect<AllTheTypes>( - C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16, - int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t &u64, - bool &b, std::string &s, std::vector<int> &v) { - - EXPECT_EQ(s8, -101) << "int8_t serialization broken"; - EXPECT_EQ(u8, 250) << "uint8_t serialization broken"; - EXPECT_EQ(s16, -10000) << "int16_t serialization broken"; - EXPECT_EQ(u16, 10000) << "uint16_t serialization broken"; - EXPECT_EQ(s32, -1000000000) << "int32_t serialization broken"; - EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization broken"; - EXPECT_EQ(s64, -10000000000) << "int64_t serialization broken"; - EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization broken"; - EXPECT_EQ(b, true) << "bool serialization broken"; - EXPECT_EQ(s, "foo") << "std::string serialization broken"; - EXPECT_EQ(v, std::vector<int>({42, 7})) - << "std::vector serialization broken"; + // Make an async call. + auto Err = Client.callAsync<DummyRPCAPI::CustomType>( + [](Expected<RPCFoo> FOrErr) { + EXPECT_TRUE(!!FOrErr) + << "Async RPCFoo(RPCFoo) response handler failed"; return Error::success(); - }); - EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed"; + }, RPCFoo()); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)"; } { - // Wait for the result. - auto EC = waitForResult(C1, ResOrErr->second, handleNone); - EXPECT_FALSE(EC) << "Could not read result."; + // Poke the client to process the result of the RPCFoo() call. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) + << "Client failed to handle response from RPCFoo(RPCFoo)"; } - // Verify that the function returned ok. - auto Val = ResOrErr->first.get(); - EXPECT_TRUE(Val) << "Remote void function failed to execute."; + ServerThread.join(); } -// Test the synchronous call API. -// FIXME: Re-enable once deadlock encountered on S390 has been debugged / fixed, -// see http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/3459 -// TEST_F(DummyRPC, TestSynchronousCall) { -// Queue Q1, Q2; -// QueueChannel C1(Q1, Q2); -// QueueChannel C2(Q2, Q1); -// -// auto ServerResult = -// std::async(std::launch::async, -// [&]() { -// return expect<IntInt>(C2, [&](int32_t V) { return V; }); -// }); -// -// auto ValOrErr = callST<IntInt>(C1, 42); -// -// EXPECT_FALSE(!!ServerResult.get()) -// << "Server returned an error."; -// EXPECT_TRUE(!!ValOrErr) -// << "callST returned an error."; -// EXPECT_EQ(*ValOrErr, 42) -// << "Incorrect callST<IntInt> result"; -// } +TEST(DummyRPC, TestWithAltCustomType) { + Queue Q1, Q2; + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); + + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::CustomType>( + [](RPCBar F) {}); + + { + // Poke the server to handle the negotiate call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to negotiate"; + } + + { + // Poke the server to handle the CustomType call. + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to RPCFoo(RPCFoo)"; + } + }); + + { + // Make an async call. + auto Err = Client.callAsync<DummyRPCAPI::CustomType>( + [](Expected<RPCBar> FOrErr) { + EXPECT_TRUE(!!FOrErr) + << "Async RPCFoo(RPCFoo) response handler failed"; + return Error::success(); + }, RPCBar()); + EXPECT_FALSE(!!Err) << "Client.callAsync failed for RPCFoo(RPCFoo)"; + } + + { + // Poke the client to process the result of the RPCFoo() call. + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) + << "Client failed to handle response from RPCFoo(RPCFoo)"; + } + + ServerThread.join(); +} + +TEST(DummyRPC, TestParallelCallGroup) { + Queue Q1, Q2; + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); + + std::thread ServerThread([&]() { + Server.addHandler<DummyRPCAPI::IntInt>( + [](int X) -> int { + return 2 * X; + }); + + // Handle the negotiate, plus three calls. + for (unsigned I = 0; I != 4; ++I) { + auto Err = Server.handleOne(); + EXPECT_FALSE(!!Err) << "Server failed to handle call to int(int)"; + } + }); + + { + int A, B, C; + ParallelCallGroup<DummyRPCEndpoint> PCG(Client); + + { + auto Err = PCG.appendCall<DummyRPCAPI::IntInt>( + [&A](Expected<int> Result) { + EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; + A = *Result; + return Error::success(); + }, 1); + EXPECT_FALSE(!!Err) << "First parallel call failed for int(int)"; + } + + { + auto Err = PCG.appendCall<DummyRPCAPI::IntInt>( + [&B](Expected<int> Result) { + EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; + B = *Result; + return Error::success(); + }, 2); + EXPECT_FALSE(!!Err) << "Second parallel call failed for int(int)"; + } + + { + auto Err = PCG.appendCall<DummyRPCAPI::IntInt>( + [&C](Expected<int> Result) { + EXPECT_TRUE(!!Result) << "Async int(int) response handler failed"; + C = *Result; + return Error::success(); + }, 3); + EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)"; + } + + // Handle the three int(int) results. + for (unsigned I = 0; I != 3; ++I) { + auto Err = Client.handleOne(); + EXPECT_FALSE(!!Err) << "Client failed to handle response from void(bool)"; + } + + { + auto Err = PCG.wait(); + EXPECT_FALSE(!!Err) << "Third parallel call failed for int(int)"; + } + + EXPECT_EQ(A, 2) << "First parallel call returned bogus result"; + EXPECT_EQ(B, 4) << "Second parallel call returned bogus result"; + EXPECT_EQ(C, 6) << "Third parallel call returned bogus result"; + } + + ServerThread.join(); +} + +TEST(DummyRPC, TestAPICalls) { + + using DummyCalls1 = APICalls<DummyRPCAPI::VoidBool, DummyRPCAPI::IntInt>; + using DummyCalls2 = APICalls<DummyRPCAPI::AllTheTypes>; + using DummyCalls3 = APICalls<DummyCalls1, DummyRPCAPI::CustomType>; + using DummyCallsAll = APICalls<DummyCalls1, DummyCalls2, DummyRPCAPI::CustomType>; + + static_assert(DummyCalls1::Contains<DummyRPCAPI::VoidBool>::value, + "Contains<Func> template should return true here"); + static_assert(!DummyCalls1::Contains<DummyRPCAPI::CustomType>::value, + "Contains<Func> template should return false here"); + + Queue Q1, Q2; + DummyRPCEndpoint Client(Q1, Q2); + DummyRPCEndpoint Server(Q2, Q1); + + std::thread ServerThread( + [&]() { + Server.addHandler<DummyRPCAPI::VoidBool>([](bool b) { }); + Server.addHandler<DummyRPCAPI::IntInt>([](int x) { return x; }); + Server.addHandler<DummyRPCAPI::CustomType>([](RPCFoo F) {}); + + for (unsigned I = 0; I < 4; ++I) { + auto Err = Server.handleOne(); + (void)!!Err; + } + }); + + { + auto Err = DummyCalls1::negotiate(Client); + EXPECT_FALSE(!!Err) << "DummyCalls1::negotiate failed"; + } + + { + auto Err = DummyCalls3::negotiate(Client); + EXPECT_FALSE(!!Err) << "DummyCalls3::negotiate failed"; + } + + { + auto Err = DummyCallsAll::negotiate(Client); + EXPECT_EQ(errorToErrorCode(std::move(Err)).value(), + static_cast<int>(OrcErrorCode::UnknownRPCFunction)) + << "Expected 'UnknownRPCFunction' error for attempted negotiate of " + "unsupported function"; + } + + ServerThread.join(); +} |
