mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-22 13:05:52 -04:00
273 lines
8.2 KiB
C++
273 lines
8.2 KiB
C++
//===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
|
|
#include "llvm/ExecutionEngine/Orc/RPCUtils.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <queue>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
using namespace llvm::orc::rpc;
|
|
|
|
class Queue : public std::queue<char> {
|
|
public:
|
|
std::mutex &getLock() { return Lock; }
|
|
|
|
private:
|
|
std::mutex Lock;
|
|
};
|
|
|
|
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.
|
|
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();
|
|
}
|
|
}
|
|
return Error::success();
|
|
}
|
|
|
|
Error appendBytes(const char *Src, unsigned Size) override {
|
|
std::lock_guard<std::mutex> Lock(OutQueue.getLock());
|
|
while (Size--)
|
|
OutQueue.push(*Src++);
|
|
return Error::success();
|
|
}
|
|
|
|
Error send() override { return Error::success(); }
|
|
|
|
private:
|
|
Queue &InQueue;
|
|
Queue &OutQueue;
|
|
};
|
|
|
|
class DummyRPCAPI {
|
|
public:
|
|
|
|
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 DummyRPCEndpoint : public DummyRPCAPI,
|
|
public SingleThreadedRPC<QueueChannel> {
|
|
public:
|
|
DummyRPCEndpoint(Queue &Q1, Queue &Q2)
|
|
: SingleThreadedRPC(C, true), C(Q1, Q2) {}
|
|
private:
|
|
QueueChannel C;
|
|
};
|
|
|
|
TEST(DummyRPC, TestAsyncVoidBool) {
|
|
Queue Q1, Q2;
|
|
DummyRPCEndpoint Client(Q1, Q2);
|
|
DummyRPCEndpoint Server(Q2, Q1);
|
|
|
|
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)";
|
|
}
|
|
});
|
|
|
|
{
|
|
// 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)";
|
|
}
|
|
|
|
{
|
|
// 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)";
|
|
}
|
|
|
|
ServerThread.join();
|
|
}
|
|
|
|
TEST(DummyRPC, TestAsyncIntInt) {
|
|
Queue Q1, Q2;
|
|
DummyRPCEndpoint Client(Q1, Q2);
|
|
DummyRPCEndpoint Server(Q2, Q1);
|
|
|
|
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)";
|
|
}
|
|
|
|
{
|
|
// 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)";
|
|
}
|
|
});
|
|
|
|
|
|
{
|
|
// 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";
|
|
}
|
|
|
|
{
|
|
// 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";
|
|
}
|
|
|
|
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";
|
|
// }
|