Skip to content

Commit

Permalink
[Orc] Re-enable the RPC unit test disabled in r286917.
Browse files Browse the repository at this point in the history
This unit test infinite-looped on s390x due to a thread_yield being optimized
out. I've updated the QueueChannel class (where thread_yield was called) to use
a condition variable instead. This should cause the unit test to behave
correctly.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@287121 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
lhames committed Nov 16, 2016
1 parent 195a4bc commit 2ca233e
Showing 1 changed file with 163 additions and 168 deletions.
331 changes: 163 additions & 168 deletions unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ 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 RawByteChannel {
Expand All @@ -31,26 +32,22 @@ class QueueChannel : public RawByteChannel {
: 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();
}

Expand Down Expand Up @@ -93,162 +90,160 @@ class DummyRPCEndpoint : public DummyRPCAPI,
QueueChannel C;
};

// FIXME: Temporarily disabled while the infnite loop discovered in r286639 is
// fixed (see llvm commits list discussion for that commit).

// 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, TestAsyncVoidBool) {
Queue Q1, Q2;
DummyRPCEndpoint Client(Q1, Q2);
DummyRPCEndpoint Server(Q2, Q1);

// 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();
// }
std::thread ServerThread([&]() {
Server.addHandler<DummyRPCAPI::VoidBool>(
[](bool B) {
EXPECT_EQ(B, true)
<< "Server void(bool) received unexpected result";
});

// 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();
// }
{
// 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.
// TEST_F(DummyRPC, TestSynchronousCall) {
Expand Down

0 comments on commit 2ca233e

Please sign in to comment.