Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions score/mw/com/impl/bindings/lola/proxy_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
#define SCORE_MW_COM_IMPL_BINDINGS_LOLA_PROXY_EVENT_H

#include "score/mw/com/impl/bindings/lola/event_data_storage.h"
#include "score/mw/com/impl/bindings/lola/event_meta_info.h"
#include "score/mw/com/impl/bindings/lola/proxy_event_common.h"

#include "score/language/safecpp/safe_math/safe_math.h"
#include "score/memory/shared/pointer_arithmetic_util.h"
#include "score/mw/com/impl/proxy_event_binding.h"
#include "score/mw/com/impl/sample_reference_tracker.h"
#include "score/mw/com/impl/subscription_state.h"
Expand Down Expand Up @@ -64,7 +68,7 @@ class ProxyEvent final : public ProxyEventBinding<SampleType>
ProxyEvent(Proxy& parent, const ElementFqId element_fq_id, const std::string_view event_name)
: ProxyEventBinding<SampleType>{},
proxy_event_common_{parent, element_fq_id, event_name},
samples_{parent.GetEventDataStorage<SampleType>(element_fq_id)}
meta_info_{parent.GetEventMetaInfo(element_fq_id)}
{
}

Expand Down Expand Up @@ -126,7 +130,7 @@ class ProxyEvent final : public ProxyEventBinding<SampleType>
Result<std::size_t> GetNumNewSamplesAvailableImpl() const noexcept;

ProxyEventCommon proxy_event_common_;
const EventDataStorage<SampleType>& samples_;
const EventMetaInfo& meta_info_;
};

template <typename SampleType>
Expand Down Expand Up @@ -184,9 +188,40 @@ inline Result<std::size_t> ProxyEvent<SampleType>::GetNewSamplesImpl(Callback&&

auto& event_data_control_local = proxy_event_common_.GetConsumerEventDataControlLocal();

const std::size_t aligned_sample_size =
memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
const auto event_slots_raw_array_size =
safe_math::Multiply(aligned_sample_size, event_data_control_local.GetMaxSampleSlots());
if (!event_slots_raw_array_size.has_value())
{
score::mw::log::LogFatal("lola") << "Could not calculate the event slots raw array size. Terminating.";
std::terminate();
}

const void* const event_slots_raw_array = meta_info_.event_slots_raw_array_.get(event_slots_raw_array_size.value());
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(nullptr != event_slots_raw_array, "Null event slot array");
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(meta_info_.data_type_info_.size == sizeof(SampleType),
"Event sample size mismatch");
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(meta_info_.data_type_info_.alignment == alignof(SampleType),
"Event sample alignment mismatch");

for (auto slot_index_it = slot_indices.begin; slot_index_it != slot_indices.end; ++slot_index_it)
{
const SampleType& sample_data{samples_.at(static_cast<std::size_t>(*slot_index_it))};
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) The pointer event_slots_raw_array points to
// the first byte of the type-erased event sample storage in shared memory. Samples may originate from either a
// typed SkeletonEvent or a GenericSkeletonEvent, therefore slot lookup must use the stable EventMetaInfo raw
// storage address and SampleType stride instead of interpreting the shared-memory DynamicArray object type.
const auto* const event_slots_array = static_cast<const std::uint8_t*>(event_slots_raw_array);
const auto* const object_start_address = &event_slots_array[aligned_sample_size * (*slot_index_it)];
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)

// Suppress "AUTOSAR C++14 M5-2-8" rule finding: "An object with integer type or pointer to void type shall
// not be converted to an object with pointer type.".
// The raw storage address is provided through EventMetaInfo. The regular typed proxy validates the expected
// type at compile time and calculates the slot offset with sizeof(SampleType)/alignof(SampleType).
// coverity[autosar_cpp14_m5_2_8_violation]
const auto* const typed_sample_data = reinterpret_cast<const SampleType*>(object_start_address);
const SampleType& sample_data{*typed_sample_data};
const EventSlotStatus event_slot_status{event_data_control_local[*slot_index_it]};
const EventSlotStatus::EventTimeStamp sample_timestamp{event_slot_status.GetTimeStamp()};

Expand Down
33 changes: 31 additions & 2 deletions score/mw/com/impl/bindings/lola/proxy_event_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,35 @@ TYPED_TEST(LolaProxyEventDeathTest, FailOnEventNotFound)
}

using LoLaTypedProxyEventTestFixture = LolaProxyEventFixture<ProxyEventStruct>;
TEST_F(LoLaTypedProxyEventTestFixture, ReadsSamplesFromGenericSkeletonRawStorage)
{
RecordProperty("Verifies", "SCR-6225206");
RecordProperty("Description",
"Checks that a typed ProxyEvent reads samples from EventMetaInfo raw storage so it is compatible "
"with a GenericSkeletonEvent storage representation.");
RecordProperty("TestType", "Regression test");
RecordProperty("DerivationTechnique", "Analysis of bug 311");

this->ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout();
const std::size_t max_sample_count_subscription{5U};
this->GivenAProxyEvent(this->element_fq_id_, this->event_name_)
.ThatIsSubscribedWithMaxSamples(max_sample_count_subscription)
.WithSkeletonEventData({{kDummySampleValue, kDummyInputTimestamp}});

const std::size_t max_samples{1U};
TestSampleType received_sample{0U};
const auto receiver = [&received_sample](impl::SamplePtr<TestSampleType> sample,
const tracing::ITracingRuntime::TracePointDataId) {
received_sample = *sample;
};

const auto num_callbacks_result = this->GetNewSamples(receiver, max_samples);

ASSERT_TRUE(num_callbacks_result.has_value());
EXPECT_EQ(num_callbacks_result.value(), 1U);
EXPECT_EQ(received_sample, kDummySampleValue);
}

TEST_F(LoLaTypedProxyEventTestFixture, SampleConstness)
{
RecordProperty("Verifies", "SCR-6340729");
Expand All @@ -703,8 +732,8 @@ TEST_F(LoLaTypedProxyEventTestFixture, SampleConstness)
this->GivenAProxyEvent(this->element_fq_id_, this->event_name_);

ProxyEventAttorney<TestSampleType> proxy_event_attorney{*test_proxy_event_};
using SamplesMemberType = typename std::remove_reference<decltype(proxy_event_attorney.GetSamplesMember())>::type;
static_assert(std::is_const<SamplesMemberType>::value, "Proxy should hold const slot data.");
using MetaInfoMemberType = typename std::remove_reference<decltype(proxy_event_attorney.GetMetaInfoMember())>::type;
static_assert(std::is_const<MetaInfoMemberType>::value, "Proxy should hold const event meta info.");
}

} // namespace
Expand Down
5 changes: 3 additions & 2 deletions score/mw/com/impl/bindings/lola/skeleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,9 @@ auto Skeleton::RegisterGeneric(const ElementFqId element_fq_id,
memory_manager_.RollbackSkeletonTracingTransactions(*event_data_control_asil_b);
}

auto& event_data_storage = memory_manager_.RetrieveEventDataFromOpenedSharedMemory<std::uint8_t>(element_fq_id);
return {static_cast<void*>(&event_data_storage), event_data_control_qm, event_data_control_asil_b};
auto* const event_data_storage =
memory_manager_.RetrieveGenericEventDataFromOpenedSharedMemory(element_fq_id, element_properties);
return {event_data_storage, event_data_control_qm, event_data_control_asil_b};
}

auto* const type_erased_event_data_storage = memory_manager_.CreateGenericEventDataInCreatedSharedMemory(
Expand Down
31 changes: 30 additions & 1 deletion score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "score/mw/com/impl/runtime.h"
#include "score/mw/com/impl/skeleton_event_binding.h"

#include "score/language/safecpp/safe_math/safe_math.h"
#include "score/memory/shared/managed_memory_resource.h"
#include "score/memory/shared/new_delete_delegate_resource.h"
#include "score/memory/shared/shared_memory_factory.h"
Expand Down Expand Up @@ -232,7 +233,35 @@ void* SkeletonMemoryManager::CreateGenericEventDataInCreatedSharedMemory(
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(inserted_meta_info.second,
"Couldn't register/emplace event-meta-info in data-section.");

return data_storage;
return event_data_raw_array;
}

void* SkeletonMemoryManager::RetrieveGenericEventDataFromOpenedSharedMemory(
const ElementFqId element_fq_id,
const SkeletonEventProperties& element_properties) noexcept
{
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(storage_ != nullptr, "Service data storage is not available.");

const auto event_meta_info_it = storage_->events_metainfo_.find(element_fq_id);
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(event_meta_info_it != storage_->events_metainfo_.cend(),
"Could not find element fq id in meta info map");

const auto sample_size = event_meta_info_it->second.data_type_info_.size;
const auto sample_alignment = event_meta_info_it->second.data_type_info_.alignment;
const auto aligned_sample_size =
memory::shared::CalculateAlignedSize(sample_size, static_cast<std::size_t>(sample_alignment));
const auto total_event_slots_size = safe_math::Multiply(aligned_sample_size, element_properties.number_of_slots);
if (!total_event_slots_size.has_value())
{
score::mw::log::LogFatal("lola") << "Could not calculate the event slots raw array size. Terminating.";
std::terminate();
}

void* const event_slots_raw_array =
event_meta_info_it->second.event_slots_raw_array_.get(total_event_slots_size.value());
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(event_slots_raw_array != nullptr,
"Could not get generic EventDataStorage raw array");
return event_slots_raw_array;
}

auto SkeletonMemoryManager::RetrieveEventControlsFromOpenedSharedMemory(const ElementFqId element_fq_id)
Expand Down
8 changes: 8 additions & 0 deletions score/mw/com/impl/bindings/lola/skeleton_memory_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ class SkeletonMemoryManager final
template <typename SampleType>
auto RetrieveEventDataFromOpenedSharedMemory(const ElementFqId element_fq_id) -> EventDataStorage<SampleType>&;

/// \brief Retrieves the raw event sample storage pointer for a generic event from opened shared memory.
///
/// Generic events use EventMetaInfo as the stable type-erased contract. This keeps generic skeleton restarts
/// independent from the concrete DynamicArray<T> representation used by typed skeletons and proxies.
auto RetrieveGenericEventDataFromOpenedSharedMemory(const ElementFqId element_fq_id,
const SkeletonEventProperties& element_properties) noexcept
-> void*;

/// \brief Rolls back any existing operations in the TransactionLog corresponding to a SkeletonEvent
///
/// The TransactionLog would only exist if a SkeletonEvent in a crashed process had tracing enabled. If tracing was
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
#include "score/mw/com/impl/bindings/lola/test/proxy_event_test_resources.h"

#include "score/memory/shared/memory_resource_registry.h"
#include "score/memory/shared/pointer_arithmetic_util.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <cstring>
#include <memory>
#include <utility>

Expand Down Expand Up @@ -129,6 +131,27 @@ void ProxyMockedMemoryFixture::InitialiseDummySkeletonEvent(const ElementFqId el
provider_event_data_control_local_.emplace(event_control_->data_control);
}

void LolaProxyEventResources::ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout()
{
const auto aligned_sample_size = memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
const auto total_data_size_bytes = aligned_sample_size * max_num_slots_;
const auto num_max_align_elements =
(total_data_size_bytes + sizeof(std::max_align_t) - 1U) / sizeof(std::max_align_t);

auto* const generic_event_data_slots = fake_data_->data_memory->construct<EventDataStorage<std::max_align_t>>(
num_max_align_elements,
memory::shared::PolymorphicOffsetPtrAllocator<std::max_align_t>(*fake_data_->data_memory));
generic_event_data_storage_ = static_cast<std::uint8_t*>(static_cast<void*>(generic_event_data_slots->data()));

auto event_data_it = fake_data_->data_storage->events_.find(element_fq_id_);
SCORE_LANGUAGE_FUTURECPP_ASSERT(event_data_it != fake_data_->data_storage->events_.end());
event_data_it->second = memory::shared::OffsetPtr<void>{static_cast<void*>(generic_event_data_slots)};

auto event_meta_info_it = fake_data_->data_storage->events_metainfo_.find(element_fq_id_);
SCORE_LANGUAGE_FUTURECPP_ASSERT(event_meta_info_it != fake_data_->data_storage->events_metainfo_.end());
event_meta_info_it->second.event_slots_raw_array_ = memory::shared::OffsetPtr<void>{generic_event_data_storage_};
}

LolaProxyEventResources::LolaProxyEventResources() : ProxyMockedMemoryFixture{}
{
InitialiseDummySkeletonEvent(element_fq_id_, SkeletonEventProperties{max_num_slots_, max_subscribers_, true});
Expand Down Expand Up @@ -187,7 +210,17 @@ SlotIndexType LolaProxyEventResources::PutData(const std::uint32_t value,
auto slot_result = provider_event_data_control_local_->AllocateNextSlot();
EXPECT_TRUE(slot_result.has_value());
auto slot_index = slot_result.value();
event_data_storage_->at(slot_index) = value;
if (generic_event_data_storage_ != nullptr)
{
const auto aligned_sample_size = memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
auto* const slot_address =
memory::shared::AddOffsetToPointer(generic_event_data_storage_, aligned_sample_size * slot_index);
std::memcpy(slot_address, &value, sizeof(value));
}
else
{
event_data_storage_->at(slot_index) = value;
}
provider_event_data_control_local_->EventReady(slot_index, timestamp);
return slot_index;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef SCORE_MW_COM_IMPL_BINDINGS_LOLA_TEST_PROXY_EVENT_TEST_RESOURCES_H
#define SCORE_MW_COM_IMPL_BINDINGS_LOLA_TEST_PROXY_EVENT_TEST_RESOURCES_H

#include "score/mw/com/impl/bindings/lola/event_data_storage.h"
#include "score/mw/com/impl/bindings/lola/event_subscription_control.h"
#include "score/mw/com/impl/bindings/lola/generic_proxy_event.h"
#include "score/mw/com/impl/bindings/lola/i_runtime.h"
Expand Down Expand Up @@ -94,9 +95,9 @@ class ProxyEventAttorney

ProxyEventAttorney(ProxyEvent<T>& proxy_event) noexcept : proxy_event_{proxy_event} {}

auto& GetSamplesMember()
auto& GetMetaInfoMember()
{
return proxy_event_.samples_;
return proxy_event_.meta_info_;
}

private:
Expand Down Expand Up @@ -207,6 +208,7 @@ class ProxyMockedMemoryFixture : public ::testing::Test
std::optional<ProviderEventDataControlLocalView<>> provider_event_data_control_local_{};
std::optional<ConsumerEventDataControlLocalView<>> consumer_event_data_control_local_{};
EventDataStorage<SampleType>* event_data_storage_{nullptr};
std::uint8_t* generic_event_data_storage_{nullptr};
RollbackSynchronization rollback_synchronization_{};

std::shared_ptr<MessagePassingServiceMock> mock_service_{std::make_shared<MessagePassingServiceMock>()};
Expand All @@ -226,6 +228,8 @@ class LolaProxyEventResources : public ProxyMockedMemoryFixture
void ExpectReregisterEventNotification(score::cpp::optional<pid_t> pid = {});
void ExpectUnregisterEventNotification(score::cpp::optional<pid_t> pid = {});

void ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout();

SlotIndexType PutData(const std::uint32_t value = 42, const EventSlotStatus::EventTimeStamp timestamp = 1);

const std::size_t max_num_slots_{5U};
Expand Down
49 changes: 49 additions & 0 deletions score/mw/com/test/generic_skeleton_typed_proxy/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# *******************************************************************************
# 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("//score/mw/com/test:pkg_application.bzl", "pkg_application")

cc_binary(
name = "generic_skeleton_typed_proxy",
srcs = [
"generic_skeleton_typed_proxy_application.cpp",
"generic_skeleton_typed_proxy_application.h",
],
data = ["mw_com_config.json"],
features = COMPILER_WARNING_FEATURES + [
"aborts_upon_exception",
],
deps = [
"//score/mw/com",
"//score/mw/com/test/common_test_resources:bigdata_type",
"//score/mw/com/test/common_test_resources:sample_sender_receiver",
"//score/mw/com/test/common_test_resources:sctf_test_runner",
"@score_baselibs//score/language/futurecpp",
],
)

pkg_application(
name = "generic_skeleton_typed_proxy-pkg",
app_name = "generic_skeleton_typed_proxy",
bin = [":generic_skeleton_typed_proxy"],
etc = [
"mw_com_config.json",
"logging.json",
],
visibility = [
"//platform/aas/test/mw/com:__pkg__",
"//score/mw/com/test/generic_skeleton_typed_proxy:__subpackages__",
],
)
Loading