Skip to content
Draft
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
2 changes: 2 additions & 0 deletions score/mw/com/impl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ cc_library(
"//score/mw/com/impl/mocking:i_skeleton_event",
"//score/mw/com/impl/plumbing:event",
"//score/mw/com/impl/plumbing:sample_allocatee_ptr",
"//score/mw/com/impl/plumbing:sample_ptr",
"//score/mw/com/impl/tracing:skeleton_event_tracing",
"@score_baselibs//score/mw/log",
"@score_baselibs//score/result",
Expand Down Expand Up @@ -534,6 +535,7 @@ cc_library(
deps = [
":binding_type",
"//score/mw/com/impl/plumbing:sample_allocatee_ptr",
"//score/mw/com/impl/plumbing:sample_ptr",
"//score/mw/com/impl/tracing:skeleton_event_tracing_data",
"@score_baselibs//score/language/futurecpp",
"@score_baselibs//score/result",
Expand Down
1 change: 1 addition & 0 deletions score/mw/com/impl/bindings/lola/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ cc_library(
"//score/mw/com/impl/configuration",
"//score/mw/com/impl/methods:skeleton_method_binding",
"//score/mw/com/impl/plumbing:sample_allocatee_ptr",
"//score/mw/com/impl/plumbing:sample_ptr",
"//score/mw/com/impl/tracing:skeleton_event_tracing",
"//score/mw/com/impl/util:arithmetic_utils",
"@score_baselibs//score/filesystem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,59 @@ auto ConsumerEventDataControlLocalView<AtomicIndirectorType>::ReferenceNextEvent
return {};
}

template <template <class> class AtomicIndirectorType>
auto ConsumerEventDataControlLocalView<AtomicIndirectorType>::GetLatestSlot() noexcept -> std::optional<SlotIndexType>
{
for (std::size_t retry_counter{0U}; retry_counter < MAX_REFERENCE_RETRIES; ++retry_counter)
{
EventSlotStatus::EventTimeStamp latest_time_stamp{EventSlotStatus::FIRST_VALID_TIMESTAMP};
std::optional<SlotIndexType> latest_slot_index{};
EventSlotStatus latest_slot_status{};

SlotIndexType current_index = 0U;
for (const auto& slot : state_slots_)
{
const EventSlotStatus slot_status{slot.load(std::memory_order_acquire)};
if (!slot_status.IsInvalid() && !slot_status.IsInWriting())
{
const auto slot_time_stamp = slot_status.GetTimeStamp();
if (latest_time_stamp < slot_time_stamp)
{
latest_time_stamp = slot_time_stamp;
latest_slot_index = current_index;
latest_slot_status = slot_status;
}
}
++current_index;
}

if (!latest_slot_index.has_value())
{
return {};
}

const auto slot_index = latest_slot_index.value();
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(static_cast<std::size_t>(slot_index) < state_slots_.size());

auto expected = static_cast<EventSlotStatus::value_type>(latest_slot_status);
const auto new_refcount =
static_cast<EventSlotStatus::SubscriberCount>(latest_slot_status.GetReferenceCount() + 1U);
const EventSlotStatus updated_slot_status{latest_slot_status.GetTimeStamp(), new_refcount};
const auto desired = static_cast<EventSlotStatus::value_type>(updated_slot_status);

transaction_log_local_view_->ReferenceTransactionBegin(slot_index);
if (AtomicIndirectorType<EventSlotStatus::value_type>::compare_exchange_weak(
state_slots_[slot_index], expected, desired, std::memory_order_acq_rel))
{
transaction_log_local_view_->ReferenceTransactionCommit(slot_index);
return latest_slot_index;
}
transaction_log_local_view_->ReferenceTransactionAbort(slot_index);
}

return {};
}

template <template <class> class AtomicIndirectorType>
// Suppress "AUTOSAR C++14 A15-5-3" rule findings. This rule states: "The std::terminate() function shall not be called
// implicitly". std::terminate() is implicitly called from 'state_slots_[]' which might leds to a segmentation fault
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

namespace score::mw::com::impl::lola
{
template <typename SampleType>
class SkeletonEventCommon;

/// \brief View class which provides functionality for interacting with EventDataControl.
///
Expand Down Expand Up @@ -68,6 +70,13 @@ class ConsumerEventDataControlLocalView final
~ConsumerEventDataControlLocalView() noexcept = default;

ConsumerEventDataControlLocalView(const ConsumerEventDataControlLocalView&) = delete;

// Suppress "AUTOSAR C++14 A11-3-1"
// SkeletonEventCommon needs controlled access to transaction-log view injection/cleanup for dual quality
// consumer setup.
// coverity[autosar_cpp14_a11_3_1_violation]
template <typename SampleType>
friend class SkeletonEventCommon;
ConsumerEventDataControlLocalView& operator=(const ConsumerEventDataControlLocalView&) = delete;
ConsumerEventDataControlLocalView(ConsumerEventDataControlLocalView&&) noexcept = delete;
ConsumerEventDataControlLocalView& operator=(ConsumerEventDataControlLocalView&& other) noexcept = delete;
Expand All @@ -87,6 +96,15 @@ class ConsumerEventDataControlLocalView final
const EventSlotStatus::EventTimeStamp last_search_time,
const EventSlotStatus::EventTimeStamp upper_limit = EventSlotStatus::TIMESTAMP_MAX) noexcept;

/// \brief Returns the latest readable sample and marks it as referenced.
///
/// \details This method performs bounded retries on data races while increasing the reference count for the
/// selected slot.
///
/// \return Index of latest sample if available, empty optional otherwise.
/// \post DereferenceEvent() is invoked to withdraw read-ownership
std::optional<SlotIndexType> GetLatestSlot() noexcept;

/// \brief Increments refcount of given slot by one (given it is in the correct state i.e. being accessible/
/// readable)
/// \details This is a specific feature - not used by the standard proxy/consumer, which is using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,38 @@ TEST_F(ConsumerEventDataControlLocalViewFixture, FailingToUpdateSlotValueCausesR
// No event will be found
ASSERT_FALSE(event.has_value());
}

TEST_F(ConsumerEventDataControlLocalViewFixture, GetLatestSlotReturnsNewestReadySlot)
{
// Given an EventDataControl with multiple ready slots and increasing timestamps
GivenAConsumerEventDataControlLocalViewUsingRealAtomics(3);
score::cpp::ignore = WithAnAllocatedSlot(1);
score::cpp::ignore = WithAnAllocatedSlot(2);
score::cpp::ignore = WithAnAllocatedSlot(3);

// When requesting the latest slot
const auto latest_slot = unit_->GetLatestSlot();

// Then the newest sample is returned and referenced
ASSERT_TRUE(latest_slot.has_value());
EXPECT_EQ((*unit_)[latest_slot.value()].GetTimeStamp(), 3U);
EXPECT_EQ((*unit_)[latest_slot.value()].GetReferenceCount(), 1U);
}

TEST_F(ConsumerEventDataControlLocalViewFixture, GetLatestSlotReturnsNullIfNoReadySlotExists)
{
// Given an EventDataControl with one slot in writing state (allocated but not marked ready)
GivenAConsumerEventDataControlLocalViewUsingRealAtomics(1);
const auto allocated_slot = provider_event_data_control_local_->AllocateNextSlot();
ASSERT_TRUE(allocated_slot.has_value());

// When requesting the latest slot
const auto latest_slot = unit_->GetLatestSlot();

// Then no slot is returned
EXPECT_FALSE(latest_slot.has_value());
}

using EventDataControlReferenceSpecificEventFixture = ConsumerEventDataControlLocalViewFixture;
TEST_F(EventDataControlReferenceSpecificEventFixture, ReferenceSpecificEvents)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ template <template <class> class AtomicIndirectorType>
// coverity[autosar_cpp14_a15_5_3_violation : FALSE]
EventSlotStatus::EventTimeStamp EventDataControlComposite<AtomicIndirectorType>::GetLatestTimestamp() const noexcept
{
EventSlotStatus::EventTimeStamp latest_time_stamp{1U};
EventSlotStatus::EventTimeStamp latest_time_stamp{EventSlotStatus{}.GetTimeStamp()};
auto& control = (asil_b_control_local_ != nullptr) ? *asil_b_control_local_ : asil_qm_control_local_.get();
for (SlotIndexType slot_index = 0U;
// Suppress "AUTOSAR C++14 A4-7-1" rule finding. This rule states: "An integer expression shall not lead to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,9 @@ TEST_F(EventDataControlCompositeFixture, GetLatestTimeStampReturnsDefaultValuesI
unit_->Discard(allocation_result.allocated_slot_index.value());
unit_->Discard(allocation_result_2.allocated_slot_index.value());

// Then the timestamp equal to 1
// Then the timestamp is invalid
auto time_stamp = unit_->GetLatestTimestamp();
EventSlotStatus::EventTimeStamp expected_time_stamp{1};
EventSlotStatus::EventTimeStamp expected_time_stamp{EventSlotStatus{}.GetTimeStamp()};
EXPECT_EQ(time_stamp, expected_time_stamp);
}

Expand All @@ -295,9 +295,9 @@ TEST_F(EventDataControlCompositeFixture, GetLatestTimeStampReturnsDefaultValuesI
// Given an EventDataControlComposite with zero used slots
WithQmAndAsilBEventDataControlCompositeUsingRealAtomics();

// Then the timestamp equal to 1
// Then the timestamp is invalid
auto time_stamp = unit_->GetLatestTimestamp();
EventSlotStatus::EventTimeStamp expected_time_stamp{1};
EventSlotStatus::EventTimeStamp expected_time_stamp{EventSlotStatus{}.GetTimeStamp()};
EXPECT_EQ(time_stamp, expected_time_stamp);
}

Expand All @@ -310,9 +310,9 @@ TEST_F(EventDataControlCompositeFixture,
// When allocating 1 slot
score::cpp::ignore = unit_->AllocateNextSlot();

// Then the timestamp equal to 1
// Then the timestamp is invalid
auto time_stamp = unit_->GetLatestTimestamp();
EventSlotStatus::EventTimeStamp expected_time_stamp{1};
EventSlotStatus::EventTimeStamp expected_time_stamp{EventSlotStatus{}.GetTimeStamp()};
EXPECT_EQ(time_stamp, expected_time_stamp);
}

Expand Down
10 changes: 8 additions & 2 deletions score/mw/com/impl/bindings/lola/event_slot_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ class EventSlotStatus final
// coverity[autosar_cpp14_a0_1_1_violation : FALSE]
static constexpr EventTimeStamp TIMESTAMP_MAX = std::numeric_limits<EventTimeStamp>::max();

/// \brief If default constructed, SlotStatus is invalid
EventSlotStatus() noexcept = default;
/// \brief First valid timestamp value that can appear in shared memory.
static constexpr EventTimeStamp FIRST_VALID_TIMESTAMP{1U};

EventSlotStatus() noexcept : EventSlotStatus{UNINITIALIZED_TIMESTAMP} {}
explicit EventSlotStatus(const value_type init_val) noexcept;
EventSlotStatus(const EventTimeStamp timestamp, const SubscriberCount refcount) noexcept;
EventSlotStatus(const EventSlotStatus&) noexcept = default;
Expand Down Expand Up @@ -83,9 +85,13 @@ class EventSlotStatus final
bool IsTimeStampBetween(const EventTimeStamp min_timestamp, const EventTimeStamp max_timestamp) const noexcept;

private:
/// \brief Timestamp value indicating that a slot was never written.
static constexpr EventTimeStamp UNINITIALIZED_TIMESTAMP{0U};

value_type data_;
};

static_assert(sizeof(EventSlotStatus) <= sizeof(std::uint64_t));
} // namespace score::mw::com::impl::lola

#endif // SCORE_MW_COM_IMPL_BINDINGS_LOLA_EVENT_SLOT_STATUS_H
3 changes: 3 additions & 0 deletions score/mw/com/impl/bindings/lola/generic_skeleton_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class GenericSkeletonEvent : public GenericSkeletonEventBinding
skeleton_event_common_.SetSkeletonEventTracingData(tracing_data);
}

// GenericSkeletonEvent does not support getter functionality (void type); no-op.
void SetGetterEnabled(bool /*getter_enabled*/) noexcept override {}

std::size_t GetMaxSize() const noexcept override
{
return size_info_.size;
Expand Down
38 changes: 38 additions & 0 deletions score/mw/com/impl/bindings/lola/skeleton_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,25 @@
#include "score/mw/com/impl/bindings/lola/i_runtime.h"
#include "score/mw/com/impl/bindings/lola/provider_event_data_control_local_view.h"
#include "score/mw/com/impl/bindings/lola/sample_allocatee_ptr.h"
#include "score/mw/com/impl/bindings/lola/sample_ptr.h"
#include "score/mw/com/impl/bindings/lola/skeleton.h"
#include "score/mw/com/impl/bindings/lola/skeleton_event_common.h"
#include "score/mw/com/impl/bindings/lola/skeleton_event_properties.h"
#include "score/mw/com/impl/com_error.h"
#include "score/mw/com/impl/configuration/quality_type.h"
#include "score/mw/com/impl/plumbing/sample_allocatee_ptr.h"
#include "score/mw/com/impl/plumbing/sample_ptr.h"
#include "score/mw/com/impl/runtime.h"
#include "score/mw/com/impl/skeleton_event_binding.h"
#include "score/mw/com/impl/tracing/skeleton_event_tracing_data.h"

#include "score/mw/log/logging.h"

#include "score/result/result.h"
#include <score/assert.hpp>
#include <score/utility.hpp>

#include <cstdint>
#include <optional>
#include <string_view>
#include <utility>
Expand Down Expand Up @@ -87,6 +93,8 @@ class SkeletonEvent final : public SkeletonEventBinding<SampleType>

Result<impl::SampleAllocateePtr<SampleType>> Allocate() noexcept override;

Result<impl::SamplePtr<SampleType>> GetLatestSample(const QualityType& quality_type) noexcept override;

/// @requirement SWS_CM_00700
Result<void> PrepareOffer() noexcept override;

Expand All @@ -102,6 +110,11 @@ class SkeletonEvent final : public SkeletonEventBinding<SampleType>
skeleton_event_common_.SetSkeletonEventTracingData(tracing_data);
}

void SetGetterEnabled(bool getter_enabled) noexcept override
{
skeleton_event_common_.SetGetterEnabled(getter_enabled);
}

private:
EventDataStorage<SampleType>* event_data_storage_;
SkeletonEventCommon<SampleType> skeleton_event_common_;
Expand Down Expand Up @@ -179,6 +192,31 @@ Result<impl::SampleAllocateePtr<SampleType>> SkeletonEvent<SampleType>::Allocate
slot_index));
}

template <typename SampleType>
Result<impl::SamplePtr<SampleType>> SkeletonEvent<SampleType>::GetLatestSample(const QualityType& quality_type) noexcept
{
if (event_data_storage_ == nullptr)
{
::score::mw::log::LogError("lola")
<< "Tried to get latest event sample, but the event has not been offered yet!";
return MakeUnexpected(ComErrc::kBindingFailure);
}

auto& consumer_event_data_control_local = skeleton_event_common_.GetConsumerEventDataControlLocalView(quality_type);
const auto slot_result = consumer_event_data_control_local.GetLatestSlot();
if (!slot_result.has_value())
{
::score::mw::log::LogError("lola") << "GetLatestSlot did not return a slot index";
return MakeUnexpected(ComErrc::kBindingFailure);
}

return impl::SamplePtr<SampleType>{
lola::SamplePtr<SampleType>{&event_data_storage_->at(static_cast<std::uint64_t>(*slot_result)),
consumer_event_data_control_local,
slot_result.value()},
impl::SampleReferenceGuard{}};
}

template <typename SampleType>
// Suppress "AUTOSAR C++14 A15-5-3" rule findings. This rule states: "The std::terminate() function shall not be called
// implicitly". This is a false positive, all results which are accessed with '.value()' that could implicitly call
Expand Down
Loading
Loading