System Monitor

Using the System Monitor

Each participant has access to a System Monitor and can register callbacks to get informed about changes of the ParticipantState or the SystemState that occur during the simulation.

Register Callbacks for State Transitions

To be notified about transitions of the ParticipantState, a ParticipantStatusHandler has to be registered. The ParticipantStatus contains the new ParticipantState and further details about the transition such as the name of the participant, the reason for the status change and timing information:

// Register ParticipantStatusHandler to receive ParticipantStatus updates from all participants.
auto participantStatusHandler =
    [](Orchestration::ParticipantStatus status) {};

auto* systemMonitor = participant->GetSystemMonitor();
systemMonitor->AddParticipantStatusHandler(participantStatusHandler);

A SystemStateHandler can be registered to get informed about system state transitions:

// Register SystemStateHandler to receive SystemState transitions.
auto systemStateHandler =
    [](Orchestration::SystemState state) {};

auto* systemMonitor = participant->GetSystemMonitor();
systemMonitor->AddSystemStateHandler(systemStateHandler);

Register Callbacks for Other Participants

A ParticipantConnectedHandler and ParticipantDisconnectedHandler can be registered. They report the name of any other participant connecting and disconnecting from the participant:

auto* systemMonitor = participant->GetSystemMonitor();

auto participantConnectedHandler = [](const std::string& participantName) { ... };
systemMonitor->SetParticipantConnectedHandler(participantConnectedHandler);

auto participantDisconnectedHandler = [](const std::string& participantName) { ... };
systemMonitor->SetParticipantDisconnectedHandler(participantConnectedHandler);

Additionally, there is a function which checks if a participant identified by it’s name is connected or not:

auto* systemMonitor = participant->GetSystemMonitor();
if (systemMonitor->IsParticipantConnected("SomeParticipant"))
{
  // things to do only if the other participant is connected
}

API and Data Type Reference

System Monitor API

class ISystemMonitor

Public Types

using SystemStateHandler = std::function<void(SystemState)>

Callback type to indicate that a SilKit::Services::Orchestration::SystemState has been received. Cf., AddSystemStateHandler(SystemStateHandler);

using ParticipantStatusHandler = std::function<void(const ParticipantStatus&)>

Callback type to indicate that a ParticipantStatus has been received. Cf., AddParticipantStatusHandler(ParticipantStatusHandler);

using ParticipantConnectedHandler = std::function<void(const ParticipantConnectionInformation &participantInformation)>

Callback type to indicate that a participant has been connected. Cf., SetParticipantConnectedHandler(ParticipantConnectedHandler);

using ParticipantDisconnectedHandler = std::function<void(const ParticipantConnectionInformation &participantInformation)>

Callback type to indicate that a participant has been disconnected. Cf., SetParticipantDisconnectedHandler(ParticipantDisconnectedHandler);

Public Functions

virtual auto AddSystemStateHandler(SystemStateHandler handler) -> HandlerId = 0

Register a callback for SilKit::Services::Orchestration::SystemState changes.

If the current system state is not SilKit::Services::Orchestration::SystemState::Invalid, the handler will be called immediately.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

virtual void RemoveSystemStateHandler(HandlerId handlerId) = 0

Remove a SystemStateHandler by SilKit::Util::HandlerId on this monitor.

Parameters

handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

virtual auto AddParticipantStatusHandler(ParticipantStatusHandler handler) -> HandlerId = 0

Register a callback for SilKit::Services::Orchestration::ParticipantStatus changes.

The handler will be called immediately for any participant that is not in SilKit::Services::Orchestration::ParticipantState::Invalid.

Returns

Returns a SilKit::Util::HandlerId that can be used to remove the callback.

virtual void RemoveParticipantStatusHandler(HandlerId handlerId) = 0

Remove a ParticipantStatusHandler by SilKit::Util::HandlerId on this monitor.

Parameters

handlerId – Identifier of the callback to be removed. Obtained upon adding to respective handler.

virtual auto SystemState() const -> Orchestration::SystemState = 0

Get the current SilKit::Services::Orchestration::SystemState.

virtual auto ParticipantStatus(const std::string &participantName) const -> const Orchestration::ParticipantStatus& = 0

Get the current ParticipantStatus of specific participant.

Parameters

participantName – The name of the participant for which the status is queried (UTF-8).

Throws

SilKit::SilKitError – If the participant name does not identify a participant that participates in synchronization.

virtual void SetParticipantConnectedHandler(ParticipantConnectedHandler handler) = 0

Set a callback for participants being connected.

Parameters

handler – The callback which overwrites any previously set callback

virtual void SetParticipantDisconnectedHandler(ParticipantDisconnectedHandler handler) = 0

Set a callback for participants being disconnected.

Parameters

handler – The callback which overwrites any previously set callback

virtual auto IsParticipantConnected(const std::string &participantName) const -> bool = 0

Check if a participant identified by the participantName is present.

Parameters

participantName – The name of the participant for which presence is queried (UTF-8).

Returns

true if the participant is present

Data Structures

struct ParticipantStatus

Details about a participant state change.

Public Members

std::string participantName

Name of the participant (UTF-8).

ParticipantState state = {ParticipantState::Invalid}

The new state of the participant.

std::string enterReason

The reason for the participant to enter the new state (UTF-8).

std::chrono::system_clock::time_point enterTime

The enter time of the participant.

std::chrono::system_clock::time_point refreshTime

The refresh time.

Enumerations and Typedefs

enum SilKit::Services::Orchestration::ParticipantState

Available participant states.

Values:

enumerator Invalid

An invalid participant state.

enumerator ServicesCreated

The controllers created state.

enumerator CommunicationInitializing

The communication initializing state.

enumerator CommunicationInitialized

The communication initialized state.

enumerator ReadyToRun

The initialized state.

enumerator Running

The running state.

enumerator Paused

The paused state.

enumerator Stopping

The stopping state.

enumerator Stopped

The stopped state.

enumerator Error

The error state.

enumerator ShuttingDown

The shutting down state.

enumerator Shutdown

The shutdown state.

enumerator Aborting

The aborting state.

enum SilKit::Services::Orchestration::SystemState

Available system states.

Values:

enumerator Invalid

An invalid participant state.

enumerator ServicesCreated

The controllers created state.

enumerator CommunicationInitializing

The communication initializing state.

enumerator CommunicationInitialized

The communication initialized state.

enumerator ReadyToRun

The initialized state.

enumerator Running

The running state.

enumerator Paused

The paused state.

enumerator Stopping

The stopping state.

enumerator Stopped

The stopped state.

enumerator Error

The error state.

enumerator ShuttingDown

The shutting down state.

enumerator Shutdown

The shutdown state.

enumerator Aborting

The aborting state.

Usage Example

This section contains a complete example that shows the use of the System Monitor and the order of callbacks in a complete state transition with two participants. Although the participants would typically reside in different processes, their interaction is shown sequentially to demonstrate cause and effect:

/* Copyright (c) 2022 Vector Informatik GmbH

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
// ------------------------------------------------------------
// Setup of the Participants
auto participant1 = SilKit::CreateParticipant(config, participantName1, registryUri);
auto participant2 = SilKit::CreateParticipant(config, participantName2, registryUri);

auto* systemMonitor = participant1->CreateSystemMonitor();

// Register ParticipantStatusHandler to receive ParticipantStatus transitions
auto participantStatusHandler =

This might lead to the following function call invocations at runtime:

auto participantStatusHandler =
    [](const ParticipantStatus& participantStatus) {};
systemMonitor->RegisterParticipantStatusHandler(participantStatusHandler);

// Register SystemStateHandler to receive SystemState transitions
auto systemStateHandler =
    [](SystemState state) {};
systemMonitor->RegisterSystemStateHandler(systemStateHandler);

// ------------------------------------------------------------
// Transition from Invalid to ServicesCreated.

// LifecycleService needs to call StartLifecycle for a transition to ParticipantState::ServicesCreated.
// For more information about the use of the life cycle service and time synchronization service refer to the corresponding section.
auto* lifecycleService1 = participant1 -> CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated});
auto* timeSyncService1 = lifecycleService1 -> CreateTimeSyncService();
auto* lifecycleService2 = participant2 -> CreateLifecycleService({SilKit::Services::Orchestration::OperationMode::Coordinated});
auto* timeSyncService2 = lifecycleService2 -> CreateTimeSyncService();

timeSyncService1->SetSimulationStepHandler(
    [](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) {}, 1ms
);
timeSyncService2->SetSimulationStepHandler(
  [](std::chrono::nanoseconds now, std::chrono::nanoseconds duration) {}, 1ms
);

lifecycleService1->StartLifecycle();

// The call of Run() leads to a participant state transition from Invalid to ServicesCreated
// and will trigger the callback of the ParticipantStatusHandler:
participantStatusHandler(participantStatus);
// with:
//  - participantStatus.participantName == participantName1
//  - participantStatus.state == ParticipantState::ServicesCreated
//  - participantStatus.reason = "LifecycleService::StartLifecycle was called"
//  - participantStatus.enterTime == enter time_point
//  - participantStatus.refreshTime == enter time_point

lifecycleService2->StartLifecycle();

// The call of Run() by the second participant again triggers
// the callback of the ParticipantStatusHandler:
participantStatusHandler(participantStatus);
// with:
//  - participantStatus.participantName == participantName2
//  - participantStatus.state == ParticipantState::ServicesCreated
//  - participantStatus.reason = "LifecycleService::StartLifecycle was called"
//  - participantStatus.enterTime == enter time_point
//  - participantStatus.refreshTime == enter time_point

// Since all participants are now in ParticipantState::ServicesCreated,
// the callback of the SystemStateHandler is triggered with SystemState::ServicesCreated:
systemStateHandler(state);