diff --git a/score/memory/shared/test/dynamic_array_in_shm_test/BUILD b/score/memory/shared/test/dynamic_array_in_shm_test/BUILD new file mode 100644 index 000000000..8ba43b868 --- /dev/null +++ b/score/memory/shared/test/dynamic_array_in_shm_test/BUILD @@ -0,0 +1,42 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +load("//quality/integration_testing:integration_testing.bzl", "integration_test") +load("//score/mw/com/test:pkg_application.bzl", "pkg_application") + +cc_binary( + name = "dynamic_array_sct", + srcs = ["dynamic_array_sct.cpp"], + features = COMPILER_WARNING_FEATURES, + deps = [ + "//score/memory/shared", + "//score/memory/shared:managed_memory_resource", + "//score/memory/shared:polymorphic_offset_ptr_allocator", + "@score_baselibs//score/containers:dynamic_array", + "@score_baselibs//score/mw/log:backend_stub_testutil", + ], +) + +pkg_application( + name = "dynamic_array_in_shm_test-pkg", + app_name = "dynamic_array_in_shm_test", + bin = [":dynamic_array_sct"], +) + +integration_test( + name = "dynamic_array_in_shm_test", + srcs = ["test_dynamic_array_sct.py"], + filesystem = ":dynamic_array_in_shm_test-pkg", +) diff --git a/score/memory/shared/test/dynamic_array_in_shm_test/dynamic_array_sct.cpp b/score/memory/shared/test/dynamic_array_in_shm_test/dynamic_array_sct.cpp new file mode 100644 index 000000000..cba3e1710 --- /dev/null +++ b/score/memory/shared/test/dynamic_array_in_shm_test/dynamic_array_sct.cpp @@ -0,0 +1,138 @@ +// ******************************************************************************* +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +#include "score/containers/dynamic_array.h" +#include "score/memory/shared/polymorphic_offset_ptr_allocator.h" +#include "score/memory/shared/shared_memory_factory.h" +#include "score/memory/shared/shared_memory_resource.h" + +#include +#include +#include +#include +#include +#include + +namespace +{ + +template +using shm_dynamic_array = score::containers::DynamicArray>; + +constexpr std::size_t kNumberOfElements{50}; +constexpr std::chrono::milliseconds kPollingInterval{100}; +constexpr std::size_t kSharedMemorySize{65536}; + +struct MemoryLayout +{ + explicit MemoryLayout(score::memory::shared::ManagedMemoryResource& resource) + : dynamic_array{kNumberOfElements, resource} + { + } + + std::atomic_bool client_exists{false}; + shm_dynamic_array dynamic_array; +}; + +class SharedMemoryResourceGuard +{ + public: + SharedMemoryResourceGuard(score::memory::shared::SharedMemoryFactory::InitializeCallback callback, + std::string memory_path) noexcept + : resource_{score::memory::shared::SharedMemoryFactory::CreateOrOpen(memory_path, + std::move(callback), + kSharedMemorySize)}, + memory_path_{std::move(memory_path)} + { + } + + ~SharedMemoryResourceGuard() noexcept + { + score::memory::shared::SharedMemoryFactory::Remove(memory_path_); + } + + SharedMemoryResourceGuard(const SharedMemoryResourceGuard&) = delete; + SharedMemoryResourceGuard& operator=(const SharedMemoryResourceGuard&) = delete; + SharedMemoryResourceGuard(SharedMemoryResourceGuard&&) = delete; + SharedMemoryResourceGuard& operator=(SharedMemoryResourceGuard&&) = delete; + + std::shared_ptr GetResource() const noexcept + { + return resource_; + } + + private: + std::shared_ptr resource_; + const std::string memory_path_; +}; + +} // namespace + +/** + * \brief Small test program to test, whether DynamicArray with a PolymorphicOffsetAllocator works in shared memory + * + * \details Two processes are started, both running this main. Both try to CreateOrOpen the same shared-mem-object. + * The one, who comes 1st initializes the shared-memory and the DynamicArray within it and writes a given + * pattern to it. The one, who comes 2nd then reads out from DynamicArray and verifies the data. + * + * \return -1 on error, 0 on success + */ +int main(int /*argc*/, char* /*argv*/[]) +{ + MemoryLayout* ptr{nullptr}; + auto callback = [&ptr](const std::shared_ptr& resource) { + ptr = resource->construct(*resource); + std::cout << "Producer: Size of DynamicArray:" << ptr->dynamic_array.size() << std::endl; + for (std::uint32_t i = 0; i < ptr->dynamic_array.size(); i++) + { + ptr->dynamic_array.at(i) = i; + } + }; + + SharedMemoryResourceGuard resource_guard(std::move(callback), "/testing_shared_memory"); + if (ptr == nullptr) + { + // This is the branch for the 2nd / slower process. + if (!resource_guard.GetResource()) + { + std::cout << "Consumer: Could not get SharedMemoryResource!" << std::endl; + return EXIT_FAILURE; + } + ptr = static_cast(resource_guard.GetResource()->getUsableBaseAddress()); + // signal to provider, that we have opened/mapped shm-object + ptr->client_exists = true; + std::cout << "Consumer: Size of DynamicArray:" << ptr->dynamic_array.size() << std::endl; + for (std::uint32_t i = 0; i < ptr->dynamic_array.size(); i++) + { + if (ptr->dynamic_array.at(i) != i) + { + std::cout << "Element: " << i << " of DynamicArray has unexpected value: " << ptr->dynamic_array.at(i) + << std::endl; + return EXIT_FAILURE; + } + } + } + else + { + // This is the branch for the 1st / quicker process, which succeeded in shm-object creation. + // give the 2nd some time to open shm-object, before we go down and unlink shm-object. + std::cout << "Producer: waiting for client/consumer." << std::endl; + while (!ptr->client_exists) + { + std::this_thread::sleep_for(kPollingInterval); + } + } + + std::cout << "Success." << std::endl; + return EXIT_SUCCESS; +} diff --git a/score/memory/shared/test/dynamic_array_in_shm_test/test_dynamic_array_sct.py b/score/memory/shared/test/dynamic_array_in_shm_test/test_dynamic_array_sct.py new file mode 100644 index 000000000..0a2ee2e3b --- /dev/null +++ b/score/memory/shared/test/dynamic_array_in_shm_test/test_dynamic_array_sct.py @@ -0,0 +1,30 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Integration test: DynamicArray with PolymorphicOffsetPtrAllocator in shared memory.""" + + +def dynamic_array_sct(target, **kwargs): + return target.wrap_exec( + "bin/dynamic_array_sct", + [], + cwd="/opt/dynamic_array_in_shm_test", + wait_on_exit=True, + **kwargs, + ) + + +def test_shared_memory_dynamic_array(target): + """Start two instances of dynamic_array_sct to store and read from a shared DynamicArray in parallel.""" + with dynamic_array_sct(target), dynamic_array_sct(target): + pass