llvm-project/llvm/unittests/ExecutionEngine/Orc/ThreadSafeModuleTest.cpp
Lang Hames 0bfa0bcd79
[ORC] Replace ThreadSafeContext::getContext with withContextDo. (#146819)
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).
2025-07-03 17:03:39 +10:00

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