| //===- 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/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<SPSError(SPSExecutorAddr)>::handle( |
| ArgData, ArgSize, |
| [](ExecutorAddr A) -> Error { |
| *A.toPtr<int *>() += 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<ExecutorAddr> 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<void> P; |
| auto F = P.get_future(); |
| |
| { |
| std::unique_ptr<MemoryMapper> Mapper = |
| cantFail(SharedMemoryMapper::Create(*SelfEPC, SAs)); |
| |
| auto PageSize = Mapper->getPageSize(); |
| size_t ReqSize = PageSize; |
| |
| Mapper->reserve(ReqSize, [&](Expected<ExecutorAddrRange> 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<SPSArgList<SPSExecutorAddr>>( |
| ExecutorAddr::fromPtr(incrementWrapper), |
| ExecutorAddr::fromPtr(&InitializeCounter))), |
| cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( |
| ExecutorAddr::fromPtr(incrementWrapper), |
| ExecutorAddr::fromPtr(&DeinitializeCounter)))}); |
| } |
| |
| EXPECT_EQ(InitializeCounter, 0); |
| EXPECT_EQ(DeinitializeCounter, 0); |
| |
| Mapper->initialize(AI, [&, Reservation](Expected<ExecutorAddr> Result) { |
| EXPECT_THAT_ERROR(Result.takeError(), Succeeded()); |
| |
| EXPECT_EQ(TestString, std::string(static_cast<char *>( |
| Reservation.Start.toPtr<char *>()))); |
| |
| 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 |