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
4 changes: 2 additions & 2 deletions score/mw/com/impl/bindings/lola/proxy_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ ProxyMethod::ProxyMethod(Proxy& proxy,
proxy.RegisterMethod(element_fq_id.element_id_, *this);
}

score::Result<score::cpp::span<std::byte>> ProxyMethod::AllocateInArgs(std::size_t queue_position)
score::Result<score::cpp::span<std::byte>> ProxyMethod::GetInArgsBuffer(std::size_t queue_position)
{
if (!is_subscribed_)
{
Expand All @@ -65,7 +65,7 @@ score::Result<score::cpp::span<std::byte>> ProxyMethod::AllocateInArgs(std::size
return GetInArgValuesElementStorage(queue_position, in_args_storage_.value(), type_erased_element_info_);
}

score::Result<score::cpp::span<std::byte>> ProxyMethod::AllocateReturnType(std::size_t queue_position)
score::Result<score::cpp::span<std::byte>> ProxyMethod::GetReturnValueBuffer(std::size_t queue_position)
{
if (!is_subscribed_)
{
Expand Down
4 changes: 2 additions & 2 deletions score/mw/com/impl/bindings/lola/proxy_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ class ProxyMethod : public ProxyMethodBinding
/// \brief Allocates storage for the in-arguments of a method call at the given queue position.
///
/// See ProxyMethodBinding for details
score::Result<score::cpp::span<std::byte>> AllocateInArgs(std::size_t queue_position) override;
score::Result<score::cpp::span<std::byte>> GetInArgsBuffer(std::size_t queue_position) override;

/// \brief Allocates storage for the return type of a method call at the given queue position.
///
/// See ProxyMethodBinding for details
score::Result<score::cpp::span<std::byte>> AllocateReturnType(std::size_t queue_position) override;
score::Result<score::cpp::span<std::byte>> GetReturnValueBuffer(std::size_t queue_position) override;

/// \brief Performs the actual method call at the given call-queue position.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ TEST_F(ProxyMethodHandlingFixture, SetsInArgsAndReturnStoragesForEachMethodInShm
// can allocate InArgs without crashing, since the allocation is using the inserted storages)
for (auto& method : proxy_method_storage_)
{
score::cpp::ignore = method.AllocateInArgs(0);
score::cpp::ignore = method.GetInArgsBuffer(0);
}
}

Expand Down
20 changes: 10 additions & 10 deletions score/mw/com/impl/bindings/lola/proxy_method_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ TEST_F(ProxyMethodAllocateInArgsFixture, CallingWithoutMarkingSubscribedReturnsE
unit_->SetInArgsAndReturnStorages(kValidInArgStorage, kEmptyReturnStorage);

// When calling AllocateInArgs
const auto result = unit_->AllocateInArgs(kDummyQueuePosition);
const auto result = unit_->GetInArgsBuffer(kDummyQueuePosition);

// Then an error is returned
EXPECT_FALSE(result.has_value());
Expand All @@ -167,7 +167,7 @@ TEST_F(ProxyMethodAllocateInArgsFixture, CallingAfterMarkingSubscribedThenUnsubs
unit_->SetInArgsAndReturnStorages(kValidInArgStorage, kEmptyReturnStorage);

// When calling AllocateInArgs
const auto result = unit_->AllocateInArgs(kDummyQueuePosition);
const auto result = unit_->GetInArgsBuffer(kDummyQueuePosition);

// Then an error is returned
EXPECT_FALSE(result.has_value());
Expand All @@ -182,7 +182,7 @@ TEST_F(ProxyMethodAllocateInArgsFixture, CallingAfterSettingValidStoragesWithVal
unit_->SetInArgsAndReturnStorages(kValidInArgStorage, kEmptyReturnStorage);

// When calling AllocateInArgs
const auto result = unit_->AllocateInArgs(kDummyQueuePosition);
const auto result = unit_->GetInArgsBuffer(kDummyQueuePosition);

// Then a valid result is returned
EXPECT_TRUE(result.has_value());
Expand All @@ -197,7 +197,7 @@ TEST_F(ProxyMethodAllocateInArgsFixture, CallingAfterSettingValidInArgsStorageWi

// When calling AllocateInArgs
// Then the program terminates
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore = unit_->AllocateInArgs(kDummyQueuePosition));
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore = unit_->GetInArgsBuffer(kDummyQueuePosition));
}

TEST_F(ProxyMethodAllocateInArgsFixture, CallingAfterSettingEmptyInArgsStorageWithInArgsTypeInfoTerminates)
Expand All @@ -209,7 +209,7 @@ TEST_F(ProxyMethodAllocateInArgsFixture, CallingAfterSettingEmptyInArgsStorageWi

// When calling AllocateInArgs
// Then the program terminates
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore = unit_->AllocateInArgs(kDummyQueuePosition));
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore = unit_->GetInArgsBuffer(kDummyQueuePosition));
}

using ProxyMethodAllocateReturnTypeFixture = ProxyMethodFixture;
Expand All @@ -222,7 +222,7 @@ TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingWithoutMarkingSubscribedRetu
unit_->SetInArgsAndReturnStorages(kEmptyInArgStorage, kValidReturnStorage);

// When calling AllocateReturnType
const auto result = unit_->AllocateReturnType(kDummyQueuePosition);
const auto result = unit_->GetReturnValueBuffer(kDummyQueuePosition);

// Then an error is returned
EXPECT_FALSE(result.has_value());
Expand All @@ -240,7 +240,7 @@ TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingAfterMarkingSubscribedThenUn
unit_->SetInArgsAndReturnStorages(kEmptyInArgStorage, kValidReturnStorage);

// When calling AllocateReturnType
const auto result = unit_->AllocateReturnType(kDummyQueuePosition);
const auto result = unit_->GetReturnValueBuffer(kDummyQueuePosition);

// Then an error is returned
EXPECT_FALSE(result.has_value());
Expand All @@ -255,7 +255,7 @@ TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingAfterSettingValidStoragesWit
unit_->SetInArgsAndReturnStorages(kEmptyInArgStorage, kValidReturnStorage);

// When calling AllocateReturnType
const auto result = unit_->AllocateReturnType(kDummyQueuePosition);
const auto result = unit_->GetReturnValueBuffer(kDummyQueuePosition);

// Then a valid result is returned
EXPECT_TRUE(result.has_value());
Expand All @@ -271,7 +271,7 @@ TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingAfterSettingValidReturnStora
// When calling AllocateReturnType
// Then the program terminates
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore =
unit_->AllocateReturnType(kDummyQueuePosition));
unit_->GetReturnValueBuffer(kDummyQueuePosition));
}

TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingAfterSettingEmptyReturnStorageWithReturnTypeInfoTerminates)
Expand All @@ -284,7 +284,7 @@ TEST_F(ProxyMethodAllocateReturnTypeFixture, CallingAfterSettingEmptyReturnStora
// When calling AllocateReturnType
// Then the program terminates
SCORE_LANGUAGE_FUTURECPP_EXPECT_CONTRACT_VIOLATED(score::cpp::ignore =
unit_->AllocateReturnType(kDummyQueuePosition));
unit_->GetReturnValueBuffer(kDummyQueuePosition));
}

using ProxyMethodDoCallFixture = ProxyMethodFixture;
Expand Down
12 changes: 6 additions & 6 deletions score/mw/com/impl/bindings/mock_binding/proxy_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class ProxyMethod : public ProxyMethodBinding
public:
~ProxyMethod() override = default;

MOCK_METHOD(score::Result<score::cpp::span<std::byte>>, AllocateInArgs, (std::size_t), (override));
MOCK_METHOD(score::Result<score::cpp::span<std::byte>>, AllocateReturnType, (std::size_t), (override));
MOCK_METHOD(score::Result<score::cpp::span<std::byte>>, GetInArgsBuffer, (std::size_t), (override));
MOCK_METHOD(score::Result<score::cpp::span<std::byte>>, GetReturnValueBuffer, (std::size_t), (override));
MOCK_METHOD(ResultBlank, DoCall, (std::size_t), (override));
};

Expand All @@ -38,14 +38,14 @@ class ProxyMethodFacade : public ProxyMethodBinding
ProxyMethodFacade(ProxyMethod& proxy_method) : ProxyMethodBinding{}, proxy_method_{proxy_method} {}
~ProxyMethodFacade() override = default;

score::Result<score::cpp::span<std::byte>> AllocateInArgs(std::size_t queue_position) override
score::Result<score::cpp::span<std::byte>> GetInArgsBuffer(std::size_t queue_position) override
{
return proxy_method_.AllocateInArgs(queue_position);
return proxy_method_.GetInArgsBuffer(queue_position);
}

score::Result<score::cpp::span<std::byte>> AllocateReturnType(std::size_t queue_position) override
score::Result<score::cpp::span<std::byte>> GetReturnValueBuffer(std::size_t queue_position) override
{
return proxy_method_.AllocateReturnType(queue_position);
return proxy_method_.GetReturnValueBuffer(queue_position);
}

score::ResultBlank DoCall(std::size_t queue_position) override
Expand Down
48 changes: 47 additions & 1 deletion score/mw/com/impl/methods/proxy_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ score::Result<std::tuple<impl::MethodInArgPtr<ArgTypes>...>> AllocateImpl(
return Unexpected(available_queue_slot.error());
}
const std::size_t queue_index = available_queue_slot.value();
auto allocated_in_args_storage = binding.AllocateInArgs(queue_index);
auto allocated_in_args_storage = binding.GetInArgsBuffer(queue_index);
if (!allocated_in_args_storage.has_value())
{
return Unexpected(allocated_in_args_storage.error());
Expand All @@ -146,6 +146,52 @@ score::Result<std::tuple<impl::MethodInArgPtr<ArgTypes>...>> AllocateImpl(
std::move(method_in_arg_ptr_tuple));
}

/// \brief Initializes all InArgs by calling the default constructor for each argument.
///
/// This step is important to avoid undefined behaviour (interpreting uninitialized memory) and also to ensure that any
/// non-trivially constructible types are properly initialized.
template <typename... ArgTypes>
ResultBlank InitializeInArgs(ProxyMethodBinding& binding, const std::size_t queue_size)
{
for (std::size_t queue_index = 0U; queue_index < queue_size; ++queue_index)
{
auto allocated_in_args_storage = binding.GetInArgsBuffer(queue_index);
if (!allocated_in_args_storage.has_value())
{
return Unexpected(allocated_in_args_storage.error());
}
const auto deserialized_arg_pointers = impl::Deserialize<ArgTypes...>(allocated_in_args_storage.value());

// std::apply takes a callable and a tuple. It calls the callable with the arguments from the unpacked tuple.
// E.g. In this case, it will call the lambda, fn, with: `fn(get<0>(args), get<1>(args), ..., get<n>(args))`
std::apply(
[](typename std::add_pointer<ArgTypes>::type... arg_pointers) {
((score::cpp::ignore = new (arg_pointers) ArgTypes{}), ...);
},
deserialized_arg_pointers);
}
return {};
}

/// \brief Initializes all Return values by calling the default constructor for each argument.
///
/// This step is important to avoid undefined behaviour (interpreting uninitialized memory) and also to ensure that any
/// non-trivially constructible types are properly initialized.
template <typename ReturnType>
ResultBlank InitializeReturnValue(ProxyMethodBinding& binding, const std::size_t queue_size)
{
for (std::size_t queue_index = 0U; queue_index < queue_size; ++queue_index)
{
auto allocated_return_value_storage = binding.GetReturnValueBuffer(queue_index);
if (!allocated_return_value_storage.has_value())
{
return Unexpected(allocated_return_value_storage.error());
}
score::cpp::ignore = new (allocated_return_value_storage->data()) ReturnType{};
}
return {};
}

/// \brief Checks, that all MethodInArgPtr arguments have the same queue_position_ and returns this common value.
/// \details Will assert/terminate, if the queue_position_ values differ.
/// \tparam MethodInArgPtrs Variadic template parameter pack for MethodInArgPtr types.
Expand Down
11 changes: 11 additions & 0 deletions score/mw/com/impl/methods/proxy_method_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ class ProxyMethodBase
proxy_base_ = proxy_base;
}

/// \brief Default initializes each method InArg and Return value (if they exist)
///
/// This function is called on creation of a Proxy during ProxyBase::SetupMethods. Since the binding creates a type
/// erased buffer in which the InArgs and Return value are created, each value must be explicitly instantiated to
/// begin the object lifetime and also perform the correct initialization (in case the type cannot be trivially
/// default constructed). We do this once on startup instead of in a call to Allocate() to prevent the type being
/// reinitialized on every method call. This potentially would have performance benefits but more importantly this
/// allows us to support "semi-dynamic" types in which a type dynamically allocates once on construction and the
/// constructor is then never called again.
virtual ResultBlank InitializeInArgsAndReturnValues() = 0;

protected:
/// \brief Size of the call-queue is currently fixed to 1! As soon as we are going to support larger call-queues,
/// the call-queue-size shall be taken from configuration and handed over to ProxyMethod ctor.
Expand Down
4 changes: 2 additions & 2 deletions score/mw/com/impl/methods/proxy_method_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ class ProxyMethodBinding
/// \return span of bytes representing the allocated storage or an error.
/// \note If the method has no in-arguments (i.e. in_args_type_erased_info_ is a std::nullopt), this method shall
/// not be called.
virtual score::Result<score::cpp::span<std::byte>> AllocateInArgs(std::size_t queue_position) = 0;
virtual score::Result<score::cpp::span<std::byte>> GetInArgsBuffer(std::size_t queue_position) = 0;

/// \brief Allocates storage for the return type of a method call at the given queue position.
/// \param queue_position The call-queue position for which to allocate the return type storage.
/// \return span of bytes representing the allocated storage or an error.
/// \note If the method has no return type (i.e. void, thus return_type_type_erased_info_ is a std::nullopt), this
/// method shall not be called.
virtual score::Result<score::cpp::span<std::byte>> AllocateReturnType(std::size_t queue_position) = 0;
virtual score::Result<score::cpp::span<std::byte>> GetReturnValueBuffer(std::size_t queue_position) = 0;

/// \brief Performs the actual method call at the given call-queue position.
/// \details The in-arguments and return type storage must have been allocated before calling this method. The
Expand Down
Loading
Loading