Skip to content
Closed
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
28 changes: 14 additions & 14 deletions score/mw/com/design/events_fields/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ field-collection!
## Event related datastructures in LoLa binding

Here we provide insight, how event communication is realized within our `LoLa` (shared memory based) binding. The
following class diagram shows LooLa specific binding implementation and its relationship with binding independent parts:
following class diagram shows LoLa specific binding implementation and its relationship with binding independent parts:

![Structural View](broken_link_k/swh/ddad_score/mw/com/design/events_fields/event_lola_model.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/event_lola_model.puml">

The referenced class `SubscriptionStateMachine` within this model is further detailed (including its dependent entities)
further [below](#event-subscription).
Expand Down Expand Up @@ -188,29 +188,29 @@ The API entry point to events on the server/skeleton side is
In any case a memory-allocation (rather a free event slot search) needs to be done. The general activity to be done in
this case is pictured in the following activity diagram:

![Activity Allocate Sample Slot](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_event_allocate_activity.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_event_allocate_activity.puml">

In case of a mixed criticality setup with an ASIL-B provider/skeleton and both - ASIL-B and ASIL-QM consumers, where
discrete control structures are needed to separate ASIL-B/QM, the activities to be taken by the ASIL-B skeleton are as
follows:

![Activity Allocate Mixed Criticality](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_event_allocate_mixed_critical_activity.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_event_allocate_mixed_critical_activity.puml">

During this activity a more complex sub-activity is executed/referenced, to achieve a coherent change of slot states in
both control structures (containing a rollback mechanism). This activity is modeled separately here:

![Coherent Status Update](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_coherent_set_writing_activity.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_coherent_set_writing_activity.puml">

### Proxy side Activities for Event Access

The central API entry point at proxy/consumer side to access event samples (after a successful subscription) is the
`GetNewSamples()` method of an event instance. The activities taken by the proxy side implementation are as follows:

![Activity GetNewSamples](broken_link_k/swh/ddad_score/mw/com/design/events_fields/get_new_samples_activity.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/get_new_samples_activity.puml">

The activity shown above thereby relies on activity `ReferenceNextEvent`, which is shown here:

![Activity GetNewSamples](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_reference_next_event_activity.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_reference_next_event_activity.puml">

The main proxy algorithm above the shared memory data structures is broken into three entities:
`score::mw::com::impl::lola::ProxyEvent`, `score::mw::com::impl::lola::ProxyEventCommon` and `score::mw::com::impl::lola::SlotCollector`.
Expand Down Expand Up @@ -280,7 +280,7 @@ once we resort back to sideband channel communication for `Subscribe` and `Unsub
We encapsulate the low-level mechanisms provided by `score::mw::com::message_passing` via
class `lola::MessagePassingFacade`, which is shown in the following class model:

![Structural View_MessagePassing](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_message_passing_model.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_message_passing_model.puml">

### `lola::MessagePassingFacade` is a Smart Proxy

Expand Down Expand Up @@ -313,7 +313,7 @@ The `score::mw::com::message_passing::Receiver`s used by `lola::MessagePassingFa
initialization of our `mw::com` runtime. Depending on the `ara::com`/`mw::com` deployment info for the
executable/process, it can be decided, whether only QM (ASIL-QM) or QM and ASIL (ASIL-B) Receivers are needed.

![Sequence Message Passing Init](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_msg_pass_initialize_seq.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_msg_pass_initialize_seq.puml">

### Event subscription

Expand All @@ -340,18 +340,18 @@ instance has been described [here](../skeleton_proxy/README.md#proxy-auto-reconn

The structure and transitions of the state machine are shown in:

![Proxy Event Subscription State Machine](broken_link_k/swh/ddad_score/mw/com/design/events_fields/proxy_event_state_machine.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_msg_pass_proxy_event_state_machineinitialize_seq.puml">

The structural model of the state machine design is as follows:

![Structural View Proxy Event Subscription State Machine](broken_link_k/swh/ddad_score/mw/com/design/events_fields/proxy_event_state_machine_model.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/proxy_event_state_machine_model.puml">

### Event Update Notification

Event Notification is a good showcase for the "smart" behavior of `lola::MessagePassingFacade` as already mentioned (see
example above). Here event notification registrations are aggregated and related messages are only sent once:

![Sequence Message Passing Event Notify](broken_link_k/swh/ddad_score/mw/com/design/events_fields/lola_msg_pass_event_notify.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/lola_msg_pass_event_notify.puml">

#### Managing user provided EventReceiveHandlers

Expand Down Expand Up @@ -438,7 +438,7 @@ looks like! This sequence builds on message passing concepts/sequences already d
[Notifications between skeleton and proxy](#notifications-between-skeleton-and-proxy) and the design of data-structures
placed in shared memory discussed [here](#event-related-datastructures-in-lola-binding)

![Sequence Update Event and Access via Polling](broken_link_k/swh/ddad_score/mw/com/design/events_fields/event_poll_lola_seq.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/event_poll_lola_seq.puml">

# General implementation details of score::mw::com

Expand Down Expand Up @@ -471,4 +471,4 @@ central counter buried inside `SampleReferenceTracker` is atomic.

This sequence diagram depicts the mechanics behind the reference counting on proxy side:

![Sequence during sample reception on proxy side](broken_link_k/swh/ddad_score/mw/com/design/events_fields/sampleptr_ref_counting.uxf?ref=18c835c8d7b01056dd48f257c14f435795a48b7d)
<img src="https://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/eclipse-score/communication/refs/heads/main/score/mw/com/design/events_fields/sampleptr_ref_counting.puml">
269 changes: 269 additions & 0 deletions score/mw/com/design/events_fields/event_lola_model.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
@startuml event_lola_model
title "Event Lola Model"

' Abstract classes and interfaces
abstract SkeletonEventBindingBase {
{abstract} +PrepareOffer(): void
{abstract} +PrepareStopOffer(): void
{abstract} +GetMaxSize(): size_t
}

abstract class SkeletonEventBinding<SampleType> {
{abstract} +Send(SampleType const&): void
{abstract} +Send(SampleAllocateePtr<SampleType>): void
{abstract} +Allocate(): SampleAllocateePtr<SampleType>
+GetMaxSize(): size_t
}

abstract class ProxyEventBindingBase {
{abstract} +Subscribe(size_t maxSampleCount): void
{abstract} +Unsubscribe(): void
{abstract} +GetSubscriptionState(): SubscriptionState
{abstract} +SetReceiveHandler(EventReceiveHandler): void
{abstract} +UnsetReceiveHandler(): void
{abstract} +GetNumNewSamplesAvailable(): Result<size_t>
}

abstract class ProxyEventBinding<SampleType> {
{abstract} +GetNewSamples(score::cpp::callback<void(SamplePtr<SampleType>)>&&, TrackerGuardFactory): Result<size_t>
{static} # MakeSamplePtr(BindingSamplePtr&&, SampleReferenceGuard): SamplePtr<SampleType>
}

abstract class SkeletonBinding {
-events_: SkeletonEvents&
+SkeletonBinding(SkeletonEvents&): void
{abstract} +PrepareStopOffer(): void
{abstract} +PrepareOffer(): Result<void>
}

' Concrete classes
class lola::SkeletonEvent<SampleType> {
-event_data_storage: EventDataStorage<SampleType>*
-event_data_control: score::cpp::optional<EventDataControlComposite>
+SkeletonEvent(parent: Skeleton&, event_fqn: const ElementFqId, max_number_of_slots: const std::size_t, enforce_max_samples: const bool)
+Send(SampleType const&): void
+Send(SampleAllocateePtr<SampleType>): void
+Allocate(): SampleAllocateePtr<SampleType>
+PrepareOffer(): void
+PrepareStopOffer(): void
}

class lola::ProxyEvent<SampleType> {
-parent: Proxy&
-subscription_state_machine: std::shared_ptr<SubscriptionStateMachine>
+ProxyEvent(ProxyBase& parent, ElementFqId)
+Subscribe(size_t maxSampleCount): void
+GetSubscriptionState(): SubscriptionState
+Unsubscribe(): void
+SetReceiveHandler(score::cpp::callback<void(void)>): void
+UnsetReceiveHandler(): void
+GetNewSamples(score::cpp::callback<void(SamplePtr<SampleType>)>&&, TrackerGuardFactory): Result<size_t>
+GetNumNewSamplesAvailable(): Result<size_t>
..
<u>Notes:</u>
Dispatches all calls to functions in ProxyEventBindingBase interface to\nProxyEventCommon.
}

class lola::Skeleton {
-data: SkeletonDataStorage*
-control_qm_: SkeletonDataControl*
-control_asil_b_: SkeletonDataControl*
+Skeleton(const InstanceIdentifier&, SkeletonEvents&)
+PrepareOffer(): ResultBlank
+PrepareStopOffer(): ResultBlank
+Register(ElementFqId, size_t numberOfSlots): std::pair<EventDataStorage*, EventDataControlComposite>
+GetInstanceQualityType() const: QualityType
}

class lola::ProxyEventCommon {
-element_fq_id_: ElementFqId
-parent_: lola::Proxy&
-subscription_event_state_machine_: std::shared_ptr<SubscriptionStateMachine>
-slot_collector_: score::cpp::optional<SlotCollector>
__
+ProxyEventCommon(lola::Proxy& parent, ElementFqId)
+Subscribe(size_t max_sample_count): void
+Unsubscribe(): void
+GetSubscriptionState(): SubscriptionState
+SetReceiveHandler(EventReceiveHandler handler): void
+UnsetReceiveHandler(EventReceiveHandler handler): void
+GetEventSourcePid(): pid_t
+GetElementFQId(): ElementFqId
+GetNumNewSamplesAvailable(): Result<std::size_t>
+GetNewSamplesSlotIndices(size_t max_count): pair<SlotIndexVector::const_reverse_iterator, SlotIndexVector::const_reverse_iterator>
..
<u>Notes:</u>
lola::ProxyEventCommon is not moveable or copyable.
SlotCollector is instantiated by the SubscriptionStateMachine when it enters the
Subscribed state. It is cleared if it subsequently leaves the Subscribed state.
All subscription operations are implemented in the separate class
SubscriptionStateMachine and the associated states.
}

class lola::SubscriptionStateMachine {
..
<u>Notes:</u>
State machine that manages subscriptions to a ProxyEvent.\nDetails about the state machine can be found in\nproxy_event_state_machine.puml and proxy_event_state_machine_model.puml
}

class lola::SlotCollector {
-event_data_control_: EventDataControl&
+SlotCollector(EventDataControl&, const std::size_t max_slots)
+GetNumNewSamplesAvailable(): size_t
+GetNewSamplesSlotIndices(size_t max_count): pair<SlotIndexVector::const_reverse_iterator, SlotIndexVector::const_reverse_iterator>
..
<u>Notes:</u>
SlotCollector is not copyable.
}

class lola::ShmPathBuilder {
+ShmPathBuilder(instance_deployment: const LolaServiceInstanceDeployment&, type_deploymenttype_deployment: const LolaServiceTypeDeployment&)
+GetControlChannelFileName(channel_type: const QualityType): score::cpp::optional<std::string>
+GetDataChannelFileName(): score::cpp::optional<std::string>
+GetControlChannelPath(channel_type: const QualityType): score::cpp::optional<std::string>
+GetDataChannelPath(): score::cpp::optional<std::string>
+GetDataChannelShmName(): score::cpp::optional<std::string>
+GetControlChannelShmName(const QualityType channel_type): score::cpp::optional<std::string>
}

' Template classes and typedefs
class SampleAllocateePtr<SampleType> {
-internal: std::variant<score::cpp::blank, lola::SampleAllocateePtr, std::unique_ptr<SampleType>>
..
<u>Notes:</u>
Variant is used to enable future version were multiple backends are supported

}

class lola::SampleAllocateePtr<SampleType> {
-managed_object_: SampleType*
-event_data_control_: EventDataControlComposite
+SampleAllocateePtr()
+SampleAllocateePtr(std::nullptr_t)
+SampleAllocateePtr(ptr: pointer, const EventDataControlComposite&, const EventDataControl::SlotIndexType)
+GetReferencedSlot() const: EventDataControl::SlotIndexType
+get() const: SampleType*
+reset(std::nullptr_t): void
+swap(other: SampleAllocateePtr&): void
}

class SamplePtr<SampleType> {
#internal: std::variant<lola::SamplePtr>
+SampleAllocateePtr(std::nullptr_t)
+reset(const pointer ptr = SampleType*): void
+swap(other: SampleAllocateePtr<SampleType>&): void
+get(): SampleType*
..
<u>Notes:</u>
Variant is used to enable future\nversion were multiple backends are supported
}

class lola::SamplePtr<SampleType> {
-managed_object_: SampleType*
-event_data_control_: EventDataControl*
+SamplePtr()
+SamplePtr(std::nullptr_t)
+SamplePtr(pointer ptr, const EventDataControlComposite&, const EventDataControl::SlotIndexType)
+get() const: pointer
+swap(): void
}

' Shared memory classes
class "<<SharedMemory>>\n<<typedef>>\nEventDataStorage<SampleType>" as EventDataStorage {
DynamicArray<SampleType,\nstd::scoped_allocator_adaptor<memory::shared::PolymorphicOffsetPtrAllocator<SampleType>>>
..
<u>Notes:</u>
Exists once per Event\nOnly writable by Skeleton,\nreadable by all subscribed Proxies independent of ASIL level.
}

class "<<SharedMemory>>\n<<typedef>>\nSkeletonDataStorage<SampleType>" as SkeletonDataStorage {
std::map<ElementFqId, offset_ptr<void>>
..
<u>Notes:</u>
The offset_ptr<void> SkeletonDataStorage stored as the value in the map is an offset_ptr<EventDataStorage> which has its type erased.\nThe type is identified later when samples are retrieved, see GetNewSamples for an explanation.
}

class "<<SharedMemory>>\nlola::SkeletonDataControl" {
+event_data_control_: std::map<ElementFqId, EventDataControl>
+skeleton_pid_: pid_t
+SkeletonDataControl(proxy: score::memory::shared::MemoryResourceProxy* const)
}

class "<<SharedMemory>>\nlola::EventDataControlImpl" {
-state_slots: std::vector<std::atomic<EventSlotStatusType::value_type>, PolymorphicOffsetAllocator<std::atomic<EventSlotStatusType::value_type>>>
+EventDataControlImpl(MemoryResourceProxy*, SlotIndexType maxSlots)
+AllocateNextSlot(): std::optional<SlotIndexType>
+EventReady(SlotIndexType, EventTimestamp): void
+Discard(SlotIndexType): void
+ReferenceNextEvent(lastSearchTime: EventTimestampType, upper_limit: const EventSlotStatus::EventTimeStamp): std::optional<SlotIndexType>
+DereferenceEvent(SlotIndexType eventSlotIndex): void
+GetNumNewEvents(reference_time: const EventSlotStatus::EventTimeStamp) const: std::size_t
..
<u>Notes:</u>
Exists at least once per provided Event.\nFor an ASIL-B provider/skeleton, which has ASIL-B AND ASIL-QM consumer/subscriber,\nit exists twice: One Control section per ASIL-level in seperated shm-objects.\nReadable/Writable by Skeleton and Proxies.
}

class "<<SharedMemory>>\nlola::EventSlotStatus" {
+EventSlotStatus(init_val: const value_type)
+IsInvalid(): bool
+IsInWriting(): bool
+MarkInWriting(): void
+MarkInvalid(): void
+GetReferenceCount(): SubscriberCount
+GetTimeStamp(): EventTimeStamp
+SetTimeStamp(EventTimeStamp)
+SetReferenceCount(SubscriberCount)
+IsUsed(): bool
+IsTimeStampBetween(EventTimeStamp min, EventTimeStamp max): bool
}

class EventDataControlCompositeImpl<memory::shared::AtomicIndirectorType> {
-asil_qm_control_: EventDataControl*
-asil_b_control_: EventDataControl*
+EventDataControlCompositeImpl(asil_qm_control: EventDataControl* const)
+EventDataControlCompositeImpl(asil_qm_control: EventDataControl* const, asil_b_control: EventDataControl* const)
+AllocateNextSlot(): std::optional<EventDataControl::SlotIndexType>
+EventReady(EventDataControl::SlotIndexType, EventSlotStatus::EventTimeStamp): void
+Discard(EventDataControl::SlotIndexType): void
+IsQmControlDisconnected(): bool
}

enum SubscriptionState {
SUBSCRIBED
NOT_SUBSCRIBED
SUBSCRIPTION_PENDING
}

SkeletonEventBindingBase <|-- SkeletonEventBinding
SkeletonEventBinding <|-- lola::SkeletonEvent
"SkeletonBinding" <|-- "lola::SkeletonEvent"
"SkeletonBinding" ..> "lola::SkeletonEvent"
ProxyEventBindingBase <|-- ProxyEventBinding
ProxyEventBinding <|-- lola::ProxyEvent
lola::Skeleton *-- SkeletonDataStorage : "1..1"
lola::Skeleton *-- "<<SharedMemory>>\nlola::SkeletonDataControl" : "1..2"
"<<SharedMemory>>\nlola::SkeletonDataControl" *-- "<<SharedMemory>>\nlola::EventDataControlImpl" : "0..n"
lola::SkeletonEvent *-- "EventDataStorage"
lola::SkeletonEvent *-- EventDataControlCompositeImpl
"<<SharedMemory>>\nlola::EventDataControlImpl" ..> "<<SharedMemory>>\nlola::EventSlotStatus"
SampleAllocateePtr o-- lola::SampleAllocateePtr
SamplePtr o-- lola::SamplePtr
lola::ProxyEvent *-- lola::ProxyEventCommon
lola::ProxyEventCommon *-- lola::SubscriptionStateMachine
lola::ProxyEventCommon --* lola::SlotCollector
ProxyEventBindingBase *-- SubscriptionState
lola::SampleAllocateePtr *-- EventDataControlCompositeImpl
EventDataControlCompositeImpl *-- "<<SharedMemory>>\nlola::EventDataControlImpl" : "2"
lola::Skeleton ..> lola::ShmPathBuilder : uses
lola::Skeleton ..> EventDataControlCompositeImpl
lola::SubscriptionStateMachine ..> lola::SlotCollector : <<creates>>
SkeletonEventBinding ..> SampleAllocateePtr
lola::ProxyEvent ..> lola::SamplePtr
SkeletonDataStorage *-- "EventDataStorage" : "0..n"
lola::SlotCollector *-- "<<SharedMemory>>\nlola::EventDataControlImpl"
ProxyEventBinding ..> SamplePtr
lola::SkeletonEvent ..> lola::SampleAllocateePtr
lola::SamplePtr ..> "<<SharedMemory>>\nlola::EventDataControlImpl"
lola::SampleAllocateePtr ..> "<<SharedMemory>>\nlola::EventDataControlImpl"

@enduml
Loading
Loading