diff --git a/score/time_daemon/src/application/svt/BUILD b/score/time_daemon/src/application/svt/BUILD index f0f1088c..44f97731 100644 --- a/score/time_daemon/src/application/svt/BUILD +++ b/score/time_daemon/src/application/svt/BUILD @@ -34,7 +34,6 @@ load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER "//score/time_daemon/src/control_flow_divider/ptp:ptp_control_flow_divider", "//score/time_daemon/src/ipc/svt/publisher:factory", "//score/time_daemon/src/msg_broker", - "//score/time_daemon/src/verification_machine/svt:svt_verification_machine", ] + deps, ) for name, testonly, deps in [ @@ -42,14 +41,16 @@ load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER "svt_handler", False, [ - "//score/time_daemon/src/ptp_machine:stub_ptp_machine", + "//score/time_daemon/src/ptp_machine/shm:gptp_shm_machine", + "//score/time_daemon/src/verification_machine/svt:svt_verification_machine", ], ), ( "svt_handler_for_utests", True, [ - "//score/time_daemon/src/ptp_machine:stub_ptp_machine", + "//score/time_daemon/src/ptp_machine/shm:gptp_shm_machine", + "//score/time_daemon/src/verification_machine/svt:svt_verification_machine_for_utests", ], ), ] diff --git a/score/time_daemon/src/application/svt/svt_handler.cpp b/score/time_daemon/src/application/svt/svt_handler.cpp index 52739d44..1c26a165 100644 --- a/score/time_daemon/src/application/svt/svt_handler.cpp +++ b/score/time_daemon/src/application/svt/svt_handler.cpp @@ -16,7 +16,7 @@ #include "score/time_daemon/src/ipc/svt/publisher/factory.h" #include "score/time_daemon/src/msg_broker/subscription.h" #include "score/time_daemon/src/msg_broker/topic.h" -#include "score/time_daemon/src/ptp_machine/stub/factory.h" +#include "score/time_daemon/src/ptp_machine/shm/factory.h" #include "score/time_daemon/src/verification_machine/svt/factory.h" #include "score/concurrency/interruptible_wait.h" #include "score/mw/log/logging.h" @@ -39,7 +39,7 @@ SvtHandler::SvtHandler() noexcept handler_status_{TimebaseHandler::Status::kIdle} { msg_broker_ = std::make_shared>(); - gptp_machine_ = CreateGPTPStubMachine("ptp_worker"); + gptp_machine_ = CreateGPTPShmMachine("ptp_worker"); verification_machine_ = CreateSvtVerificationMachine("time_verification_worker"); ipc_publisher_ = CreateSvtPublisher("svt_ipc_publisher"); ctrl_flow_divider_ = CreatePtpControlFlowDivider("ptp_control_flow_divider", std::chrono::milliseconds{250}); diff --git a/score/time_daemon/src/application/svt/svt_handler.h b/score/time_daemon/src/application/svt/svt_handler.h index 63663225..5fef4d01 100644 --- a/score/time_daemon/src/application/svt/svt_handler.h +++ b/score/time_daemon/src/application/svt/svt_handler.h @@ -18,7 +18,7 @@ #include "score/time_daemon/src/control_flow_divider/ptp/ptp_control_flow_divider.h" #include "score/time_daemon/src/ipc/svt/publisher/svt_publisher.h" #include "score/time_daemon/src/msg_broker/msg_broker.h" -#include "score/time_daemon/src/ptp_machine/stub/gptp_stub_machine.h" +#include "score/time_daemon/src/ptp_machine/shm/gptp_shm_machine.h" #include "score/time_daemon/src/verification_machine/svt/svt_verification_machine.h" #include @@ -72,7 +72,7 @@ class SvtHandler : public TimebaseHandler private: std::unique_ptr job_runner_; ///< Manages periodic jobs and tasks std::shared_ptr> msg_broker_; ///< Handles message communication - std::shared_ptr gptp_machine_; ///< Manages GPTP synchronization + std::shared_ptr gptp_machine_; ///< Manages GPTP synchronization std::shared_ptr verification_machine_; ///< Handles SVT verification std::shared_ptr ipc_publisher_; ///< Publishes SVT data via IPC std::shared_ptr ctrl_flow_divider_; ///< Divides PTP control flow diff --git a/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine.cpp b/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine.cpp index 836eca62..15278fb8 100644 --- a/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine.cpp +++ b/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine.cpp @@ -30,7 +30,7 @@ bool ShmPTPEngine::Initialize() if (initialized_) return true; - initialized_ = receiver_.Init(ipc_name_); + initialized_ = receiver_.Open(ipc_name_); if (initialized_) { score::mw::log::LogInfo(kGPtpMachineContext) << "ShmPTPEngine: connected to IPC channel " << ipc_name_; diff --git a/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine_test.cpp b/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine_test.cpp index 6b74e1c8..8ac1a997 100644 --- a/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine_test.cpp +++ b/score/time_daemon/src/ptp_machine/shm/details/shm_ptp_engine_test.cpp @@ -86,7 +86,7 @@ class ShmPTPEngineTest : public ::testing::Test void TearDown() override { engine_->Deinitialize(); - pub_.Destroy(); + pub_.Close(); } std::string name_; @@ -103,13 +103,13 @@ TEST_F(ShmPTPEngineTest, Initialize_WhenShmNotExist_ReturnsFalse) TEST_F(ShmPTPEngineTest, Initialize_WhenShmExists_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); EXPECT_TRUE(engine_->Initialize()); } TEST_F(ShmPTPEngineTest, Initialize_CalledTwiceWhenInitialized_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); ASSERT_TRUE(engine_->Initialize()); EXPECT_TRUE(engine_->Initialize()); // idempotent } @@ -121,14 +121,14 @@ TEST_F(ShmPTPEngineTest, Deinitialize_WhenNotInitialized_ReturnsTrue) TEST_F(ShmPTPEngineTest, Deinitialize_AfterInitialize_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); ASSERT_TRUE(engine_->Initialize()); EXPECT_TRUE(engine_->Deinitialize()); } TEST_F(ShmPTPEngineTest, Deinitialize_CalledTwice_BothReturnTrue) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); ASSERT_TRUE(engine_->Initialize()); EXPECT_TRUE(engine_->Deinitialize()); EXPECT_TRUE(engine_->Deinitialize()); @@ -136,7 +136,7 @@ TEST_F(ShmPTPEngineTest, Deinitialize_CalledTwice_BothReturnTrue) TEST_F(ShmPTPEngineTest, ReInitialize_AfterDeinitialize_Succeeds) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); ASSERT_TRUE(engine_->Initialize()); ASSERT_TRUE(engine_->Deinitialize()); EXPECT_TRUE(engine_->Initialize()); @@ -152,7 +152,7 @@ TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_WhenNotInitialized_ReturnsFalse) TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_WithPublishedData_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); pub_.Publish(MakeTestIpcData()); ASSERT_TRUE(engine_->Initialize()); @@ -162,7 +162,7 @@ TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_WithPublishedData_ReturnsTrue) TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_CopiesTimeAndStatusCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); const score::ts::GptpIpcData src = MakeTestIpcData(); pub_.Publish(src); ASSERT_TRUE(engine_->Initialize()); @@ -179,7 +179,7 @@ TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_CopiesTimeAndStatusCorrectly) TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_CopiesSyncFupDataCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); const score::ts::GptpIpcData src = MakeTestIpcData(); pub_.Publish(src); ASSERT_TRUE(engine_->Initialize()); @@ -196,7 +196,7 @@ TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_CopiesSyncFupDataCorrectly) TEST_F(ShmPTPEngineTest, ReadPTPSnapshot_CopiesPDelayDataCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); const score::ts::GptpIpcData src = MakeTestIpcData(); pub_.Publish(src); ASSERT_TRUE(engine_->Initialize()); diff --git a/score/time_daemon/src/ptp_machine/shm/gptp_shm_machine_test.cpp b/score/time_daemon/src/ptp_machine/shm/gptp_shm_machine_test.cpp index 1e27a715..fffa2a7a 100644 --- a/score/time_daemon/src/ptp_machine/shm/gptp_shm_machine_test.cpp +++ b/score/time_daemon/src/ptp_machine/shm/gptp_shm_machine_test.cpp @@ -56,7 +56,7 @@ class GPTPShmMachineIntegrationTest : public ::testing::Test void SetUp() override { name_ = UniqueShmName(); - ASSERT_TRUE(pub_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); pub_.Publish(MakePublishedInfo()); machine_ = CreateGPTPShmMachine("ShmPTPMachine", name_); @@ -73,7 +73,7 @@ class GPTPShmMachineIntegrationTest : public ::testing::Test { machine_->Stop(); machine_.reset(); - pub_.Destroy(); + pub_.Close(); } std::string name_; diff --git a/score/time_daemon/src/verification_machine/svt/BUILD b/score/time_daemon/src/verification_machine/svt/BUILD index 4ebd4cdc..02c2f49b 100644 --- a/score/time_daemon/src/verification_machine/svt/BUILD +++ b/score/time_daemon/src/verification_machine/svt/BUILD @@ -14,26 +14,45 @@ load("@score_baselibs//:bazel/unit_tests.bzl", "cc_unit_test_suites_for_host_and_qnx") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") -cc_library( - name = "svt_verification_machine", - srcs = [ - "factory.cpp", - ], - hdrs = [ - "factory.h", - "svt_verification_machine.h", - ], - features = COMPILER_WARNING_FEATURES, - tags = ["QM"], - visibility = ["//score/time_daemon:__subpackages__"], - deps = [ - "//score/time_daemon/src/common/data_types:ptp_time_info", - "//score/time_daemon/src/common/machines", - "//score/time_daemon/src/verification_machine/core:verification_machine", - "//score/time_daemon/src/verification_machine/svt/validators", - "@score_baselibs//score/mw/log:frontend", - ], -) +[ + cc_library( + name = name, + testonly = testonly, + srcs = [ + "factory.cpp", + ], + hdrs = [ + "factory.h", + "svt_verification_machine.h", + ], + features = COMPILER_WARNING_FEATURES, + tags = ["QM"], + visibility = ["//score/time_daemon:__subpackages__"], + deps = [ + "//score/time_daemon/src/common/data_types:ptp_time_info", + "//score/time_daemon/src/common/machines", + "//score/time_daemon/src/verification_machine/core:verification_machine", + "//score/time_daemon/src/verification_machine/svt/validators", + "@score_baselibs//score/mw/log:frontend", + ] + deps, + ) + for name, testonly, deps in [ + ( + "svt_verification_machine", + False, + [ + "//score/time/high_res_steady_time:high_res_steady_time", + ], + ), + ( + "svt_verification_machine_for_utests", + True, + [ + "//score/time/high_res_steady_time:high_res_steady_time_mock", + ], + ), + ] +] cc_unit_test_suites_for_host_and_qnx( name = "unit_test_suite", @@ -51,8 +70,7 @@ cc_test( ], tags = ["unit"], deps = [ - ":svt_verification_machine", - "//score/time/high_res_steady_time:high_res_steady_time_mock", + ":svt_verification_machine_for_utests", "@googletest//:gtest", "@googletest//:gtest_main", "@score_baselibs//score/mw/log:console_only_backend", diff --git a/score/time_slave/src/application/time_slave.cpp b/score/time_slave/src/application/time_slave.cpp index 0aa477ca..426402d2 100644 --- a/score/time_slave/src/application/time_slave.cpp +++ b/score/time_slave/src/application/time_slave.cpp @@ -42,7 +42,7 @@ std::int32_t TimeSlave::Initialize(const score::mw::lifecycle::ApplicationContex return kInitFailure; } - if (!publisher_.Init()) + if (!publisher_.Open()) { score::mw::log::LogError(kTimeSlaveAppContext) << "TimeSlave: shared memory publisher initialization failed"; return kInitFailure; @@ -71,7 +71,7 @@ std::int32_t TimeSlave::Run(const score::cpp::stop_token& token) } engine_->Deinitialize(); - publisher_.Destroy(); + publisher_.Close(); score::mw::log::LogInfo(kTimeSlaveAppContext) << "TimeSlave stopped"; return kInitSuccess; diff --git a/score/ts_client/src/BUILD b/score/ts_client/src/BUILD index 445363dd..3fcc0a90 100644 --- a/score/ts_client/src/BUILD +++ b/score/ts_client/src/BUILD @@ -28,13 +28,14 @@ cc_library( "gptp_ipc_receiver.h", ], features = COMPILER_WARNING_FEATURES, - linkopts = select({ - "@platforms//os:qnx": [], - "//conditions:default": ["-lrt"], - }), tags = ["QM"], - visibility = ["//score:__subpackages__"], - deps = [], + visibility = [ + "//score/time_daemon:__subpackages__", + "//score/time_slave:__subpackages__", + ], + deps = [ + "@score_baselibs//score/memory/shared", + ], ) cc_test( @@ -48,6 +49,7 @@ cc_test( ":gptp_ipc", "@googletest//:gtest", "@googletest//:gtest_main", + "@score_baselibs//score/mw/log:console_only_backend", ], ) @@ -62,6 +64,7 @@ cc_test( ":gptp_ipc", "@googletest//:gtest", "@googletest//:gtest_main", + "@score_baselibs//score/mw/log:console_only_backend", ], ) @@ -76,6 +79,7 @@ cc_test( ":gptp_ipc", "@googletest//:gtest", "@googletest//:gtest_main", + "@score_baselibs//score/mw/log:console_only_backend", ], ) diff --git a/score/ts_client/src/gptp_ipc_channel.h b/score/ts_client/src/gptp_ipc_channel.h index 96f97927..37d078e5 100644 --- a/score/ts_client/src/gptp_ipc_channel.h +++ b/score/ts_client/src/gptp_ipc_channel.h @@ -25,7 +25,7 @@ namespace ts namespace details { -/// Default POSIX shared memory name for the gPTP IPC channel. +/// Default shared memory name for the gPTP IPC channel. constexpr char kGptpIpcName[] = "/gptp_ptp_info"; /// Magic number to validate the shared memory region ('GPTP'). diff --git a/score/ts_client/src/gptp_ipc_data.h b/score/ts_client/src/gptp_ipc_data.h index f210cae9..3b2030f5 100644 --- a/score/ts_client/src/gptp_ipc_data.h +++ b/score/ts_client/src/gptp_ipc_data.h @@ -33,9 +33,6 @@ struct GptpIpcStatus bool is_correct; }; -/** - * @brief IPC-layer Sync+FollowUp measurement data. - */ struct GptpIpcSyncFupData { std::uint64_t precise_origin_timestamp; @@ -49,9 +46,6 @@ struct GptpIpcSyncFupData std::uint64_t clock_identity; }; -/** - * @brief IPC-layer peer-delay measurement data. - */ struct GptpIpcPDelayData { std::uint64_t request_origin_timestamp; @@ -71,7 +65,7 @@ struct GptpIpcPDelayData /** * @brief IPC data snapshot written by TimeSlave and read by TimeDaemon. * - * This type is internal to ts_client/src and intentionally decoupled from + * This type is internal to ts_client and intentionally decoupled from * score::td::PtpTimeInfo. Callers are responsible for mapping between the two. */ struct GptpIpcData diff --git a/score/ts_client/src/gptp_ipc_publisher.cpp b/score/ts_client/src/gptp_ipc_publisher.cpp index 8e8c58bb..55b73a65 100644 --- a/score/ts_client/src/gptp_ipc_publisher.cpp +++ b/score/ts_client/src/gptp_ipc_publisher.cpp @@ -12,9 +12,6 @@ ********************************************************************************/ #include "score/ts_client/src/gptp_ipc_publisher.h" -#include -#include -#include #include #include @@ -30,39 +27,28 @@ namespace details GptpIpcPublisher::~GptpIpcPublisher() { - Destroy(); + Close(); } -bool GptpIpcPublisher::Init(const std::string& ipc_name) +bool GptpIpcPublisher::Open(const std::string& ipc_name) { - if (region_ != nullptr) + if (shm_resource_ != nullptr) return true; ipc_name_ = ipc_name; - (void)::shm_unlink(ipc_name_.c_str()); + score::memory::shared::SharedMemoryFactory::Remove(ipc_name_); + score::memory::shared::SharedMemoryFactory::RemoveStaleArtefacts(ipc_name_); - shm_fd_ = ::shm_open(ipc_name_.c_str(), O_CREAT | O_RDWR, 0600); - if (shm_fd_ < 0) - return false; + shm_resource_ = score::memory::shared::SharedMemoryFactory::Create( + ipc_name_, + [this](std::shared_ptr res) { + region_ = res->construct(); + }, + sizeof(GptpIpcRegion) + alignof(GptpIpcRegion) - 1U, + score::memory::shared::permission::WorldWritable{}); - if (::ftruncate(shm_fd_, static_cast(sizeof(GptpIpcRegion))) != 0) - { - ::close(shm_fd_); // LCOV_EXCL_LINE - shm_fd_ = -1; // LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - - void* ptr = ::mmap(nullptr, sizeof(GptpIpcRegion), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_, 0); - if (ptr == MAP_FAILED) - { - ::close(shm_fd_); // LCOV_EXCL_LINE - shm_fd_ = -1; // LCOV_EXCL_LINE - return false; // LCOV_EXCL_LINE - } - - region_ = new (ptr) GptpIpcRegion{}; - return true; + return (shm_resource_ != nullptr) && (region_ != nullptr); } void GptpIpcPublisher::Publish(const score::ts::GptpIpcData& data) @@ -83,24 +69,15 @@ void GptpIpcPublisher::Publish(const score::ts::GptpIpcData& data) region_->seq.store(next + 1U, std::memory_order_release); } -void GptpIpcPublisher::Destroy() +void GptpIpcPublisher::Close() { - if (region_ != nullptr) - { - region_->~GptpIpcRegion(); - ::munmap(region_, sizeof(GptpIpcRegion)); - region_ = nullptr; - } - if (shm_fd_ >= 0) - { - ::close(shm_fd_); - shm_fd_ = -1; - } if (!ipc_name_.empty()) { - ::shm_unlink(ipc_name_.c_str()); + score::memory::shared::SharedMemoryFactory::Remove(ipc_name_); ipc_name_.clear(); } + shm_resource_.reset(); + region_ = nullptr; } } // namespace details diff --git a/score/ts_client/src/gptp_ipc_publisher.h b/score/ts_client/src/gptp_ipc_publisher.h index 59abccba..5808c357 100644 --- a/score/ts_client/src/gptp_ipc_publisher.h +++ b/score/ts_client/src/gptp_ipc_publisher.h @@ -14,7 +14,9 @@ #define SCORE_TS_CLIENT_SRC_GPTP_IPC_PUBLISHER_H #include "score/ts_client/src/gptp_ipc_channel.h" +#include "score/memory/shared/shared_memory_factory.h" +#include #include namespace score @@ -39,19 +41,13 @@ class GptpIpcPublisher final GptpIpcPublisher(const GptpIpcPublisher&) = delete; GptpIpcPublisher& operator=(const GptpIpcPublisher&) = delete; - /// Create and map the shared memory segment. - /// @return true on success. - bool Init(const std::string& ipc_name = kGptpIpcName); - - /// Publish a GptpIpcData snapshot using seqlock. + bool Open(const std::string& ipc_name = kGptpIpcName); void Publish(const score::ts::GptpIpcData& data); - - /// Unmap and unlink the shared memory segment. - void Destroy(); + void Close(); private: GptpIpcRegion* region_{nullptr}; - int shm_fd_{-1}; + std::shared_ptr shm_resource_; std::string ipc_name_; }; diff --git a/score/ts_client/src/gptp_ipc_publisher_test.cpp b/score/ts_client/src/gptp_ipc_publisher_test.cpp index b4f7d41e..843b525a 100644 --- a/score/ts_client/src/gptp_ipc_publisher_test.cpp +++ b/score/ts_client/src/gptp_ipc_publisher_test.cpp @@ -27,15 +27,15 @@ class GptpIpcPublisherTest : public ::testing::Test protected: void TearDown() override { - pub_.Destroy(); + pub_.Close(); } GptpIpcPublisher pub_; }; -TEST_F(GptpIpcPublisherTest, Init_ValidName_ReturnsTrue) +TEST_F(GptpIpcPublisherTest, Open_ValidName_ReturnsTrue) { - EXPECT_TRUE(pub_.Init(UniqueShmName())); + EXPECT_TRUE(pub_.Open(UniqueShmName())); } TEST_F(GptpIpcPublisherTest, Publish_WithoutInit_DoesNotCrash) @@ -44,23 +44,23 @@ TEST_F(GptpIpcPublisherTest, Publish_WithoutInit_DoesNotCrash) EXPECT_NO_THROW(pub_.Publish(data)); } -TEST_F(GptpIpcPublisherTest, Destroy_CalledTwice_DoesNotCrash) +TEST_F(GptpIpcPublisherTest, Close_CalledTwice_DoesNotCrash) { - ASSERT_TRUE(pub_.Init(UniqueShmName())); - pub_.Destroy(); - EXPECT_NO_THROW(pub_.Destroy()); + ASSERT_TRUE(pub_.Open(UniqueShmName())); + pub_.Close(); + EXPECT_NO_THROW(pub_.Close()); } -TEST_F(GptpIpcPublisherTest, Destroy_WithoutInit_DoesNotCrash) +TEST_F(GptpIpcPublisherTest, Close_WithoutOpen_DoesNotCrash) { - EXPECT_NO_THROW(pub_.Destroy()); + EXPECT_NO_THROW(pub_.Close()); } -TEST_F(GptpIpcPublisherTest, Init_CalledTwice_ReturnsTrueOnSecondCall) +TEST_F(GptpIpcPublisherTest, Open_CalledTwice_ReturnsTrueOnSecondCall) { // region_ != nullptr after first Init → second call returns true immediately. - ASSERT_TRUE(pub_.Init(UniqueShmName())); - EXPECT_TRUE(pub_.Init(UniqueShmName())); + ASSERT_TRUE(pub_.Open(UniqueShmName())); + EXPECT_TRUE(pub_.Open(UniqueShmName())); } } // namespace details diff --git a/score/ts_client/src/gptp_ipc_receiver.cpp b/score/ts_client/src/gptp_ipc_receiver.cpp index ee6ee838..a0c27133 100644 --- a/score/ts_client/src/gptp_ipc_receiver.cpp +++ b/score/ts_client/src/gptp_ipc_receiver.cpp @@ -12,11 +12,8 @@ ********************************************************************************/ #include "score/ts_client/src/gptp_ipc_receiver.h" -#include -#include -#include -#include #include +#include namespace score { @@ -32,33 +29,26 @@ GptpIpcReceiver::~GptpIpcReceiver() Close(); } -bool GptpIpcReceiver::Init(const std::string& ipc_name) +bool GptpIpcReceiver::Open(const std::string& ipc_name) { - if (region_ != nullptr) + if (shm_resource_ != nullptr) return true; - shm_fd_ = ::shm_open(ipc_name.c_str(), O_RDONLY, 0); - if (shm_fd_ < 0) + shm_resource_ = score::memory::shared::SharedMemoryFactory::Open(ipc_name, false); + if (shm_resource_ == nullptr) return false; + // construct() on the publisher side aligns the object to + // alignof(GptpIpcRegion) within the usable region. We must apply the same + // alignment here so that both sides point to the same address. + void* ptr = shm_resource_->getUsableBaseAddress(); + std::size_t space = sizeof(GptpIpcRegion) + alignof(GptpIpcRegion); + ptr = std::align(alignof(GptpIpcRegion), sizeof(GptpIpcRegion), ptr, space); + if (ptr == nullptr) { - struct ::stat st{}; - if (::fstat(shm_fd_, &st) != 0 || static_cast(st.st_size) < sizeof(GptpIpcRegion)) - { - ::close(shm_fd_); - shm_fd_ = -1; - return false; - } - } - - void* ptr = ::mmap(nullptr, sizeof(GptpIpcRegion), PROT_READ, MAP_SHARED, shm_fd_, 0); - if (ptr == MAP_FAILED) - { - ::close(shm_fd_); - shm_fd_ = -1; + Close(); return false; } - region_ = static_cast(ptr); if (region_->magic.load(std::memory_order_acquire) != kGptpIpcMagic) @@ -106,16 +96,8 @@ std::optional GptpIpcReceiver::Receive() void GptpIpcReceiver::Close() { - if (region_ != nullptr) - { - ::munmap(const_cast(region_), sizeof(GptpIpcRegion)); - region_ = nullptr; - } - if (shm_fd_ >= 0) - { - ::close(shm_fd_); - shm_fd_ = -1; - } + shm_resource_.reset(); + region_ = nullptr; } } // namespace details diff --git a/score/ts_client/src/gptp_ipc_receiver.h b/score/ts_client/src/gptp_ipc_receiver.h index a9fd98ee..bc86d4da 100644 --- a/score/ts_client/src/gptp_ipc_receiver.h +++ b/score/ts_client/src/gptp_ipc_receiver.h @@ -14,7 +14,9 @@ #define SCORE_TS_CLIENT_SRC_GPTP_IPC_RECEIVER_H #include "score/ts_client/src/gptp_ipc_channel.h" +#include "score/memory/shared/shared_memory_factory.h" +#include #include #include @@ -40,20 +42,13 @@ class GptpIpcReceiver final GptpIpcReceiver(const GptpIpcReceiver&) = delete; GptpIpcReceiver& operator=(const GptpIpcReceiver&) = delete; - /// Open and map the shared memory segment (read-only). - /// @return true on success. - bool Init(const std::string& ipc_name = kGptpIpcName); - - /// Read a GptpIpcData snapshot using seqlock (up to 20 retries). - /// @return The data if consistent, or std::nullopt on contention failure. + bool Open(const std::string& ipc_name = kGptpIpcName); std::optional Receive(); - - /// Unmap the shared memory segment. void Close(); private: const GptpIpcRegion* region_{nullptr}; - int shm_fd_{-1}; + std::shared_ptr shm_resource_; }; } // namespace details diff --git a/score/ts_client/src/gptp_ipc_receiver_test.cpp b/score/ts_client/src/gptp_ipc_receiver_test.cpp index 5f481997..06d1861e 100644 --- a/score/ts_client/src/gptp_ipc_receiver_test.cpp +++ b/score/ts_client/src/gptp_ipc_receiver_test.cpp @@ -38,9 +38,9 @@ class GptpIpcReceiverTest : public ::testing::Test GptpIpcReceiver rx_; }; -TEST_F(GptpIpcReceiverTest, Init_ShmNotExist_ReturnsFalse) +TEST_F(GptpIpcReceiverTest, Open_ShmNotExist_ReturnsFalse) { - EXPECT_FALSE(rx_.Init("/gptp_nonexistent_" + std::to_string(::getpid()))); + EXPECT_FALSE(rx_.Open("/gptp_nonexistent_" + std::to_string(::getpid()))); } TEST_F(GptpIpcReceiverTest, Close_WithoutInit_DoesNotCrash) @@ -59,18 +59,18 @@ TEST_F(GptpIpcReceiverTest, Receive_WithoutInit_ReturnsNullopt) EXPECT_FALSE(rx_.Receive().has_value()); } -TEST_F(GptpIpcReceiverTest, Init_CalledTwice_ReturnsTrueOnSecondCall) +TEST_F(GptpIpcReceiverTest, Open_CalledTwice_ReturnsTrueOnSecondCall) { - // region_ != nullptr after first Init → second call returns true immediately. + // region_ != nullptr after first Open → second call returns true immediately. GptpIpcPublisher pub; const std::string name = UniqueShmName(); - ASSERT_TRUE(pub.Init(name)); - ASSERT_TRUE(rx_.Init(name)); - EXPECT_TRUE(rx_.Init(name)); - pub.Destroy(); + ASSERT_TRUE(pub.Open(name)); + ASSERT_TRUE(rx_.Open(name)); + EXPECT_TRUE(rx_.Open(name)); + pub.Close(); } -TEST_F(GptpIpcReceiverTest, Init_TooSmallShm_ReturnsFalse) +TEST_F(GptpIpcReceiverTest, Open_TooSmallShm_ReturnsFalse) { // Create a shm segment smaller than GptpIpcRegion so the fstat size check fails. const std::string name = UniqueShmName(); @@ -79,7 +79,7 @@ TEST_F(GptpIpcReceiverTest, Init_TooSmallShm_ReturnsFalse) ASSERT_EQ(::ftruncate(fd, 1), 0); ::close(fd); - EXPECT_FALSE(rx_.Init(name)); + EXPECT_FALSE(rx_.Open(name)); ::shm_unlink(name.c_str()); } diff --git a/score/ts_client/src/gptp_ipc_roundtrip_test.cpp b/score/ts_client/src/gptp_ipc_roundtrip_test.cpp index 844ba7aa..f27a0f9f 100644 --- a/score/ts_client/src/gptp_ipc_roundtrip_test.cpp +++ b/score/ts_client/src/gptp_ipc_roundtrip_test.cpp @@ -35,7 +35,7 @@ class GptpIpcRoundtripTest : public ::testing::Test void TearDown() override { rx_.Close(); - pub_.Destroy(); + pub_.Close(); } std::string name_; @@ -43,16 +43,16 @@ class GptpIpcRoundtripTest : public ::testing::Test GptpIpcReceiver rx_; }; -TEST_F(GptpIpcRoundtripTest, ReceiverInit_AfterPublisherInit_ReturnsTrue) +TEST_F(GptpIpcRoundtripTest, ReceiverOpen_AfterPublisherOpen_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); - EXPECT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + EXPECT_TRUE(rx_.Open(name_)); } TEST_F(GptpIpcRoundtripTest, ReceiverReceive_BeforeAnyPublish_ReturnsNullopt) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); // seq_confirm is initialised to 1 (≠ seq=0) by GptpIpcRegion's constructor, // so the seqlock always mismatches before the first Publish() call. EXPECT_FALSE(rx_.Receive().has_value()); @@ -60,8 +60,8 @@ TEST_F(GptpIpcRoundtripTest, ReceiverReceive_BeforeAnyPublish_ReturnsNullopt) TEST_F(GptpIpcRoundtripTest, PublishReceive_BasicFields_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::ts::GptpIpcData data{}; data.ptp_assumed_time = std::chrono::nanoseconds{1'234'567'890LL}; @@ -84,8 +84,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_BasicFields_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_StatusFlags_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::ts::GptpIpcData data{}; data.status.is_timeout = true; @@ -105,8 +105,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_StatusFlags_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_SyncFupData_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::ts::GptpIpcData data{}; data.sync_fup_data.precise_origin_timestamp = 100'000'000'000ULL; @@ -132,8 +132,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_SyncFupData_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_PDelayData_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::ts::GptpIpcData data{}; data.pdelay_data.request_origin_timestamp = 1'000'000'000ULL; @@ -158,8 +158,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_PDelayData_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, MultiplePublish_LastValueIsVisible) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); for (int i = 1; i <= 5; ++i) { @@ -175,16 +175,16 @@ TEST_F(GptpIpcRoundtripTest, MultiplePublish_LastValueIsVisible) // ── Edge cases via ManualShm ────────────────────────────────────────────────── -TEST_F(GptpIpcRoundtripTest, ReceiverInit_WrongMagic_ReturnsFalse) +TEST_F(GptpIpcRoundtripTest, ReceiverOpen_WrongMagic_ReturnsFalse) { ManualShm shm{name_}; ASSERT_TRUE(shm.Valid()); new (shm.Region()) GptpIpcRegion{}; const std::uint32_t bad = 0xDEADBEEFU; - std::memcpy(shm.ptr, &bad, sizeof(bad)); + std::memcpy(shm.Region(), &bad, sizeof(bad)); - EXPECT_FALSE(rx_.Init(name_)); + EXPECT_FALSE(rx_.Open(name_)); } TEST_F(GptpIpcRoundtripTest, Receive_PersistentOddSeq_ExhaustsRetriesAndReturnsNullopt) @@ -196,7 +196,7 @@ TEST_F(GptpIpcRoundtripTest, Receive_PersistentOddSeq_ExhaustsRetriesAndReturnsN region->seq.store(1U, std::memory_order_relaxed); region->seq_confirm.store(0U, std::memory_order_relaxed); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(rx_.Open(name_)); EXPECT_FALSE(rx_.Receive().has_value()); } @@ -209,7 +209,7 @@ TEST_F(GptpIpcRoundtripTest, Receive_SeqConfirmMismatch_ExhaustsRetriesAndReturn region->seq.store(4U, std::memory_order_relaxed); region->seq_confirm.store(2U, std::memory_order_relaxed); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(rx_.Open(name_)); EXPECT_FALSE(rx_.Receive().has_value()); } diff --git a/score/ts_client/src/gptp_ipc_test.cpp b/score/ts_client/src/gptp_ipc_test.cpp index eadae9b3..7c7ce66e 100644 --- a/score/ts_client/src/gptp_ipc_test.cpp +++ b/score/ts_client/src/gptp_ipc_test.cpp @@ -88,15 +88,15 @@ class GptpIpcPublisherTest : public ::testing::Test protected: void TearDown() override { - pub_.Destroy(); + pub_.Close(); } GptpIpcPublisher pub_; }; -TEST_F(GptpIpcPublisherTest, Init_ValidName_ReturnsTrue) +TEST_F(GptpIpcPublisherTest, Open_ValidName_ReturnsTrue) { - EXPECT_TRUE(pub_.Init(UniqueShmName())); + EXPECT_TRUE(pub_.Open(UniqueShmName())); } TEST_F(GptpIpcPublisherTest, Publish_WithoutInit_DoesNotCrash) @@ -106,23 +106,23 @@ TEST_F(GptpIpcPublisherTest, Publish_WithoutInit_DoesNotCrash) EXPECT_NO_THROW(pub_.Publish(info)); } -TEST_F(GptpIpcPublisherTest, Destroy_CalledTwice_DoesNotCrash) +TEST_F(GptpIpcPublisherTest, Close_CalledTwice_DoesNotCrash) { - ASSERT_TRUE(pub_.Init(UniqueShmName())); - pub_.Destroy(); - EXPECT_NO_THROW(pub_.Destroy()); + ASSERT_TRUE(pub_.Open(UniqueShmName())); + pub_.Close(); + EXPECT_NO_THROW(pub_.Close()); } -TEST_F(GptpIpcPublisherTest, Destroy_WithoutInit_DoesNotCrash) +TEST_F(GptpIpcPublisherTest, Close_WithoutOpen_DoesNotCrash) { - EXPECT_NO_THROW(pub_.Destroy()); + EXPECT_NO_THROW(pub_.Close()); } -TEST_F(GptpIpcPublisherTest, Init_CalledTwice_ReturnsTrueOnSecondCall) +TEST_F(GptpIpcPublisherTest, Open_CalledTwice_ReturnsTrueOnSecondCall) { - // region_ != nullptr after first Init → second call returns true immediately. - ASSERT_TRUE(pub_.Init(UniqueShmName())); - EXPECT_TRUE(pub_.Init(UniqueShmName())); + // region_ != nullptr after first Open → second call returns true immediately. + ASSERT_TRUE(pub_.Open(UniqueShmName())); + EXPECT_TRUE(pub_.Open(UniqueShmName())); } // ── GptpIpcReceiver ─────────────────────────────────────────────────────────── @@ -138,9 +138,9 @@ class GptpIpcReceiverTest : public ::testing::Test GptpIpcReceiver rx_; }; -TEST_F(GptpIpcReceiverTest, Init_ShmNotExist_ReturnsFalse) +TEST_F(GptpIpcReceiverTest, Open_ShmNotExist_ReturnsFalse) { - EXPECT_FALSE(rx_.Init("/gptp_nonexistent_" + std::to_string(::getpid()))); + EXPECT_FALSE(rx_.Open("/gptp_nonexistent_" + std::to_string(::getpid()))); } TEST_F(GptpIpcReceiverTest, Close_WithoutInit_DoesNotCrash) @@ -159,18 +159,18 @@ TEST_F(GptpIpcReceiverTest, Receive_WithoutInit_ReturnsNullopt) EXPECT_FALSE(rx_.Receive().has_value()); } -TEST_F(GptpIpcReceiverTest, Init_CalledTwice_ReturnsTrueOnSecondCall) +TEST_F(GptpIpcReceiverTest, Open_CalledTwice_ReturnsTrueOnSecondCall) { - // region_ != nullptr after first Init → second call returns true immediately. + // region_ != nullptr after first Open → second call returns true immediately. GptpIpcPublisher pub; const std::string name = UniqueShmName(); - ASSERT_TRUE(pub.Init(name)); - ASSERT_TRUE(rx_.Init(name)); - EXPECT_TRUE(rx_.Init(name)); - pub.Destroy(); + ASSERT_TRUE(pub.Open(name)); + ASSERT_TRUE(rx_.Open(name)); + EXPECT_TRUE(rx_.Open(name)); + pub.Close(); } -TEST_F(GptpIpcReceiverTest, Init_TooSmallShm_ReturnsFalse) +TEST_F(GptpIpcReceiverTest, Open_TooSmallShm_ReturnsFalse) { // Create a shm segment smaller than GptpIpcRegion so the fstat size check fails. const std::string name = UniqueShmName(); @@ -179,7 +179,7 @@ TEST_F(GptpIpcReceiverTest, Init_TooSmallShm_ReturnsFalse) ASSERT_EQ(::ftruncate(fd, 1), 0); ::close(fd); - EXPECT_FALSE(rx_.Init(name)); + EXPECT_FALSE(rx_.Open(name)); ::shm_unlink(name.c_str()); } @@ -196,7 +196,7 @@ class GptpIpcRoundtripTest : public ::testing::Test void TearDown() override { rx_.Close(); - pub_.Destroy(); + pub_.Close(); } std::string name_; @@ -204,16 +204,16 @@ class GptpIpcRoundtripTest : public ::testing::Test GptpIpcReceiver rx_; }; -TEST_F(GptpIpcRoundtripTest, ReceiverInit_AfterPublisherInit_ReturnsTrue) +TEST_F(GptpIpcRoundtripTest, ReceiverOpen_AfterPublisherOpen_ReturnsTrue) { - ASSERT_TRUE(pub_.Init(name_)); - EXPECT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + EXPECT_TRUE(rx_.Open(name_)); } TEST_F(GptpIpcRoundtripTest, ReceiverReceive_BeforeAnyPublish_ReturnsNullopt) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); // seq_confirm is initialised to 1 (≠ seq=0) by GptpIpcRegion's constructor, // so the seqlock always mismatches before the first Publish() call. // Receive() must exhaust its retries and return std::nullopt. @@ -222,8 +222,8 @@ TEST_F(GptpIpcRoundtripTest, ReceiverReceive_BeforeAnyPublish_ReturnsNullopt) TEST_F(GptpIpcRoundtripTest, PublishReceive_BasicFields_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::td::PtpTimeInfo info{}; info.ptp_assumed_time = std::chrono::nanoseconds{1'234'567'890LL}; @@ -246,8 +246,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_BasicFields_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_StatusFlags_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::td::PtpTimeInfo info{}; info.status.is_timeout = true; @@ -268,8 +268,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_StatusFlags_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_SyncFupData_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::td::PtpTimeInfo info{}; info.sync_fup_data.precise_origin_timestamp = 100'000'000'000ULL; @@ -295,8 +295,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_SyncFupData_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, PublishReceive_PDelayData_RoundtripCorrectly) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); score::td::PtpTimeInfo info{}; info.pdelay_data.request_origin_timestamp = 1'000'000'000ULL; @@ -321,8 +321,8 @@ TEST_F(GptpIpcRoundtripTest, PublishReceive_PDelayData_RoundtripCorrectly) TEST_F(GptpIpcRoundtripTest, MultiplePublish_LastValueIsVisible) { - ASSERT_TRUE(pub_.Init(name_)); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(pub_.Open(name_)); + ASSERT_TRUE(rx_.Open(name_)); for (int i = 1; i <= 5; ++i) { @@ -348,7 +348,7 @@ TEST_F(GptpIpcRoundtripTest, ReceiverInit_WrongMagic_ReturnsFalse) const std::uint32_t bad = 0xDEADBEEFU; std::memcpy(shm.ptr, &bad, sizeof(bad)); - EXPECT_FALSE(rx_.Init(name_)); + EXPECT_FALSE(rx_.Open(name_)); } TEST_F(GptpIpcRoundtripTest, Receive_PersistentOddSeq_ExhaustsRetriesAndReturnsNullopt) @@ -361,7 +361,7 @@ TEST_F(GptpIpcRoundtripTest, Receive_PersistentOddSeq_ExhaustsRetriesAndReturnsN region->seq.store(1U, std::memory_order_relaxed); region->seq_confirm.store(0U, std::memory_order_relaxed); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(rx_.Open(name_)); EXPECT_FALSE(rx_.Receive().has_value()); } @@ -375,7 +375,7 @@ TEST_F(GptpIpcRoundtripTest, Receive_SeqConfirmMismatch_ExhaustsRetriesAndReturn region->seq.store(4U, std::memory_order_relaxed); region->seq_confirm.store(2U, std::memory_order_relaxed); - ASSERT_TRUE(rx_.Init(name_)); + ASSERT_TRUE(rx_.Open(name_)); EXPECT_FALSE(rx_.Receive().has_value()); } diff --git a/score/ts_client/src/gptp_ipc_test_utils.h b/score/ts_client/src/gptp_ipc_test_utils.h index b3b34ea0..c8669579 100644 --- a/score/ts_client/src/gptp_ipc_test_utils.h +++ b/score/ts_client/src/gptp_ipc_test_utils.h @@ -14,11 +14,11 @@ #define SCORE_TS_CLIENT_SRC_GPTP_IPC_TEST_UTILS_H #include "score/ts_client/src/gptp_ipc_channel.h" +#include "score/memory/shared/shared_memory_factory.h" -#include -#include #include #include +#include #include namespace score @@ -28,7 +28,6 @@ namespace ts namespace details { -/// Generate a unique POSIX shm name per invocation (avoids cross-test pollution). inline std::string UniqueShmName() { static std::atomic counter{0}; @@ -36,43 +35,36 @@ inline std::string UniqueShmName() std::to_string(counter.fetch_add(1, std::memory_order_relaxed)); } -/// RAII helper: creates shm manually (without GptpIpcPublisher) for edge-case -/// testing; cleans up in destructor. +/// RAII helper: creates SHM via SharedMemoryFactory (same layout as GptpIpcPublisher) +/// so that GptpIpcReceiver can open it. Gives direct access to the region for +/// edge-case tests that need to corrupt seq/magic. struct ManualShm { - std::string name; - void* ptr = MAP_FAILED; - std::size_t size = sizeof(GptpIpcRegion); + std::shared_ptr resource_; + GptpIpcRegion* region_{nullptr}; + std::string name_; - explicit ManualShm(const std::string& n) : name{n} + explicit ManualShm(const std::string& n) : name_{n} { - const int fd = ::shm_open(name.c_str(), O_CREAT | O_RDWR, 0666); - if (fd < 0) - return; - if (::ftruncate(fd, static_cast(size)) != 0) - { - ::close(fd); - return; - } - ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - ::close(fd); + score::memory::shared::SharedMemoryFactory::Remove(n); + score::memory::shared::SharedMemoryFactory::RemoveStaleArtefacts(n); + resource_ = score::memory::shared::SharedMemoryFactory::Create( + n, + [this](std::shared_ptr res) { + region_ = res->construct(); + }, + sizeof(GptpIpcRegion) + alignof(GptpIpcRegion) - 1U, + score::memory::shared::permission::WorldWritable{}); } ~ManualShm() { - if (ptr != MAP_FAILED) - ::munmap(ptr, size); - ::shm_unlink(name.c_str()); + resource_.reset(); + score::memory::shared::SharedMemoryFactory::Remove(name_); } - bool Valid() const - { - return ptr != MAP_FAILED; - } - GptpIpcRegion* Region() - { - return static_cast(ptr); - } + bool Valid() const { return resource_ != nullptr && region_ != nullptr; } + GptpIpcRegion* Region() { return region_; } }; } // namespace details