
This removes ThreadSafeContext::Lock, ThreadSafeContext::getLock, and ThreadSafeContext::getContext, and replaces them with a ThreadSafeContext::withContextDo method (and const override). The new method can be used to access an existing ThreadSafeContext-wrapped LLVMContext in a safe way: ThreadSafeContext TSCtx = ... ; TSCtx.withContextDo([](LLVMContext *Ctx) { // this closure has exclusive access to Ctx. }); The new API enforces correct locking, whereas the old APIs relied on manual locking (which almost no in-tree code preformed, relying instead on incidental exclusive access to the ThreadSafeContext).
107 lines
3.7 KiB
C++
107 lines
3.7 KiB
C++
//===--- ThreadSafeModuleTest.cpp - Test basic use of ThreadSafeModule ----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <atomic>
|
|
#include <future>
|
|
#include <thread>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
|
|
namespace {
|
|
|
|
TEST(ThreadSafeModuleTest, ContextWhollyOwnedByOneModule) {
|
|
// Test that ownership of a context can be transferred to a single
|
|
// ThreadSafeModule.
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("M", *Ctx);
|
|
ThreadSafeModule TSM(std::move(M), std::move(Ctx));
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, ContextOwnershipSharedByTwoModules) {
|
|
// Test that ownership of a context can be shared between more than one
|
|
// ThreadSafeModule.
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
|
|
auto M1 = std::make_unique<Module>("M1", *Ctx);
|
|
auto M2 = std::make_unique<Module>("M2", *Ctx);
|
|
|
|
ThreadSafeContext TSCtx(std::move(Ctx));
|
|
ThreadSafeModule TSM1(std::move(M1), TSCtx);
|
|
ThreadSafeModule TSM2(std::move(M2), std::move(TSCtx));
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, ContextOwnershipSharedWithClient) {
|
|
// Test that ownership of a context can be shared with a client-held
|
|
// ThreadSafeContext so that it can be re-used for new modules.
|
|
ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
|
|
|
|
{
|
|
// Create and destroy a module.
|
|
auto M1 = TSCtx.withContextDo(
|
|
[](LLVMContext *Ctx) { return std::make_unique<Module>("M1", *Ctx); });
|
|
ThreadSafeModule TSM1(std::move(M1), TSCtx);
|
|
}
|
|
|
|
// Verify that the context is still available for re-use.
|
|
auto M2 = TSCtx.withContextDo(
|
|
[](LLVMContext *Ctx) { return std::make_unique<Module>("M2", *Ctx); });
|
|
ThreadSafeModule TSM2(std::move(M2), std::move(TSCtx));
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, ThreadSafeModuleMoveAssignment) {
|
|
// Move assignment needs to move the module before the context (opposite
|
|
// to the field order) to ensure that overwriting with an empty
|
|
// ThreadSafeModule does not destroy the context early.
|
|
ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
|
|
auto M = TSCtx.withContextDo(
|
|
[](LLVMContext *Ctx) { return std::make_unique<Module>("M", *Ctx); });
|
|
ThreadSafeModule TSM(std::move(M), std::move(TSCtx));
|
|
TSM = ThreadSafeModule();
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, WithContextDoPreservesContext) {
|
|
// Test that withContextDo passes through the LLVMContext that was used
|
|
// to create the ThreadSafeContext.
|
|
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
LLVMContext *OriginalCtx = Ctx.get();
|
|
ThreadSafeContext TSCtx(std::move(Ctx));
|
|
TSCtx.withContextDo(
|
|
[&](LLVMContext *ClosureCtx) { EXPECT_EQ(ClosureCtx, OriginalCtx); });
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, WithModuleDo) {
|
|
// Test non-const version of withModuleDo.
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("M", *Ctx);
|
|
ThreadSafeModule TSM(std::move(M), std::move(Ctx));
|
|
TSM.withModuleDo([](Module &M) {});
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, WithModuleDoConst) {
|
|
// Test const version of withModuleDo.
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("M", *Ctx);
|
|
const ThreadSafeModule TSM(std::move(M), std::move(Ctx));
|
|
TSM.withModuleDo([](const Module &M) {});
|
|
}
|
|
|
|
TEST(ThreadSafeModuleTest, ConsumingModuleDo) {
|
|
// Test consumingModuleDo.
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("M", *Ctx);
|
|
ThreadSafeModule TSM(std::move(M), std::move(Ctx));
|
|
TSM.consumingModuleDo([](std::unique_ptr<Module> M) {});
|
|
}
|
|
|
|
} // end anonymous namespace
|