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
18 changes: 18 additions & 0 deletions score/mw/com/impl/bindings/lola/messaging/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ cc_library(
"i_message_passing_service.cpp",
"method_call_registration_guard.cpp",
"method_subscription_registration_guard.cpp",
"method_unsubscription_registration_guard.cpp",
],
hdrs = [
"i_message_passing_service.h",
"method_call_registration_guard.h",
"method_subscription_registration_guard.h",
"method_unsubscription_registration_guard.h",
],
features = COMPILER_WARNING_FEATURES,
implementation_deps = [
Expand Down Expand Up @@ -370,6 +372,21 @@ cc_gtest_unit_test(
],
)

cc_gtest_unit_test(
name = "method_unsubscription_registration_guard_test",
srcs = ["method_unsubscription_registration_guard_test.cpp"],
features = COMPILER_WARNING_FEATURES,
visibility = [
"//score/mw/com/impl:__subpackages__",
],
deps = [
":i_message_passing_service",
":message_passing_service_mock",
"@score_baselibs//score/mw/log:recorder_mock",
"@score_baselibs//score/scope_exit",
],
)

cc_gtest_unit_test(
name = "method_call_registration_guard_test",
srcs = ["method_call_registration_guard_test.cpp"],
Expand Down Expand Up @@ -412,6 +429,7 @@ cc_unit_test_suites_for_host_and_qnx(
":message_passing_service_test",
":mw_log_logger_test",
":method_subscription_registration_guard_test",
":method_unsubscription_registration_guard_test",
":method_call_registration_guard_test",
],
visibility = ["//score/mw/com/impl/bindings/lola:__pkg__"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "score/mw/com/impl/bindings/lola/element_fq_id.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_call_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_subscription_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_unsubscription_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/methods/proxy_method_instance_identifier.h"
#include "score/mw/com/impl/bindings/lola/proxy_instance_identifier.h"
#include "score/mw/com/impl/bindings/lola/skeleton_instance_identifier.h"
Expand Down Expand Up @@ -47,6 +48,7 @@ class IMessagePassingService
{
friend class MethodSubscriptionRegistrationGuardFactory;
friend class MethodCallRegistrationGuardFactory;
friend class MethodUnsubscriptionRegistrationGuardFactory;

public:
using HandlerRegistrationNoType = std::uint32_t;
Expand Down Expand Up @@ -86,6 +88,17 @@ class IMessagePassingService
using ServiceMethodSubscribedHandler = safecpp::CopyableScopedFunction<
score::Result<void>(ProxyInstanceIdentifier proxy_instance_identifier, uid_t proxy_uid, pid_t proxy_pid)>;

/// \brief Handler which will be called when the proxy process sends a message that it has unsubscribed from a
/// service method.
///
/// When a Proxy is destroyed, it will call UnsubscribeServiceMethod which will send a message to the Skeleton
/// process. The Skeleton process will then call the ServiceMethodUnsubscribedHandler to close the proxy's shared
/// memory region and unregister the method call handler corresponding to the proxy's ProxyMethodInstanceIdentifier
/// from each SkeletonMethod.
///
using ServiceMethodUnsubscribedHandler =
safecpp::CopyableScopedFunction<score::ResultBlank(ProxyInstanceIdentifier proxy_instance_identifier)>;

/// \brief Handler which will be called when the proxy process sends a message that it has called a method.
///
/// This will be triggered when the Proxy process calls CallMethod.
Expand Down Expand Up @@ -197,6 +210,24 @@ class IMessagePassingService
ServiceMethodSubscribedHandler subscribed_callback,
AllowedConsumerUids allowed_proxy_uids) = 0;

/// \brief Register a handler on Skeleton side which will be called when UnsubscribeServiceMethod is called by a
/// Proxy.
///
/// When a Proxy is destroyed, it will call UnsubscribeServiceMethod. When this message is received in the
/// Skeleton process, the handler registered in this function will be called.
///
/// The handler is scoped to on_service_method_subscribed_handler_scope_ on the Skeleton side, so that it is
/// not called after the Skeleton has started its StopOffer sequence. This is our synchronisation point.
///
/// \param asil_level ASIL level of method.
/// \param skeleton_instance_identifier to identify which ServiceMethodUnsubscribedHandler to call when
/// UnsubscribeServiceMethod is called on the Proxy side
/// \param unsubscribed_callback callback that will be called when UnsubscribeServiceMethod is called
virtual Result<MethodUnsubscriptionRegistrationGuard> RegisterOnServiceMethodUnsubscribedHandler(
const QualityType asil_level,
const SkeletonInstanceIdentifier skeleton_instance_identifier,
ServiceMethodUnsubscribedHandler unsubscribed_callback) = 0;

/// \brief Register a handler on Skeleton side which will be called when CallMethod is called by a ProxyMethod.
///
/// When a user calls a method on a ProxyMethod, it will put the InArgs in shared memory (if there are any) and then
Expand Down Expand Up @@ -283,6 +314,21 @@ class IMessagePassingService
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) = 0;

/// \brief Best-effort call made by a Proxy on destruction to notify the Skeleton that the proxy is being
/// destroyed so that the Skeleton can clean up the proxy's shared memory region.
///
/// This mirrors SubscribeServiceMethod. If this call fails, some resources will be leaked on the Skeleton side
/// but will be cleaned up when the Proxy process restarts and the Skeleton detects the PID change.
///
/// \param asil_level ASIL level of method.
/// \param skeleton_instance_identifier identification of the Skeleton corresponding to the Proxy.
/// \param proxy_instance_identifier identification of the Proxy which is being destroyed.
/// \param target_node_id PID of the Skeleton process which the unsubscribe call is sent to.
virtual ResultBlank UnsubscribeServiceMethod(const QualityType asil_level,
const SkeletonInstanceIdentifier& skeleton_instance_identifier,
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) = 0;

/// \brief Blocking call which is called on Proxy side to trigger the Skeleton to process a method call. The
/// callback registered with RegisterOnServiceMethodSubscribed will be called on the Skeleton side and a response
/// will be returned
Expand Down Expand Up @@ -330,6 +376,19 @@ class IMessagePassingService
/// \param proxy_method_instance_identifier to identify which registered MethodCallHandler to unregister
virtual void UnregisterMethodCallHandler(const QualityType asil_level,
ProxyMethodInstanceIdentifier proxy_method_instance_identifier) = 0;

/// \brief Unregister handler that was registered with RegisterOnServiceMethodUnsubscribedHandler
///
/// This function is private and will only be called by MethodUnsubscriptionRegistrationGuardFactory on
/// destruction.
///
/// \pre Shall only be called after RegisterOnServiceMethodUnsubscribedHandler was successfully called.
///
/// \param asil_level ASIL level of method.
/// \param skeleton_instance_identifier to identify which registered ServiceMethodUnsubscribedHandler to unregister
virtual void UnregisterOnServiceMethodUnsubscribedHandler(
const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier) = 0;
};

} // namespace score::mw::com::impl::lola
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,20 @@ class IMessagePassingServiceInstance
IMessagePassingService::ServiceMethodSubscribedHandler subscribed_callback,
IMessagePassingService::AllowedConsumerUids allowed_proxy_uids) = 0;

virtual ResultBlank RegisterOnServiceMethodUnsubscribedHandler(
const SkeletonInstanceIdentifier skeleton_instance_identifier,
IMessagePassingService::ServiceMethodUnsubscribedHandler unsubscribed_callback) = 0;

virtual Result<void> RegisterMethodCallHandler(const ProxyMethodInstanceIdentifier proxy_method_instance_identifier,
IMessagePassingService::MethodCallHandler method_call_callback,
const uid_t allowed_proxy_uid) = 0;

virtual void UnregisterOnServiceMethodSubscribedHandler(
SkeletonInstanceIdentifier skeleton_instance_identifier) = 0;

virtual void UnregisterOnServiceMethodUnsubscribedHandler(
SkeletonInstanceIdentifier skeleton_instance_identifier) = 0;

virtual void UnregisterMethodCallHandler(ProxyMethodInstanceIdentifier proxy_method_instance_identifier) = 0;

virtual void NotifyOutdatedNodeId(const pid_t outdated_node_id, const pid_t target_node_id) noexcept = 0;
Expand All @@ -75,6 +82,10 @@ class IMessagePassingServiceInstance
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) = 0;

virtual ResultBlank UnsubscribeServiceMethod(const SkeletonInstanceIdentifier& skeleton_instance_identifier,
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) = 0;

virtual Result<void> CallMethod(const ProxyMethodInstanceIdentifier& proxy_method_instance_identifier,
const std::size_t queue_position,
const pid_t target_node_id) = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "score/mw/com/impl/bindings/lola/messaging/message_passing_service_instance_factory.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_call_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_subscription_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_unsubscription_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/messaging/mw_log_logger.h"
#include "score/mw/com/impl/bindings/lola/messaging/thread_abstraction.h"

Expand Down Expand Up @@ -164,6 +165,23 @@ Result<MethodSubscriptionRegistrationGuard> MessagePassingService::RegisterOnSer
*this, asil_level, skeleton_instance_identifier, registration_guards_scope_);
}

Result<MethodUnsubscriptionRegistrationGuard> MessagePassingService::RegisterOnServiceMethodUnsubscribedHandler(
const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier,
ServiceMethodUnsubscribedHandler unsubscribed_callback)
{
auto& instance = GetMessagePassingServiceInstance(asil_level);

const auto result = instance.RegisterOnServiceMethodUnsubscribedHandler(skeleton_instance_identifier,
std::move(unsubscribed_callback));
if (!(result.has_value()))
{
return MakeUnexpected<MethodUnsubscriptionRegistrationGuard>(result.error());
}
return MethodUnsubscriptionRegistrationGuardFactory::Create(
*this, asil_level, skeleton_instance_identifier, registration_guards_scope_);
}

Result<MethodCallRegistrationGuard> MessagePassingService::RegisterMethodCallHandler(
const QualityType asil_level,
ProxyMethodInstanceIdentifier proxy_method_instance_identifier,
Expand Down Expand Up @@ -211,6 +229,17 @@ Result<void> MessagePassingService::SubscribeServiceMethod(
return instance.SubscribeServiceMethod(skeleton_instance_identifier, proxy_instance_identifier, target_node_id);
}

ResultBlank MessagePassingService::UnsubscribeServiceMethod(
const QualityType asil_level,
const SkeletonInstanceIdentifier& skeleton_instance_identifier,
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id)
{
auto& instance = GetMessagePassingServiceInstance(asil_level);

return instance.UnsubscribeServiceMethod(skeleton_instance_identifier, proxy_instance_identifier, target_node_id);
}

Result<void> MessagePassingService::CallMethod(const QualityType asil_level,
const ProxyMethodInstanceIdentifier& proxy_method_instance_identifier,
std::size_t queue_position,
Expand All @@ -230,6 +259,15 @@ void MessagePassingService::UnregisterOnServiceMethodSubscribedHandler(
instance.UnregisterOnServiceMethodSubscribedHandler(skeleton_instance_identifier);
}

void MessagePassingService::UnregisterOnServiceMethodUnsubscribedHandler(
const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier)
{
auto& instance = GetMessagePassingServiceInstance(asil_level);

instance.UnregisterOnServiceMethodUnsubscribedHandler(skeleton_instance_identifier);
}

void MessagePassingService::UnregisterMethodCallHandler(const QualityType asil_level,
ProxyMethodInstanceIdentifier proxy_method_instance_identifier)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "score/mw/com/impl/bindings/lola/messaging/i_message_passing_service_instance.h"
#include "score/mw/com/impl/bindings/lola/messaging/i_message_passing_service_instance_factory.h"
#include "score/mw/com/impl/bindings/lola/messaging/message_passing_service_instance.h"
#include "score/mw/com/impl/bindings/lola/messaging/method_unsubscription_registration_guard.h"
#include "score/mw/com/impl/bindings/lola/proxy_instance_identifier.h"
#include "score/mw/com/impl/bindings/lola/skeleton_instance_identifier.h"
#include "score/mw/com/impl/configuration/global_configuration.h"
Expand Down Expand Up @@ -108,6 +109,14 @@ class MessagePassingService final : public IMessagePassingService
ServiceMethodSubscribedHandler subscribed_callback,
AllowedConsumerUids allowed_proxy_uids) override;

/// \brief Register a handler on Skeleton side which will be called when UnsubscribeServiceMethod is called by a
/// Proxy.
/// \details see IMessagePassingService::RegisterOnServiceMethodUnsubscribedHandler
Result<MethodUnsubscriptionRegistrationGuard> RegisterOnServiceMethodUnsubscribedHandler(
const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier,
ServiceMethodUnsubscribedHandler unsubscribed_callback) override;

/// \brief Register a handler on Skeleton side which will be called when CallMethod is called by a Proxy.
/// \details see IMessagePassingService::RegisterMethodCallHandler
Result<MethodSubscriptionRegistrationGuard> RegisterMethodCallHandler(
Expand Down Expand Up @@ -144,6 +153,14 @@ class MessagePassingService final : public IMessagePassingService
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) override;

/// \brief Best-effort call made by a Proxy on destruction to notify the Skeleton that the proxy is being
/// destroyed.
/// \details see IMessagePassingService::UnsubscribeServiceMethod
ResultBlank UnsubscribeServiceMethod(const QualityType asil_level,
const SkeletonInstanceIdentifier& skeleton_instance_identifier,
const ProxyInstanceIdentifier& proxy_instance_identifier,
const pid_t target_node_id) override;

/// \brief Blocking call which is called on Proxy side to trigger the Skeleton to process a method call. The
/// callback registered with RegisterOnServiceMethodSubscribed will be called on the Skeleton side and a response
/// will be returned.
Expand All @@ -161,6 +178,9 @@ class MessagePassingService final : public IMessagePassingService
void UnregisterOnServiceMethodSubscribedHandler(const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier) override;

void UnregisterOnServiceMethodUnsubscribedHandler(const QualityType asil_level,
SkeletonInstanceIdentifier skeleton_instance_identifier) override;

void UnregisterMethodCallHandler(const QualityType asil_level,
ProxyMethodInstanceIdentifier proxy_method_instance_identifier) override;

Expand Down
Loading