From 612d80348f79502ad0f3ee2b5a4c8d47477c3f23 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 17 Mar 2026 21:39:09 +1100 Subject: [PATCH] [orc-rt] Move SPS controller interface funcs into their own headers. (#186991) This provides clean separation between the ORC runtime code that implements runtime functionality and the wrapper functions that permit this code to be called from the controller via the ExecutorProcessControl API. Separating the controller interface from the implementation functions should allow clients to introduce alternative serialization schemes if they want (e.g. JSON). In particular, this commit adds a new orc-rt/include/orc-rt/sps-ci directory and moves SimpleNativeMemoryMap SPS controller interface into a new header in that directory. This commit also splits the implementation and testing of the SPS controller interface for SimpleNativeMemoryMap into separate files. --- orc-rt/include/CMakeLists.txt | 2 + orc-rt/include/orc-rt/ControllerInterface.h | 2 + orc-rt/include/orc-rt/SPSWrapperFunction.h | 7 +- orc-rt/include/orc-rt/SimpleNativeMemoryMap.h | 19 -- orc-rt/include/orc-rt/sps-ci/AllSPSCI.h | 26 ++ .../sps-ci/SimpleNativeMemoryMapSPSCI.h | 25 ++ orc-rt/lib/executor/CMakeLists.txt | 2 + orc-rt/lib/executor/SimpleNativeMemoryMap.cpp | 83 ----- orc-rt/lib/executor/sps-ci/AllSPSCI.cpp | 28 ++ .../sps-ci/SimpleNativeMemoryMapSPSCI.cpp | 101 ++++++ orc-rt/unittests/CMakeLists.txt | 2 + orc-rt/unittests/CommonTestUtils.h | 16 + .../SimpleNativeMemoryMapSPSCITest.cpp | 319 ++++++++++++++++++ .../unittests/SimpleNativeMemoryMapTest.cpp | 252 ++++---------- 14 files changed, 598 insertions(+), 286 deletions(-) create mode 100644 orc-rt/include/orc-rt/sps-ci/AllSPSCI.h create mode 100644 orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h create mode 100644 orc-rt/lib/executor/sps-ci/AllSPSCI.cpp create mode 100644 orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp create mode 100644 orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt index df381d5223a4..e16941b9d24f 100644 --- a/orc-rt/include/CMakeLists.txt +++ b/orc-rt/include/CMakeLists.txt @@ -23,6 +23,8 @@ set(ORC_RT_HEADERS orc-rt/SimpleNativeMemoryMap.h orc-rt/SimplePackedSerialization.h orc-rt/SPSAllocAction.h + orc-rt/sps-ci/AllSPSCI.h + orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h orc-rt/SPSMemoryFlags.h orc-rt/SPSWrapperFunction.h orc-rt/SPSWrapperFunctionBuffer.h diff --git a/orc-rt/include/orc-rt/ControllerInterface.h b/orc-rt/include/orc-rt/ControllerInterface.h index 0955c6d57c90..54b310bf9e6e 100644 --- a/orc-rt/include/orc-rt/ControllerInterface.h +++ b/orc-rt/include/orc-rt/ControllerInterface.h @@ -19,6 +19,8 @@ #include #include +#define ORC_RT_SYMTAB_PAIR(sym) {{#sym}, reinterpret_cast(&sym)} + namespace orc_rt { /// A symbol table defining the interface exposed by the ORC runtime to the diff --git a/orc-rt/include/orc-rt/SPSWrapperFunction.h b/orc-rt/include/orc-rt/SPSWrapperFunction.h index d61792db9435..4f32179545e5 100644 --- a/orc-rt/include/orc-rt/SPSWrapperFunction.h +++ b/orc-rt/include/orc-rt/SPSWrapperFunction.h @@ -18,7 +18,12 @@ #include "orc-rt/SimplePackedSerialization.h" #include "orc-rt/WrapperFunction.h" -#define ORC_RT_SPS_INTERFACE ORC_RT_INTERFACE +#define ORC_RT_SPS_WRAPPER(Name, SPSSig, Handle) \ + static void Name(orc_rt_SessionRef S, uint64_t CallId, \ + orc_rt_WrapperFunctionReturn Return, \ + orc_rt_WrapperFunctionBuffer ArgBytes) { \ + SPSWrapperFunction::handle(S, CallId, Return, ArgBytes, Handle); \ + } namespace orc_rt { namespace detail { diff --git a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h index 067702654cb5..d98e094c6fb9 100644 --- a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h +++ b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h @@ -16,7 +16,6 @@ #include "orc-rt/AllocAction.h" #include "orc-rt/Error.h" #include "orc-rt/MemoryFlags.h" -#include "orc-rt/SPSWrapperFunction.h" #include "orc-rt/Service.h" #include "orc-rt/move_only_function.h" @@ -113,22 +112,4 @@ private: } // namespace orc_rt -ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes); - -ORC_RT_SPS_INTERFACE void -orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes); - -ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes); - -ORC_RT_SPS_INTERFACE void -orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes); - #endif // ORC_RT_SIMPLENATIVEMEMORYMAP_H diff --git a/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h b/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h new file mode 100644 index 000000000000..e92ba6ad3914 --- /dev/null +++ b/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h @@ -0,0 +1,26 @@ +//===- AllSPSCI.h -- All SPS Controller Interface registrations -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Convenience header that includes all SPS Controller Interface headers and +// declares addAll. +// +//===----------------------------------------------------------------------===// + +#ifndef ORC_RT_SPS_CI_ALLSPSCI_H +#define ORC_RT_SPS_CI_ALLSPSCI_H + +#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h" + +namespace orc_rt::sps_ci { + +/// Add all SPS interfaces to the controller interface. +Error addAll(ControllerInterface &CI); + +} // namespace orc_rt::sps_ci + +#endif // ORC_RT_SPS_CI_ALLSPSCI_H diff --git a/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h b/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h new file mode 100644 index 000000000000..7d8e705e1b3a --- /dev/null +++ b/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h @@ -0,0 +1,25 @@ +//===------- SimpleNativeMemoryMapSPSCI.h -- SNMM SPS CI --------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// SPS Controller Interface registration for SimpleNativeMemoryMap. +// +//===----------------------------------------------------------------------===// + +#ifndef ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H +#define ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H + +#include "orc-rt/ControllerInterface.h" + +namespace orc_rt::sps_ci { + +/// Add the SimpleNativeMemoryMap SPS interface to the controller interface. +Error addSimpleNativeMemoryMap(ControllerInterface &CI); + +} // namespace orc_rt::sps_ci + +#endif // ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt index 752006430273..6d05386a097f 100644 --- a/orc-rt/lib/executor/CMakeLists.txt +++ b/orc-rt/lib/executor/CMakeLists.txt @@ -9,6 +9,8 @@ set(files SimpleNativeMemoryMap.cpp TaskDispatcher.cpp ThreadPoolTaskDispatcher.cpp + sps-ci/AllSPSCI.cpp + sps-ci/SimpleNativeMemoryMapSPSCI.cpp ) add_library(orc-rt-executor STATIC ${files}) diff --git a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp index 378e0a3907fc..49ccf9382a00 100644 --- a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp +++ b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp @@ -14,8 +14,6 @@ //===----------------------------------------------------------------------===// #include "orc-rt/SimpleNativeMemoryMap.h" -#include "orc-rt/SPSAllocAction.h" -#include "orc-rt/SPSMemoryFlags.h" #include #if defined(__APPLE__) || defined(__linux__) @@ -26,47 +24,6 @@ namespace orc_rt { -struct SPSSimpleNativeMemoryMapSegment; - -template <> -class SPSSerializationTraits< - SPSSimpleNativeMemoryMapSegment, - SimpleNativeMemoryMap::InitializeRequest::Segment> { - using SPSType = - SPSTuple>; - -public: - static bool - deserialize(SPSInputBuffer &IB, - SimpleNativeMemoryMap::InitializeRequest::Segment &S) { - AllocGroup AG; - ExecutorAddr Address; - uint64_t Size; - span Content; - if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content)) - return false; - if (Size > std::numeric_limits::max()) - return false; - S = {AG, Address.toPtr(), static_cast(Size), Content}; - return true; - } -}; - -struct SPSSimpleNativeMemoryMapInitializeRequest; - -template <> -class SPSSerializationTraits { - using SPSType = SPSTuple, - SPSSequence>; - -public: - static bool deserialize(SPSInputBuffer &IB, - SimpleNativeMemoryMap::InitializeRequest &FR) { - return SPSType::AsArgList::deserialize(IB, FR.Segments, FR.AAPs); - } -}; - void SimpleNativeMemoryMap::reserve(OnReserveCompleteFn &&OnComplete, size_t Size) { // FIXME: Get page size from session object. @@ -366,44 +323,4 @@ Error SimpleNativeMemoryMap::recordDeallocActions( return Error::success(); } -ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes) { - using Sig = SPSExpected(SPSExecutorAddr, SPSSize); - SPSWrapperFunction::handle( - S, CallId, Return, ArgBytes, - WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve)); -} - -ORC_RT_SPS_INTERFACE void -orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes) { - using Sig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::handle(S, CallId, Return, ArgBytes, - WrapperFunction::handleWithAsyncMethod( - &SimpleNativeMemoryMap::releaseMultiple)); -} - -ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes) { - using Sig = SPSExpected( - SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest); - SPSWrapperFunction::handle(S, CallId, Return, ArgBytes, - WrapperFunction::handleWithAsyncMethod( - &SimpleNativeMemoryMap::initialize)); -} - -ORC_RT_SPS_INTERFACE void -orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper( - orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return, - orc_rt_WrapperFunctionBuffer ArgBytes) { - using Sig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::handle( - S, CallId, Return, ArgBytes, - WrapperFunction::handleWithAsyncMethod( - &SimpleNativeMemoryMap::deinitializeMultiple)); -} - } // namespace orc_rt diff --git a/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp b/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp new file mode 100644 index 000000000000..e1f002781132 --- /dev/null +++ b/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp @@ -0,0 +1,28 @@ +//===- AllSPSCI.cpp -------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implementation of sps_ci::addAll. +// +//===----------------------------------------------------------------------===// + +#include "orc-rt/sps-ci/AllSPSCI.h" + +namespace orc_rt::sps_ci { + +Error addAll(ControllerInterface &CI) { + using AdderFn = Error (*)(ControllerInterface &); + AdderFn Adders[] = {addSimpleNativeMemoryMap}; + + for (auto *Adder : Adders) + if (auto Err = Adder(CI)) + return Err; + + return Error::success(); +} + +} // namespace orc_rt::sps_ci diff --git a/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp b/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp new file mode 100644 index 000000000000..466cf725750f --- /dev/null +++ b/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp @@ -0,0 +1,101 @@ +//===- SimpleNativeMemoryMapSPSCI.cpp -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// SPS Controller Interface implementation for SimpleNativeMemoryMap. +// +//===----------------------------------------------------------------------===// + +#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h" + +#include "orc-rt/SPSAllocAction.h" +#include "orc-rt/SPSMemoryFlags.h" +#include "orc-rt/SPSWrapperFunction.h" +#include "orc-rt/SimpleNativeMemoryMap.h" + +namespace orc_rt { + +struct SPSSimpleNativeMemoryMapSegment; + +template <> +class SPSSerializationTraits< + SPSSimpleNativeMemoryMapSegment, + SimpleNativeMemoryMap::InitializeRequest::Segment> { + using SPSType = + SPSTuple>; + +public: + static bool + deserialize(SPSInputBuffer &IB, + SimpleNativeMemoryMap::InitializeRequest::Segment &S) { + AllocGroup AG; + ExecutorAddr Address; + uint64_t Size; + span Content; + if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content)) + return false; + if (Size > std::numeric_limits::max()) + return false; + S = {AG, Address.toPtr(), static_cast(Size), Content}; + return true; + } +}; + +struct SPSSimpleNativeMemoryMapInitializeRequest; + +template <> +class SPSSerializationTraits { + using SPSType = SPSTuple, + SPSSequence>; + +public: + static bool deserialize(SPSInputBuffer &IB, + SimpleNativeMemoryMap::InitializeRequest &FR) { + return SPSType::AsArgList::deserialize(IB, FR.Segments, FR.AAPs); + } +}; + +namespace sps_ci { + +ORC_RT_SPS_WRAPPER( + orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper, + SPSExpected(SPSExecutorAddr, SPSSize), + WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve)) + +ORC_RT_SPS_WRAPPER(orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper, + SPSError(SPSExecutorAddr, SPSSequence), + WrapperFunction::handleWithAsyncMethod( + &SimpleNativeMemoryMap::releaseMultiple)) + +ORC_RT_SPS_WRAPPER( + orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper, + SPSExpected(SPSExecutorAddr, + SPSSimpleNativeMemoryMapInitializeRequest), + WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::initialize)) + +ORC_RT_SPS_WRAPPER( + orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper, + SPSError(SPSExecutorAddr, SPSSequence), + WrapperFunction::handleWithAsyncMethod( + &SimpleNativeMemoryMap::deinitializeMultiple)) + +static std::pair + orc_rt_SimpleNativeMemoryMap_sps_interface[] = { + ORC_RT_SYMTAB_PAIR(orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper), + ORC_RT_SYMTAB_PAIR( + orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper), + ORC_RT_SYMTAB_PAIR(orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper), + ORC_RT_SYMTAB_PAIR( + orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper)}; + +Error addSimpleNativeMemoryMap(ControllerInterface &CI) { + return CI.addSymbolsUnique(orc_rt_SimpleNativeMemoryMap_sps_interface); +} + +} // namespace sps_ci +} // namespace orc_rt diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt index 593066a39fe1..a7cfa616c5ab 100644 --- a/orc-rt/unittests/CMakeLists.txt +++ b/orc-rt/unittests/CMakeLists.txt @@ -31,6 +31,7 @@ add_orc_rt_unittest(CoreTests ScopeExitTest.cpp SessionTest.cpp SimpleNativeMemoryMapTest.cpp + SimpleNativeMemoryMapSPSCITest.cpp SimplePackedSerializationTest.cpp SPSAllocActionTest.cpp SPSMemoryFlagsTest.cpp @@ -43,6 +44,7 @@ add_orc_rt_unittest(CoreTests iterator_range-test.cpp move_only_function-test.cpp span-test.cpp + DISABLE_LLVM_LINK_LLVM_DYLIB ) target_compile_options(CoreTests PRIVATE ${ORC_RT_COMPILE_FLAGS}) diff --git a/orc-rt/unittests/CommonTestUtils.h b/orc-rt/unittests/CommonTestUtils.h index 1c66bddaf75b..d5a6c644537e 100644 --- a/orc-rt/unittests/CommonTestUtils.h +++ b/orc-rt/unittests/CommonTestUtils.h @@ -9,7 +9,10 @@ #ifndef ORC_RT_UNITTEST_COMMONTESTUTILS_H #define ORC_RT_UNITTEST_COMMONTESTUTILS_H +#include "orc-rt/move_only_function.h" + #include +#include template class OpCounter { public: @@ -64,4 +67,17 @@ template size_t OpCounter::MoveConstructions = 0; template size_t OpCounter::MoveAssignments = 0; template size_t OpCounter::Destructions = 0; +template +orc_rt::move_only_function waitFor(std::future &F) { + std::promise P; + F = P.get_future(); + return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); }; +} + +inline orc_rt::move_only_function waitFor(std::future &F) { + std::promise P; + F = P.get_future(); + return [P = std::move(P)]() mutable { P.set_value(); }; +} + #endif // ORC_RT_UNITTEST_COMMONTESTUTILS_H diff --git a/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp b/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp new file mode 100644 index 000000000000..37c1b2577f90 --- /dev/null +++ b/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp @@ -0,0 +1,319 @@ +//===- SimpleNativeMemoryMapSPSControllerInterfaceTest.cpp ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Tests for SimpleNativeMemoryMap's SPS Controller Interface. +// +//===----------------------------------------------------------------------===// + +#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h" +#include "orc-rt/SPSAllocAction.h" +#include "orc-rt/SPSMemoryFlags.h" +#include "orc-rt/SPSWrapperFunction.h" +#include "orc-rt/SimpleNativeMemoryMap.h" + +#include "AllocActionTestUtils.h" +#include "CommonTestUtils.h" +#include "DirectCaller.h" +#include "gtest/gtest.h" + +using namespace orc_rt; + +namespace orc_rt { + +struct SPSSimpleNativeMemoryMapSegment; +struct SPSSimpleNativeMemoryMapInitializeRequest; + +/// A SimpleNativeMemoryMap::InitializeRequest::Segment plus segment content (if +/// segment content type is regular). +struct TestSNMMSegment + : public SimpleNativeMemoryMap::InitializeRequest::Segment { + + TestSNMMSegment(AllocGroup AG, char *Address, size_t Size, + std::vector C = {}) + : SimpleNativeMemoryMap::InitializeRequest::Segment( + {AG, Address, Size, {}}), + OwnedContent(std::move(C)) { + this->Content = {OwnedContent.data(), OwnedContent.size()}; + } + + std::vector OwnedContent; +}; + +template <> +class SPSSerializationTraits { + using SPSType = + SPSTuple>; + +public: + static size_t size(const TestSNMMSegment &S) { + return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address), + static_cast(S.Size), S.Content); + } + + static bool serialize(SPSOutputBuffer &OB, const TestSNMMSegment &S) { + return SPSType::AsArgList::serialize( + OB, S.AG, ExecutorAddr::fromPtr(S.Address), + static_cast(S.Size), S.Content); + } +}; + +struct TestSNMMInitializeRequest { + std::vector Segments; + std::vector AAPs; +}; + +template <> +class SPSSerializationTraits { + using SPSType = SPSTuple, + SPSSequence>; + +public: + static size_t size(const TestSNMMInitializeRequest &IR) { + return SPSType::AsArgList::size(IR.Segments, IR.AAPs); + } + static bool serialize(SPSOutputBuffer &OB, + const TestSNMMInitializeRequest &IR) { + return SPSType::AsArgList::serialize(OB, IR.Segments, IR.AAPs); + } +}; + +} // namespace orc_rt + +// Write the given value to the address pointed to by P. +static orc_rt_WrapperFunctionBuffer +write_value_sps_allocaction(const char *ArgData, size_t ArgSize) { + return SPSAllocActionFunction::handle( + ArgData, ArgSize, + [](ExecutorAddr P, uint64_t Val) { + *P.toPtr() = Val; + return WrapperFunctionBuffer(); + }) + .release(); +} + +// Read the uint64_t value at Src and write it to Dst. +static orc_rt_WrapperFunctionBuffer +read_value_sps_allocaction(const char *ArgData, size_t ArgSize) { + return SPSAllocActionFunction::handle( + ArgData, ArgSize, + [](ExecutorAddr Dst, ExecutorAddr Src) { + *Dst.toPtr() = *Src.toPtr(); + return WrapperFunctionBuffer(); + }) + .release(); +} + +class SimpleNativeMemoryMapSPSCITest : public ::testing::Test { +protected: + void SetUp() override { + cantFail(sps_ci::addSimpleNativeMemoryMap(CI)); + SNMM = std::make_unique(); + } + + void TearDown() override { + if (SNMM) { + std::future F; + SNMM->onShutdown(waitFor(F)); + F.get(); + } + } + + DirectCaller caller(const char *Name) { + return DirectCaller(nullptr, reinterpret_cast( + const_cast(CI.at(Name)))); + } + + template + void spsReserve(OnCompleteFn &&OnComplete, size_t Size) { + using SPSSig = SPSExpected(SPSExecutorAddr, SPSSize); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Size); + } + + template + void spsReleaseMultiple(OnCompleteFn &&OnComplete, span Addrs) { + using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Addrs); + } + + template + void spsInitialize(OnCompleteFn &&OnComplete, TestSNMMInitializeRequest IR) { + using SPSSig = SPSExpected( + SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), std::move(IR)); + } + + template + void spsDeinitializeMultiple(OnCompleteFn &&OnComplete, span Bases) { + using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Bases); + } + + ControllerInterface CI; + std::unique_ptr SNMM; +}; + +TEST_F(SimpleNativeMemoryMapSPSCITest, Registration) { + EXPECT_TRUE(CI.count("orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper")); + EXPECT_TRUE( + CI.count("orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper")); + EXPECT_TRUE(CI.count("orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper")); + EXPECT_TRUE(CI.count( + "orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper")); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveAndRelease) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + auto *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future> ReleaseResult; + spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1}); + cantFail(cantFail(ReleaseResult.get())); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, FullPipelineForOneRWSegment) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue1 = 0; + uint64_t SentinelValue2 = 0; + uint64_t SentinelValue3 = 42; + + std::vector Content; + Content.resize(sizeof(uint64_t) * 2); + memcpy(Content.data(), &SentinelValue3, sizeof(uint64_t)); + memcpy(Content.data() + sizeof(uint64_t), &SentinelValue1, sizeof(uint64_t)); + + IR.Segments.push_back({MemProt::Read | MemProt::Write, InitializeBase, + 64 * 1024, std::move(Content)}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue1), + ExecutorAddr::fromPtr(InitializeBase)), + {}}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, + ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t), + uint64_t(42)), + *MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue2), + ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t))}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue3), + ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t) * 2), + {}}); + + spsInitialize(waitFor(InitializeKey), std::move(IR)); + void *InitializeKeyAddr = cantFail(cantFail(InitializeKey.get())); + + EXPECT_EQ(SentinelValue1, 42U); + EXPECT_EQ(SentinelValue2, 0U); + EXPECT_EQ(SentinelValue3, 0U); + + std::future> DeallocResult; + spsDeinitializeMultiple(waitFor(DeallocResult), {&InitializeKeyAddr, 1}); + cantFail(cantFail(DeallocResult.get())); + + EXPECT_EQ(SentinelValue1, 42U); + EXPECT_EQ(SentinelValue2, 42U); + EXPECT_EQ(SentinelValue3, 0U); + + std::future> ReleaseResult; + spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1}); + cantFail(cantFail(ReleaseResult.get())); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeShutdown) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue = 0; + + IR.Segments.push_back( + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase), + uint64_t(42)), + *MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue), + ExecutorAddr::fromPtr(InitializeBase))}); + spsInitialize(waitFor(InitializeKey), std::move(IR)); + cantFail(cantFail(InitializeKey.get())); + + EXPECT_EQ(SentinelValue, 0U); + + std::future ShutdownResult; + SNMM->onShutdown(waitFor(ShutdownResult)); + ShutdownResult.get(); + SNMM.reset(); + + EXPECT_EQ(SentinelValue, 42); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeDetachShutdown) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue = 0; + + IR.Segments.push_back( + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase), + uint64_t(42)), + *MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue), + ExecutorAddr::fromPtr(InitializeBase))}); + spsInitialize(waitFor(InitializeKey), std::move(IR)); + cantFail(cantFail(InitializeKey.get())); + + EXPECT_EQ(SentinelValue, 0U); + + std::future DetachResult; + SNMM->onDetach(waitFor(DetachResult)); + DetachResult.get(); + + EXPECT_EQ(SentinelValue, 0); + + std::future ShutdownResult; + SNMM->onShutdown(waitFor(ShutdownResult)); + ShutdownResult.get(); + SNMM.reset(); + + EXPECT_EQ(SentinelValue, 42); +} diff --git a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp index 30b1f5a8bf18..adb590ad69bf 100644 --- a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp +++ b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp @@ -12,154 +12,15 @@ #include "orc-rt/SimpleNativeMemoryMap.h" #include "orc-rt/SPSAllocAction.h" -#include "orc-rt/SPSMemoryFlags.h" #include "AllocActionTestUtils.h" -#include "DirectCaller.h" +#include "CommonTestUtils.h" #include "gtest/gtest.h" -#include +#include using namespace orc_rt; -namespace orc_rt { - -struct SPSSimpleNativeMemoryMapSegment; - -/// A SimpleNativeMemoryMap::InitializeRequest::Segment plus segment content (if -/// segment content type is regular). -struct TestSNMMSegment - : public SimpleNativeMemoryMap::InitializeRequest::Segment { - - TestSNMMSegment(AllocGroup AG, char *Address, size_t Size, - std::vector C = {}) - : SimpleNativeMemoryMap::InitializeRequest::Segment( - {AG, Address, Size, {}}), - OwnedContent(std::move(C)) { - this->Content = {OwnedContent.data(), OwnedContent.size()}; - } - - std::vector OwnedContent; -}; - -template <> -class SPSSerializationTraits { - using SPSType = - SPSTuple>; - -public: - static size_t size(const TestSNMMSegment &S) { - return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address), - static_cast(S.Size), S.Content); - } - - static bool serialize(SPSOutputBuffer &OB, const TestSNMMSegment &S) { - return SPSType::AsArgList::serialize( - OB, S.AG, ExecutorAddr::fromPtr(S.Address), - static_cast(S.Size), S.Content); - } -}; - -struct SPSSimpleNativeMemoryMapInitializeRequest; - -struct TestSNMMInitializeRequest { - std::vector Segments; - std::vector AAPs; -}; - -template <> -class SPSSerializationTraits { - using SPSType = SPSTuple, - SPSSequence>; - -public: - static size_t size(const TestSNMMInitializeRequest &IR) { - return SPSType::AsArgList::size(IR.Segments, IR.AAPs); - } - static bool serialize(SPSOutputBuffer &OB, - const TestSNMMInitializeRequest &IR) { - return SPSType::AsArgList::serialize(OB, IR.Segments, IR.AAPs); - } -}; - -} // namespace orc_rt - -template move_only_function waitFor(std::future &F) { - std::promise P; - F = P.get_future(); - return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); }; -} - -move_only_function waitFor(std::future &F) { - std::promise P; - F = P.get_future(); - return [P = std::move(P)]() mutable { P.set_value(); }; -} - -TEST(SimpleNativeMemoryMapTest, CreateAndDestroy) { - // Test that we can create and destroy a SimpleNativeMemoryMap instance as - // expected. - auto SNMM = std::make_unique(); -} - -template -static void snmm_reserve(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, size_t Size) { - using SPSSig = SPSExpected(SPSExecutorAddr, SPSSize); - SPSWrapperFunction::call( - DirectCaller(nullptr, orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper), - std::forward(OnComplete), Instance, Size); -} - -template -static void snmm_releaseMultiple(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - span Addr) { - using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::call( - DirectCaller(nullptr, - orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper), - std::forward(OnComplete), Instance, Addr); -} - -template -static void snmm_initialize(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - TestSNMMInitializeRequest IR) { - using SPSSig = SPSExpected( - SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest); - SPSWrapperFunction::call( - DirectCaller(nullptr, - orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper), - std::forward(OnComplete), Instance, std::move(IR)); -} - -template -static void snmm_deinitializeMultiple(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - span Base) { - using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::call( - DirectCaller( - nullptr, - orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper), - std::forward(OnComplete), Instance, Base); -} - -TEST(SimpleNativeMemoryMapTest, ReserveAndRelease) { - // Test that we can reserve and release a slab of address space as expected, - // without finalizing any memory within it. - auto SNMM = std::make_unique(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - auto Addr = cantFail(cantFail(ReserveAddr.get())); - - std::future> ReleaseResult; - snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1}); - cantFail(cantFail(ReleaseResult.get())); -} - // Write the given value to the address pointed to by P. static orc_rt_WrapperFunctionBuffer write_value_sps_allocaction(const char *ArgData, size_t ArgSize) { @@ -173,7 +34,6 @@ write_value_sps_allocaction(const char *ArgData, size_t ArgSize) { } // Read the uint64_t value at Src and write it to Dst. -// Increments int via pointer. static orc_rt_WrapperFunctionBuffer read_value_sps_allocaction(const char *ArgData, size_t ArgSize) { return SPSAllocActionFunction::handle( @@ -185,7 +45,27 @@ read_value_sps_allocaction(const char *ArgData, size_t ArgSize) { .release(); } -TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) { +TEST(SimpleNativeMemoryMapTest, CreateAndDestroy) { + // Test that we can create and destroy a SimpleNativeMemoryMap instance as + // expected. + auto SNMM = std::make_unique(); +} + +TEST(SimpleNativeMemoryMapTest, ReserveAndRelease) { + // Test that we can reserve and release a slab of address space as expected, + // without finalizing any memory within it. + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); + + std::future ReleaseResult; + SNMM.releaseMultiple(waitFor(ReleaseResult), {Addr}); + cantFail(ReleaseResult.get()); +} + +TEST(SimpleNativeMemoryMapTest, FullPipelineForOneRWSegment) { // Test that we can: // 1. reserve some address space. // 2. initialize a range within it as read/write, and that finalize actions @@ -194,13 +74,12 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) { // expected. // 4. release the address range. - auto SNMM = std::make_unique(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(Addr) + 64 * 1024; uint64_t SentinelValue1 = 0; // Read from pre-filled content @@ -214,8 +93,11 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) { memcpy(Content.data(), &SentinelValue3, sizeof(uint64_t)); memcpy(Content.data() + sizeof(uint64_t), &SentinelValue1, sizeof(uint64_t)); - IR.Segments.push_back({MemProt::Read | MemProt::Write, InitializeBase, - 64 * 1024, std::move(Content)}); + SimpleNativeMemoryMap::InitializeRequest IR; + IR.Segments.push_back({MemProt::Read | MemProt::Write, + InitializeBase, + 64 * 1024, + {Content.data(), Content.size()}}); // Read initial content into Sentinel 1. IR.AAPs.push_back({ @@ -243,44 +125,44 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) { {} // No dealloc action. }); - snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR)); - void *InitializeKeyAddr = cantFail(cantFail(InitializeKey.get())); + std::future> InitializeResult; + SNMM.initialize(waitFor(InitializeResult), std::move(IR)); + void *InitializeKeyAddr = cantFail(InitializeResult.get()); EXPECT_EQ(SentinelValue1, 42U); EXPECT_EQ(SentinelValue2, 0U); EXPECT_EQ(SentinelValue3, 0U); - std::future> DeallocResult; - snmm_deinitializeMultiple(waitFor(DeallocResult), SNMM.get(), - {&InitializeKeyAddr, 1}); - cantFail(cantFail(DeallocResult.get())); + std::future DeallocResult; + SNMM.deinitializeMultiple(waitFor(DeallocResult), {InitializeKeyAddr}); + cantFail(DeallocResult.get()); EXPECT_EQ(SentinelValue1, 42U); EXPECT_EQ(SentinelValue2, 42U); EXPECT_EQ(SentinelValue3, 0U); - std::future> ReleaseResult; - snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1}); - cantFail(cantFail(ReleaseResult.get())); + std::future ReleaseResult; + SNMM.releaseMultiple(waitFor(ReleaseResult), {Addr}); + cantFail(ReleaseResult.get()); } -TEST(SimpleNativeMemoryMap, ReserveInitializeShutdown) { +TEST(SimpleNativeMemoryMapTest, ReserveInitializeShutdown) { // Test that memory is deinitialized in the case where we reserve and // initialize some memory, then just shut down the memory manager. - auto SNMM = std::make_unique(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(Addr) + 64 * 1024; uint64_t SentinelValue = 0; + SimpleNativeMemoryMap::InitializeRequest IR; IR.Segments.push_back( - {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024, {}}); IR.AAPs.push_back( {*MakeAllocAction::from( @@ -289,35 +171,37 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeShutdown) { *MakeAllocAction::from( read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue), ExecutorAddr::fromPtr(InitializeBase))}); - snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR)); - cantFail(cantFail(InitializeKey.get())); + + std::future> InitializeResult; + SNMM.initialize(waitFor(InitializeResult), std::move(IR)); + cantFail(InitializeResult.get()); EXPECT_EQ(SentinelValue, 0U); std::future ShutdownResult; - SNMM->onShutdown(waitFor(ShutdownResult)); + SNMM.onShutdown(waitFor(ShutdownResult)); ShutdownResult.get(); EXPECT_EQ(SentinelValue, 42); } -TEST(SimpleNativeMemoryMap, ReserveInitializeDetachShutdown) { +TEST(SimpleNativeMemoryMapTest, ReserveInitializeDetachShutdown) { // Test that memory is deinitialized in the case where we reserve and // initialize some memory, then just shut down the memory manager. - auto SNMM = std::make_unique(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(Addr) + 64 * 1024; uint64_t SentinelValue = 0; + SimpleNativeMemoryMap::InitializeRequest IR; IR.Segments.push_back( - {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024, {}}); IR.AAPs.push_back( {*MakeAllocAction::from( @@ -326,19 +210,21 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeDetachShutdown) { *MakeAllocAction::from( read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue), ExecutorAddr::fromPtr(InitializeBase))}); - snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR)); - cantFail(cantFail(InitializeKey.get())); + + std::future> InitializeResult; + SNMM.initialize(waitFor(InitializeResult), std::move(IR)); + cantFail(InitializeResult.get()); EXPECT_EQ(SentinelValue, 0U); std::future DetachResult; - SNMM->onDetach(waitFor(DetachResult)); + SNMM.onDetach(waitFor(DetachResult)); DetachResult.get(); EXPECT_EQ(SentinelValue, 0); std::future ShutdownResult; - SNMM->onShutdown(waitFor(ShutdownResult)); + SNMM.onShutdown(waitFor(ShutdownResult)); ShutdownResult.get(); EXPECT_EQ(SentinelValue, 42);