//===- SharedMemoryMapperTest.cpp -- Tests for SharedMemoryMapper ---------===// // // 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 "OrcTestCommon.h" #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h" #include "llvm/Testing/Support/Error.h" using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::shared; using namespace llvm::orc::rt_bootstrap; #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32) // A basic function to be used as both initializer/deinitializer orc::shared::CWrapperFunctionResult incrementWrapper(const char *ArgData, size_t ArgSize) { return WrapperFunction::handle( ArgData, ArgSize, [](ExecutorAddr A) -> Error { *A.toPtr() += 1; return Error::success(); }) .release(); } TEST(SharedMemoryMapperTest, MemReserveInitializeDeinitializeRelease) { // These counters are used to track how many times the initializer and // deinitializer functions are called int InitializeCounter = 0; int DeinitializeCounter = 0; auto SelfEPC = cantFail(SelfExecutorProcessControl::Create()); ExecutorSharedMemoryMapperService MapperService; SharedMemoryMapper::SymbolAddrs SAs; { StringMap Map; MapperService.addBootstrapSymbols(Map); SAs.Instance = Map[rt::ExecutorSharedMemoryMapperServiceInstanceName]; SAs.Reserve = Map[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName]; SAs.Initialize = Map[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName]; SAs.Deinitialize = Map[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName]; SAs.Release = Map[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName]; } std::string TestString = "Hello, World!"; // barrier std::promise P; auto F = P.get_future(); { std::unique_ptr Mapper = cantFail(SharedMemoryMapper::Create(*SelfEPC, SAs)); auto PageSize = Mapper->getPageSize(); size_t ReqSize = PageSize; Mapper->reserve(ReqSize, [&](Expected Result) { EXPECT_THAT_ERROR(Result.takeError(), Succeeded()); auto Reservation = std::move(*Result); { char *Addr = Mapper->prepare(Reservation.Start, TestString.size() + 1); std::strcpy(Addr, TestString.c_str()); } MemoryMapper::AllocInfo AI; { MemoryMapper::AllocInfo::SegInfo SI; SI.Offset = 0; SI.ContentSize = TestString.size() + 1; SI.ZeroFillSize = PageSize - SI.ContentSize; SI.AG = MemProt::Read | MemProt::Write; AI.MappingBase = Reservation.Start; AI.Segments.push_back(SI); AI.Actions.push_back( {cantFail(WrapperFunctionCall::Create>( ExecutorAddr::fromPtr(incrementWrapper), ExecutorAddr::fromPtr(&InitializeCounter))), cantFail(WrapperFunctionCall::Create>( ExecutorAddr::fromPtr(incrementWrapper), ExecutorAddr::fromPtr(&DeinitializeCounter)))}); } EXPECT_EQ(InitializeCounter, 0); EXPECT_EQ(DeinitializeCounter, 0); Mapper->initialize(AI, [&, Reservation](Expected Result) { EXPECT_THAT_ERROR(Result.takeError(), Succeeded()); EXPECT_EQ(TestString, std::string(static_cast( Reservation.Start.toPtr()))); EXPECT_EQ(InitializeCounter, 1); EXPECT_EQ(DeinitializeCounter, 0); Mapper->deinitialize({*Result}, [&, Reservation](Error Err) { EXPECT_THAT_ERROR(std::move(Err), Succeeded()); EXPECT_EQ(InitializeCounter, 1); EXPECT_EQ(DeinitializeCounter, 1); Mapper->release({Reservation.Start}, [&](Error Err) { EXPECT_THAT_ERROR(std::move(Err), Succeeded()); P.set_value(); }); }); }); }); // This will block the test if any of the above callbacks are not executed F.wait(); // Mapper must be destructed before calling shutdown to avoid double free } EXPECT_THAT_ERROR(MapperService.shutdown(), Succeeded()); cantFail(SelfEPC->disconnect()); } #endif