summaryrefslogtreecommitdiff
path: root/unittests/ExecutionEngine/Orc
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/ExecutionEngine/Orc')
-rw-r--r--unittests/ExecutionEngine/Orc/CMakeLists.txt2
-rw-r--r--unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp34
-rw-r--r--unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp3
-rw-r--r--unittests/ExecutionEngine/Orc/Makefile16
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp99
-rw-r--r--unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp77
-rw-r--r--unittests/ExecutionEngine/Orc/OrcCAPITest.cpp4
-rw-r--r--unittests/ExecutionEngine/Orc/OrcTestCommon.h5
-rw-r--r--unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp247
9 files changed, 335 insertions, 152 deletions
diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 41fef24556b11..68f6d0c28d7ca 100644
--- a/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -20,3 +20,5 @@ add_llvm_unittest(OrcJITTests
OrcTestCommon.cpp
RPCUtilsTest.cpp
)
+
+target_link_libraries(OrcJITTests ${PTHREAD_LIB})
diff --git a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
index a27e649b616f8..8140a1ff24939 100644
--- a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp
@@ -18,19 +18,20 @@ namespace {
class DummyCallbackManager : public orc::JITCompileCallbackManager {
public:
- DummyCallbackManager() : JITCompileCallbackManager(0) { }
+ DummyCallbackManager() : JITCompileCallbackManager(0) {}
+
public:
void grow() override { llvm_unreachable("not implemented"); }
};
class DummyStubsManager : public orc::IndirectStubsManager {
public:
- std::error_code createStub(StringRef StubName, TargetAddress InitAddr,
- JITSymbolFlags Flags) override {
+ Error createStub(StringRef StubName, TargetAddress InitAddr,
+ JITSymbolFlags Flags) override {
llvm_unreachable("Not implemented");
}
- std::error_code createStubs(const StubInitsMap &StubInits) override {
+ Error createStubs(const StubInitsMap &StubInits) override {
llvm_unreachable("Not implemented");
}
@@ -42,22 +43,20 @@ public:
llvm_unreachable("Not implemented");
}
- std::error_code updatePointer(StringRef Name,
- TargetAddress NewAddr) override {
+ Error updatePointer(StringRef Name, TargetAddress NewAddr) override {
llvm_unreachable("Not implemented");
}
};
TEST(CompileOnDemandLayerTest, FindSymbol) {
- auto MockBaseLayer =
- createMockBaseLayer<int>(DoNothingAndReturn<int>(0),
- DoNothingAndReturn<void>(),
- [](const std::string &Name, bool) {
- if (Name == "foo")
- return JITSymbol(1, JITSymbolFlags::Exported);
- return JITSymbol(nullptr);
- },
- DoNothingAndReturn<JITSymbol>(nullptr));
+ auto MockBaseLayer = createMockBaseLayer<int>(
+ DoNothingAndReturn<int>(0), DoNothingAndReturn<void>(),
+ [](const std::string &Name, bool) {
+ if (Name == "foo")
+ return JITSymbol(1, JITSymbolFlags::Exported);
+ return JITSymbol(nullptr);
+ },
+ DoNothingAndReturn<JITSymbol>(nullptr));
typedef decltype(MockBaseLayer) MockBaseLayerT;
DummyCallbackManager CallbackMgr;
@@ -68,8 +67,7 @@ TEST(CompileOnDemandLayerTest, FindSymbol) {
auto Sym = COD.findSymbol("foo", true);
- EXPECT_TRUE(!!Sym)
- << "CompileOnDemand::findSymbol should call findSymbol in the base layer.";
+ EXPECT_TRUE(!!Sym) << "CompileOnDemand::findSymbol should call findSymbol in "
+ "the base layer.";
}
-
}
diff --git a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
index 38b60ea7fcd47..ac847039d9fb2 100644
--- a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
+++ b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp
@@ -17,7 +17,8 @@ using namespace llvm;
namespace {
TEST(IndirectionUtilsTest, MakeStub) {
- ModuleBuilder MB(getGlobalContext(), "x86_64-apple-macosx10.10", "");
+ LLVMContext Context;
+ ModuleBuilder MB(Context, "x86_64-apple-macosx10.10", "");
Function *F = MB.createFunctionDecl<void(DummyStruct, DummyStruct)>("");
SmallVector<AttributeSet, 4> Attrs;
Attrs.push_back(
diff --git a/unittests/ExecutionEngine/Orc/Makefile b/unittests/ExecutionEngine/Orc/Makefile
deleted file mode 100644
index c899728e50789..0000000000000
--- a/unittests/ExecutionEngine/Orc/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- unittests/ExecutionEngine/Orc/Makefile --------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-TESTNAME = OrcJIT
-LINK_COMPONENTS := core ipo mcjit orcjit native support
-
-include $(LEVEL)/Makefile.config
-include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
-
diff --git a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
index 59ee01f36010c..87928347d88ed 100644
--- a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
@@ -12,6 +12,7 @@
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
+#include "llvm/ExecutionEngine/Orc/NullResolver.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
@@ -24,19 +25,26 @@ namespace {
class ObjectLinkingLayerExecutionTest : public testing::Test,
public OrcExecutionTest {
+
};
class SectionMemoryManagerWrapper : public SectionMemoryManager {
public:
int FinalizationCount = 0;
- bool finalizeMemory(std::string *ErrMsg = 0) override {
+ int NeedsToReserveAllocationSpaceCount = 0;
+
+ bool needsToReserveAllocationSpace() override {
+ ++NeedsToReserveAllocationSpaceCount;
+ return SectionMemoryManager::needsToReserveAllocationSpace();
+ }
+
+ bool finalizeMemory(std::string *ErrMsg = nullptr) override {
++FinalizationCount;
return SectionMemoryManager::finalizeMemory(ErrMsg);
}
};
TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
-
class SectionMemoryManagerWrapper : public SectionMemoryManager {
public:
SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
@@ -57,9 +65,10 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
ObjectLinkingLayer<> ObjLayer;
- auto M = llvm::make_unique<Module>("", getGlobalContext());
+ LLVMContext Context;
+ auto M = llvm::make_unique<Module>("", Context);
M->setTargetTriple("x86_64-unknown-linux-gnu");
- Type *Int32Ty = IntegerType::get(getGlobalContext(), 32);
+ Type *Int32Ty = IntegerType::get(Context, 32);
GlobalVariable *GV =
new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
ConstantInt::get(Int32Ty, 42), "foo");
@@ -105,9 +114,7 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
}
}
-
TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
-
if (!TM)
return;
@@ -120,15 +127,19 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
// Module 2:
// int bar();
// int foo() { return bar(); }
+ //
+ // Verify that the memory manager is only finalized once (for Module 2).
+ // Failure suggests that finalize is being called on the inner RTDyld
+ // instance (for Module 1) which is unsafe, as it will prevent relocation of
+ // Module 2.
- ModuleBuilder MB1(getGlobalContext(), "", "dummy");
+ ModuleBuilder MB1(Context, "", "dummy");
{
MB1.getModule()->setDataLayout(TM->createDataLayout());
Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
- BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
- BarImpl);
+ BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
IRBuilder<> Builder(BarEntry);
- IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
+ IntegerType *Int32Ty = IntegerType::get(Context, 32);
Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
Builder.CreateRet(FourtyTwo);
}
@@ -137,13 +148,12 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
std::vector<object::ObjectFile*> Obj1Set;
Obj1Set.push_back(Obj1.getBinary());
- ModuleBuilder MB2(getGlobalContext(), "", "dummy");
+ ModuleBuilder MB2(Context, "", "dummy");
{
MB2.getModule()->setDataLayout(TM->createDataLayout());
Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
- BasicBlock *FooEntry = BasicBlock::Create(getGlobalContext(), "entry",
- FooImpl);
+ BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
IRBuilder<> Builder(FooEntry);
Builder.CreateRet(Builder.CreateCall(BarDecl));
}
@@ -155,7 +165,7 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
createLambdaResolver(
[&](const std::string &Name) {
if (auto Sym = ObjLayer.findSymbol(Name, true))
- return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
+ return Sym.toRuntimeDyldSymbol();
return RuntimeDyld::SymbolInfo(nullptr);
},
[](const std::string &Name) {
@@ -173,4 +183,65 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
<< "Extra call to finalize";
}
+TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
+ if (!TM)
+ return;
+
+ ObjectLinkingLayer<> ObjLayer;
+ SimpleCompiler Compile(*TM);
+
+ // Create a pair of unrelated modules:
+ //
+ // Module 1:
+ // int foo() { return 42; }
+ // Module 2:
+ // int bar() { return 7; }
+ //
+ // Both modules will share a memory manager. We want to verify that the
+ // second object is not loaded before the first one is finalized. To do this
+ // in a portable way, we abuse the
+ // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
+ // called once per object before any sections are allocated.
+
+ ModuleBuilder MB1(Context, "", "dummy");
+ {
+ MB1.getModule()->setDataLayout(TM->createDataLayout());
+ Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
+ BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
+ IRBuilder<> Builder(BarEntry);
+ IntegerType *Int32Ty = IntegerType::get(Context, 32);
+ Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
+ Builder.CreateRet(FourtyTwo);
+ }
+
+ auto Obj1 = Compile(*MB1.getModule());
+ std::vector<object::ObjectFile*> Obj1Set;
+ Obj1Set.push_back(Obj1.getBinary());
+
+ ModuleBuilder MB2(Context, "", "dummy");
+ {
+ MB2.getModule()->setDataLayout(TM->createDataLayout());
+ Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
+ BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
+ IRBuilder<> Builder(BarEntry);
+ IntegerType *Int32Ty = IntegerType::get(Context, 32);
+ Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
+ Builder.CreateRet(Seven);
+ }
+ auto Obj2 = Compile(*MB2.getModule());
+ std::vector<object::ObjectFile*> Obj2Set;
+ Obj2Set.push_back(Obj2.getBinary());
+
+ SectionMemoryManagerWrapper SMMW;
+ NullResolver NR;
+ auto H = ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &NR);
+ ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &NR);
+ ObjLayer.emitAndFinalize(H);
+
+ // Only one call to needsToReserveAllocationSpace should have been made.
+ EXPECT_EQ(SMMW.NeedsToReserveAllocationSpaceCount, 1)
+ << "More than one call to needsToReserveAllocationSpace "
+ "(multiple unrelated objects loaded prior to finalization)";
}
+
+} // end anonymous namespace
diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
index c88c94f17b1c9..e1b1f2f927815 100644
--- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
+++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp
@@ -7,9 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/NullResolver.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
+#include "llvm/Object/ObjectFile.h"
#include "gtest/gtest.h"
using namespace llvm::orc;
@@ -51,13 +56,14 @@ public:
template <typename ObjSetT, typename MemoryManagerPtrT,
typename SymbolResolverPtrT>
- ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr,
+ ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver) {
EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
size_t I = 0;
for (auto &ObjPtr : Objects) {
- EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied";
+ EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied";
+ I++;
}
EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
LastCalled = "addObjectSet";
@@ -216,13 +222,14 @@ TEST(ObjectTransformLayerTest, Main) {
auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
M.expectAddObjectSet(Objs1, MM.get(), SR.get());
- auto H = T1.addObjectSet(Objs1, std::move(MM), std::move(SR));
+ auto H = T1.addObjectSet(std::move(Objs1), std::move(MM), std::move(SR));
M.verifyAddObjectSet(H);
// Test addObjectSet with T2 (mutating, naked pointers)
- llvm::SmallVector<MockObjectFile *, 2> Objs2;
- Objs2.push_back(&MockObject1);
- Objs2.push_back(&MockObject2);
+ llvm::SmallVector<MockObjectFile *, 2> Objs2Vec;
+ Objs2Vec.push_back(&MockObject1);
+ Objs2Vec.push_back(&MockObject2);
+ llvm::MutableArrayRef<MockObjectFile *> Objs2(Objs2Vec);
M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
M.verifyAddObjectSet(H);
@@ -271,5 +278,61 @@ TEST(ObjectTransformLayerTest, Main) {
const auto &T1C = T1;
OwnedObj = T1C.getTransform()(std::move(OwnedObj));
EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
+
+ volatile bool RunStaticChecks = false;
+ if (!RunStaticChecks)
+ return;
+
+ // Make sure that ObjectTransformLayer implements the object layer concept
+ // correctly by sandwitching one between an ObjectLinkingLayer and an
+ // IRCompileLayer, verifying that it compiles if we have a call to the
+ // IRComileLayer's addModuleSet that should call the transform layer's
+ // addObjectSet, and also calling the other public transform layer methods
+ // directly to make sure the methods they intend to forward to exist on
+ // the ObjectLinkingLayer.
+
+ // We'll need a concrete MemoryManager class.
+ class NullManager : public llvm::RuntimeDyld::MemoryManager {
+ public:
+ uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
+ llvm::StringRef) override {
+ return nullptr;
+ }
+ uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
+ bool) override {
+ return nullptr;
+ }
+ void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
+ void deregisterEHFrames(uint8_t *, uint64_t, size_t) override {}
+ bool finalizeMemory(std::string *) override { return false; }
+ };
+
+ // Construct the jit layers.
+ ObjectLinkingLayer<> BaseLayer;
+ auto IdentityTransform = [](
+ std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
+ Obj) { return Obj; };
+ ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
+ TransformLayer(BaseLayer, IdentityTransform);
+ auto NullCompiler = [](llvm::Module &) {
+ return llvm::object::OwningBinary<llvm::object::ObjectFile>();
+ };
+ IRCompileLayer<decltype(TransformLayer)> CompileLayer(TransformLayer,
+ NullCompiler);
+
+ // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
+ // compile.
+ NullResolver Resolver;
+ NullManager Manager;
+ CompileLayer.addModuleSet(std::vector<llvm::Module *>(), &Manager, &Resolver);
+
+ // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
+ // compile.
+ decltype(TransformLayer)::ObjSetHandleT ObjSet;
+ TransformLayer.emitAndFinalize(ObjSet);
+ TransformLayer.findSymbolIn(ObjSet, Name, false);
+ TransformLayer.findSymbol(Name, true);
+ TransformLayer.mapSectionAddress(ObjSet, nullptr, 0);
+ TransformLayer.removeObjectSet(ObjSet);
}
}
diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
index 776d26970a311..305325b6c6ef1 100644
--- a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
+++ b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
@@ -25,11 +25,11 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest {
protected:
std::unique_ptr<Module> createTestModule(const Triple &TT) {
- ModuleBuilder MB(getGlobalContext(), TT.str(), "");
+ ModuleBuilder MB(Context, TT.str(), "");
Function *TestFunc = MB.createFunctionDecl<int()>("testFunc");
Function *Main = MB.createFunctionDecl<int(int, char*[])>("main");
- Main->getBasicBlockList().push_back(BasicBlock::Create(getGlobalContext()));
+ Main->getBasicBlockList().push_back(BasicBlock::Create(Context));
IRBuilder<> B(&Main->back());
Value* Result = B.CreateCall(TestFunc);
B.CreateRet(Result);
diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
index f480e0789ae5f..fe3da88dc9d1f 100644
--- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h
+++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h
@@ -46,12 +46,15 @@ public:
if (TM) {
// If we found a TargetMachine, check that it's one that Orc supports.
const Triple& TT = TM->getTargetTriple();
- if (TT.getArch() != Triple::x86_64 || !TT.isOSDarwin())
+
+ if ((TT.getArch() != Triple::x86_64 && TT.getArch() != Triple::x86) ||
+ TT.isOSWindows())
TM = nullptr;
}
};
protected:
+ LLVMContext Context;
std::unique_ptr<TargetMachine> TM;
private:
static bool NativeTargetInitialized;
diff --git a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
index 8215144a514d6..7d55641e4ce2b 100644
--- a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
+++ b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp
@@ -17,131 +17,192 @@ using namespace llvm;
using namespace llvm::orc;
using namespace llvm::orc::remote;
-class QueueChannel : public RPCChannel {
+class Queue : public std::queue<char> {
public:
- QueueChannel(std::queue<char> &Queue) : Queue(Queue) {}
+ std::mutex &getLock() { return Lock; }
+
+private:
+ std::mutex Lock;
+};
- std::error_code readBytes(char *Dst, unsigned Size) override {
- while (Size--) {
- *Dst++ = Queue.front();
- Queue.pop();
+class QueueChannel : public RPCChannel {
+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 std::error_code();
+ return Error::success();
}
- std::error_code appendBytes(const char *Src, unsigned Size) override {
+ Error appendBytes(const char *Src, unsigned Size) override {
+ std::lock_guard<std::mutex> Lock(OutQueue.getLock());
while (Size--)
- Queue.push(*Src++);
- return std::error_code();
+ OutQueue.push(*Src++);
+ return Error::success();
}
- std::error_code send() override { return std::error_code(); }
+ Error send() override { return Error::success(); }
private:
- std::queue<char> &Queue;
+ Queue &InQueue;
+ Queue &OutQueue;
};
-class DummyRPC : public testing::Test,
- public RPC<QueueChannel> {
+class DummyRPC : public testing::Test, public RPC<QueueChannel> {
public:
- typedef Procedure<1, bool> Proc1;
- typedef Procedure<2, int8_t,
- uint8_t,
- int16_t,
- uint16_t,
- int32_t,
- uint32_t,
- int64_t,
- uint64_t,
- bool,
- std::string,
- std::vector<int>> AllTheTypes;
+ enum FuncId : uint32_t {
+ VoidBoolId = RPCFunctionIdTraits<FuncId>::FirstValidId,
+ IntIntId,
+ AllTheTypesId
+ };
+
+ 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;
};
+TEST_F(DummyRPC, TestAsyncVoidBool) {
+ Queue Q1, Q2;
+ QueueChannel C1(Q1, Q2);
+ QueueChannel C2(Q2, Q1);
+
+ // Make an async call.
+ auto ResOrErr = callAsyncWithSeq<VoidBool>(C1, true);
+ EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
-TEST_F(DummyRPC, TestBasic) {
- std::queue<char> Queue;
- QueueChannel C(Queue);
+ {
+ // 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 a call to Proc1.
- auto EC = call<Proc1>(C, true);
- EXPECT_FALSE(EC) << "Simple call over queue failed";
+ // Wait for the result.
+ auto EC = waitForResult(C1, ResOrErr->second, handleNone);
+ EXPECT_FALSE(EC) << "Could not read result.";
}
+ // Verify that the function returned ok.
+ auto Val = ResOrErr->first.get();
+ EXPECT_TRUE(Val) << "Remote void function failed to execute.";
+}
+
+TEST_F(DummyRPC, TestAsyncIntInt) {
+ Queue Q1, Q2;
+ QueueChannel C1(Q1, Q2);
+ QueueChannel C2(Q2, Q1);
+
+ // Make an async call.
+ auto ResOrErr = callAsyncWithSeq<IntInt>(C1, 21);
+ EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed";
+
{
// Expect a call to Proc1.
- auto EC = expect<Proc1>(C,
- [&](bool &B) {
- EXPECT_EQ(B, true)
- << "Bool serialization broken";
- return std::error_code();
- });
+ auto EC = expect<IntInt>(C2, [&](int32_t I) -> Expected<int32_t> {
+ EXPECT_EQ(I, 21) << "Bool serialization broken";
+ return 2 * I;
+ });
EXPECT_FALSE(EC) << "Simple expect over queue failed";
}
+
+ {
+ // Wait for the result.
+ auto EC = waitForResult(C1, ResOrErr->second, handleNone);
+ EXPECT_FALSE(EC) << "Could not read result.";
+ }
+
+ // 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.";
}
TEST_F(DummyRPC, TestSerialization) {
- std::queue<char> Queue;
- QueueChannel C(Queue);
+ Queue Q1, Q2;
+ QueueChannel C1(Q1, Q2);
+ QueueChannel C2(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";
{
- // Make a call to Proc1.
- std::vector<int> v({42, 7});
- auto EC = call<AllTheTypes>(C,
- -101,
- 250,
- -10000,
- 10000,
- -1000000000,
- 1000000000,
- -10000000000,
- 10000000000,
- true,
- "foo",
- v);
+ // 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";
+ return Error::success();
+ });
EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
}
{
- // Expect a call to Proc1.
- auto EC = expect<AllTheTypes>(C,
- [&](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 std::error_code();
- });
- EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
+ // Wait for the result.
+ auto EC = waitForResult(C1, ResOrErr->second, handleNone);
+ EXPECT_FALSE(EC) << "Could not read result.";
}
+
+ // Verify that the function returned ok.
+ auto Val = ResOrErr->first.get();
+ EXPECT_TRUE(Val) << "Remote void function failed to execute.";
}
+
+// 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";
+// }