Skip to content

Commit

Permalink
Merge pull request #665 from ApexAI/iox-#14-adjust-untyped-user-heade…
Browse files Browse the repository at this point in the history
…r-API

Iox #14 adjust untyped user header api
  • Loading branch information
elBoberido authored Apr 1, 2021
2 parents a7bc3a0 + 6b9f226 commit 79db27b
Show file tree
Hide file tree
Showing 22 changed files with 172 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ struct cpp2c_Publisher
cpp2c_Publisher& operator=(cpp2c_Publisher&& rhs) noexcept;

iox::popo::PublisherPortData* m_portData{nullptr};
uint32_t m_userHeaderSize{iox::CHUNK_NO_USER_HEADER_SIZE};
uint32_t m_userHeaderAlignment{iox::CHUNK_NO_USER_HEADER_ALIGNMENT};
};

#endif
25 changes: 17 additions & 8 deletions iceoryx_binding_c/include/iceoryx_binding_c/publisher.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ typedef struct
/// @brief The option whether the publisher should already be offered when creating it
bool offerOnCreate;

/// @brief The size of the user-header
/// @note must be a multiple of the alignment and is by default is 0 to indicate that no user-header is used
uint32_t userHeaderSize;

/// @brief The alignment of the user-header
/// @note must be a power of two and the maximum allowed user-header alignment is 8
uint32_t userHeaderAlignment;

/// @brief this value will be set exclusively by `iox_pub_options_init` and is not supposed to be modified otherwise
uint64_t initCheck;
} iox_pub_options_t;
Expand Down Expand Up @@ -106,6 +98,23 @@ ENUM iox_AllocationResult iox_pub_loan_aligned_chunk(iox_pub_t const self,
const uint32_t userPayloadSize,
const uint32_t userPayloadAlignment);

/// @brief allocates a chunk in the shared memory with a section for the user-header and a custom alignment for the
/// user-payload
/// @param[in] self handle of the publisher
/// @param[in] userPayloadOfChunk pointer in which a pointer to the user-payload of the allocated chunk is stored
/// @param[in] userPayloadSize user-payload size of the allocated chunk
/// @param[in] userPayloadAlignment user-payload alignment of the allocated chunk
/// @param[in] userHeaderSize user-header size of the allocated chunk
/// @param[in] userHeaderAlignment user-header alignment of the allocated chunk
/// @return on success it returns AllocationResult_SUCCESS otherwise a value which
/// describes the error
ENUM iox_AllocationResult iox_pub_loan_aligned_chunk_with_user_header(iox_pub_t const self,
void** const userPayloadOfChunk,
const uint32_t userPayloadSize,
const uint32_t userPayloadAlignment,
const uint32_t userHeaderSize,
const uint32_t userHeaderAlignment);

/// @brief releases ownership of a previously allocated chunk without sending it
/// @param[in] self handle of the publisher
/// @param[in] userPayloadOfChunk pointer to the user-payload of the chunk which should be free'd
Expand Down
4 changes: 2 additions & 2 deletions iceoryx_binding_c/source/c_chunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ const void* iox_chunk_header_to_user_payload_const(const iox_chunk_header_t* con

void* iox_chunk_header_to_user_header(iox_chunk_header_t* const chunkHeader)
{
return reinterpret_cast<ChunkHeader*>(chunkHeader)->userHeader<void>();
return reinterpret_cast<ChunkHeader*>(chunkHeader)->userHeader();
}

const void* iox_chunk_header_to_user_header_const(const iox_chunk_header_t* const chunkHeader)
{
return reinterpret_cast<const ChunkHeader*>(chunkHeader)->userHeader<void>();
return reinterpret_cast<const ChunkHeader*>(chunkHeader)->userHeader();
}

iox_chunk_header_t* iox_chunk_header_from_user_payload(void* const userPayload)
Expand Down
34 changes: 22 additions & 12 deletions iceoryx_binding_c/source/c_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ void iox_pub_options_init(iox_pub_options_t* options)
options->historyCapacity = publisherOptions.historyCapacity;
options->nodeName = nullptr;
options->offerOnCreate = publisherOptions.offerOnCreate;
options->userHeaderSize = IOX_C_CHUNK_NO_USER_HEADER_SIZE;
options->userHeaderAlignment = IOX_C_CHUNK_NO_USER_HEADER_ALIGNMENT;

options->initCheck = PUBLISHER_OPTIONS_INIT_CHECK_CONSTANT;
}
Expand All @@ -72,9 +70,6 @@ iox_pub_t iox_pub_init(iox_pub_storage_t* self,
new (self) cpp2c_Publisher();
iox_pub_t me = reinterpret_cast<iox_pub_t>(self);

me->m_userHeaderSize = IOX_C_CHUNK_NO_USER_HEADER_SIZE,
me->m_userHeaderAlignment = IOX_C_CHUNK_NO_USER_HEADER_ALIGNMENT;

PublisherOptions publisherOptions;

// use default options otherwise
Expand All @@ -93,9 +88,6 @@ iox_pub_t iox_pub_init(iox_pub_storage_t* self,
publisherOptions.nodeName = NodeName_t(TruncateToCapacity, options->nodeName);
}
publisherOptions.offerOnCreate = options->offerOnCreate;

me->m_userHeaderSize = options->userHeaderSize;
me->m_userHeaderAlignment = options->userHeaderAlignment;
}

me->m_portData = PoshRuntime::getInstance().getMiddlewarePublisher(
Expand All @@ -117,18 +109,36 @@ void iox_pub_deinit(iox_pub_t const self)
iox_AllocationResult
iox_pub_loan_chunk(iox_pub_t const self, void** const userPayloadOfChunk, const uint32_t userPayloadSize)
{
return iox_pub_loan_aligned_chunk(
self, userPayloadOfChunk, userPayloadSize, IOX_C_CHUNK_DEFAULT_USER_PAYLOAD_ALIGNMENT);
return iox_pub_loan_aligned_chunk_with_user_header(self,
userPayloadOfChunk,
userPayloadSize,
IOX_C_CHUNK_DEFAULT_USER_PAYLOAD_ALIGNMENT,
IOX_C_CHUNK_NO_USER_HEADER_SIZE,
IOX_C_CHUNK_NO_USER_HEADER_ALIGNMENT);
}

iox_AllocationResult iox_pub_loan_aligned_chunk(iox_pub_t const self,
void** const userPayloadOfChunk,
const uint32_t userPayloadSize,
const uint32_t userPayloadAlignment)
{
return iox_pub_loan_aligned_chunk_with_user_header(self,
userPayloadOfChunk,
userPayloadSize,
userPayloadAlignment,
IOX_C_CHUNK_NO_USER_HEADER_SIZE,
IOX_C_CHUNK_NO_USER_HEADER_ALIGNMENT);
}

iox_AllocationResult iox_pub_loan_aligned_chunk_with_user_header(iox_pub_t const self,
void** const userPayloadOfChunk,
const uint32_t userPayloadSize,
const uint32_t userPayloadAlignment,
const uint32_t userHeaderSize,
const uint32_t userHeaderAlignment)
{
auto result = PublisherPortUser(self->m_portData)
.tryAllocateChunk(
userPayloadSize, userPayloadAlignment, self->m_userHeaderSize, self->m_userHeaderAlignment)
.tryAllocateChunk(userPayloadSize, userPayloadAlignment, userHeaderSize, userHeaderAlignment)
.and_then([&userPayloadOfChunk](ChunkHeader* h) { *userPayloadOfChunk = h->userPayload(); });
if (result.has_error())
{
Expand Down
34 changes: 20 additions & 14 deletions iceoryx_binding_c/test/moduletests/test_chunk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,18 @@ TEST_F(Chunk_test, UserPayloadChunkHeaderUserPayloadRoundtripWorksForConst)

TEST_F(Chunk_test, GettingUserHeaderFromNonConstChunkHeaderWorks)
{
iox_pub_options_t options;
iox_pub_options_init(&options);
options.userHeaderSize = 64U;
options.userHeaderAlignment = 8U;
iox_pub_t publisherWithUserHeader = iox_pub_init(&publisherStorage, "All", "Glory", "Hypnotoad", nullptr);

constexpr uint32_t USER_PAYLOAD_SIZE(42U);
constexpr uint32_t USER_PAYLOAD_ALIGNMENT(64U);
constexpr uint32_t USER_HEADER_SIZE = 16U;
constexpr uint32_t USER_HEADER_ALIGNMENT = 8U;
void* userPayload{nullptr};
ASSERT_EQ(iox_pub_loan_chunk(publisherWithUserHeader, &userPayload, USER_PAYLOAD_SIZE), AllocationResult_SUCCESS);
ASSERT_EQ(iox_pub_loan_aligned_chunk_with_user_header(publisher,
&userPayload,
USER_PAYLOAD_SIZE,
USER_PAYLOAD_ALIGNMENT,
USER_HEADER_SIZE,
USER_HEADER_ALIGNMENT),
AllocationResult_SUCCESS);

auto chunkHeader = iox_chunk_header_from_user_payload(userPayload);

Expand All @@ -126,15 +129,18 @@ TEST_F(Chunk_test, GettingUserHeaderFromNonConstChunkHeaderWorks)

TEST_F(Chunk_test, GettingUserHeaderFromConstChunkHeaderWorks)
{
iox_pub_options_t options;
iox_pub_options_init(&options);
options.userHeaderSize = 64U;
options.userHeaderAlignment = 8U;
iox_pub_t publisherWithUserHeader = iox_pub_init(&publisherStorage, "All", "Glory", "Hypnotoad", nullptr);

constexpr uint32_t USER_PAYLOAD_SIZE(42U);
constexpr uint32_t USER_PAYLOAD_ALIGNMENT(64U);
constexpr uint32_t USER_HEADER_SIZE = 16U;
constexpr uint32_t USER_HEADER_ALIGNMENT = 8U;
void* userPayload{nullptr};
ASSERT_EQ(iox_pub_loan_chunk(publisherWithUserHeader, &userPayload, USER_PAYLOAD_SIZE), AllocationResult_SUCCESS);
ASSERT_EQ(iox_pub_loan_aligned_chunk_with_user_header(publisher,
&userPayload,
USER_PAYLOAD_SIZE,
USER_PAYLOAD_ALIGNMENT,
USER_HEADER_SIZE,
USER_HEADER_ALIGNMENT),
AllocationResult_SUCCESS);

const iox_chunk_header_t* chunkHeader = iox_chunk_header_from_user_payload(userPayload);

Expand Down
65 changes: 21 additions & 44 deletions iceoryx_binding_c/test/moduletests/test_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,66 +196,43 @@ TEST_F(iox_pub_test, allocateChunkForOneChunkIsSuccessful)
EXPECT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(&m_sut, &chunk, sizeof(DummySample)));
}

TEST_F(iox_pub_test, allocateChunkWithUserHeaderIsSuccessful)
TEST_F(iox_pub_test, allocateChunkUserPayloadAlignmentIsSuccessful)
{
// the user header options are stored in the publisher itself with iox_pub_init and therefore the the
// RouDiEnvironment is needed

iox::roudi::RouDiEnvironment roudiEnv;

iox_runtime_init("hypnotoad");

iox_pub_options_t options;
iox_pub_options_init(&options);
options.userHeaderSize = 4U;
options.userHeaderAlignment = 2U;
iox_pub_storage_t storage;

auto sut = iox_pub_init(&storage, "a", "b", "c", &options);

constexpr uint32_t USER_PAYLOAD_ALIGNMENT{128U};
void* chunk = nullptr;
ASSERT_EQ(AllocationResult_SUCCESS, iox_pub_loan_chunk(sut, &chunk, sizeof(DummySample)));
ASSERT_EQ(AllocationResult_SUCCESS,
iox_pub_loan_aligned_chunk(&m_sut, &chunk, sizeof(DummySample), USER_PAYLOAD_ALIGNMENT));

auto chunkHeader = iox_chunk_header_from_user_payload(chunk);
auto spaceBetweenChunkHeaderAndUserPaylod =
reinterpret_cast<uint64_t>(chunk) - reinterpret_cast<uint64_t>(chunkHeader);
EXPECT_GT(spaceBetweenChunkHeaderAndUserPaylod, sizeof(iox::mepoo::ChunkHeader));
EXPECT_TRUE(reinterpret_cast<uint64_t>(chunk) % USER_PAYLOAD_ALIGNMENT == 0U);
}

TEST_F(iox_pub_test, allocateChunkWithUserHeaderAndUserPayloadAlignmentIsSuccessful)
TEST_F(iox_pub_test, allocateChunkWithUserHeaderIsSuccessful)
{
// the user header options are stored in the publisher itself with iox_pub_init and therefore the the
// RouDiEnvironment is needed

iox::roudi::RouDiEnvironment roudiEnv;

iox_runtime_init("hypnotoad");

iox_pub_options_t options;
iox_pub_options_init(&options);
options.userHeaderSize = 4U;
options.userHeaderAlignment = 2U;
iox_pub_storage_t storage;

auto sut = iox_pub_init(&storage, "a", "b", "c", &options);
constexpr uint32_t USER_HEADER_SIZE = 4U;
constexpr uint32_t USER_HEADER_ALIGNMENT = 2U;

constexpr uint32_t USER_PAYLOAD_ALIGNMENT{128U};
void* chunk = nullptr;
ASSERT_EQ(AllocationResult_SUCCESS,
iox_pub_loan_aligned_chunk(sut, &chunk, sizeof(DummySample), USER_PAYLOAD_ALIGNMENT));
iox_pub_loan_aligned_chunk_with_user_header(
&m_sut, &chunk, sizeof(DummySample), alignof(DummySample), USER_HEADER_SIZE, USER_HEADER_ALIGNMENT));

EXPECT_TRUE(reinterpret_cast<uint64_t>(chunk) % USER_PAYLOAD_ALIGNMENT == 0U);
auto chunkHeader = iox_chunk_header_from_user_payload(chunk);
auto spaceBetweenChunkHeaderAndUserPaylod =
reinterpret_cast<uint64_t>(chunk) - reinterpret_cast<uint64_t>(chunkHeader);
EXPECT_GT(spaceBetweenChunkHeaderAndUserPaylod, sizeof(iox::mepoo::ChunkHeader));
}

TEST_F(iox_pub_test, allocateChunkWithUserHeaderAndUserPayloadAlignmentFails)
{
m_sut.m_userHeaderSize = 4U;
m_sut.m_userHeaderAlignment = 3U;

constexpr uint32_t USER_PAYLOAD_ALIGNMENT{128U};
constexpr uint32_t USER_HEADER_SIZE = 4U;
constexpr uint32_t USER_HEADER_ALIGNMENT = 3U;

void* chunk = nullptr;
ASSERT_EQ(AllocationResult_INVALID_PARAMETER_FOR_USER_PAYLOAD_OR_USER_HEADER,
iox_pub_loan_aligned_chunk(&m_sut, &chunk, sizeof(DummySample), USER_PAYLOAD_ALIGNMENT));
ASSERT_EQ(
AllocationResult_INVALID_PARAMETER_FOR_USER_PAYLOAD_OR_USER_HEADER,
iox_pub_loan_aligned_chunk_with_user_header(
&m_sut, &chunk, sizeof(DummySample), USER_PAYLOAD_ALIGNMENT, USER_HEADER_SIZE, USER_HEADER_ALIGNMENT));
}

TEST_F(iox_pub_test, chunkHeaderCanBeObtainedFromChunk)
Expand Down
37 changes: 0 additions & 37 deletions iceoryx_posh/include/iceoryx_posh/internal/mepoo/chunk_header.inl

This file was deleted.

20 changes: 10 additions & 10 deletions iceoryx_posh/include/iceoryx_posh/internal/popo/publisher.inl
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,23 @@ namespace iox
namespace popo
{
template <typename T, typename H, typename BasePublisher_t>
inline Publisher<T, H, BasePublisher_t>::Publisher(const capro::ServiceDescription& service,
const PublisherOptions& publisherOptions)
inline PublisherImpl<T, H, BasePublisher_t>::PublisherImpl(const capro::ServiceDescription& service,
const PublisherOptions& publisherOptions)
: BasePublisher_t(service, publisherOptions)
{
}

template <typename T, typename H, typename BasePublisher_t>
template <typename... Args>
inline cxx::expected<Sample<T, H>, AllocationError> Publisher<T, H, BasePublisher_t>::loan(Args&&... args) noexcept
inline cxx::expected<Sample<T, H>, AllocationError> PublisherImpl<T, H, BasePublisher_t>::loan(Args&&... args) noexcept
{
return std::move(loanSample().and_then([&](auto& sample) { new (sample.get()) T(std::forward<Args>(args)...); }));
}

template <typename T, typename H, typename BasePublisher_t>
template <typename Callable, typename... ArgTypes>
inline cxx::expected<AllocationError> Publisher<T, H, BasePublisher_t>::publishResultOf(Callable c,
ArgTypes... args) noexcept
inline cxx::expected<AllocationError> PublisherImpl<T, H, BasePublisher_t>::publishResultOf(Callable c,
ArgTypes... args) noexcept
{
static_assert(cxx::is_invocable<Callable, T*, ArgTypes...>::value,
"Publisher<T>::publishResultOf expects a valid callable with a specific signature as the "
Expand All @@ -56,7 +56,7 @@ inline cxx::expected<AllocationError> Publisher<T, H, BasePublisher_t>::publishR
}

template <typename T, typename H, typename BasePublisher_t>
inline cxx::expected<AllocationError> Publisher<T, H, BasePublisher_t>::publishCopyOf(const T& val) noexcept
inline cxx::expected<AllocationError> PublisherImpl<T, H, BasePublisher_t>::publishCopyOf(const T& val) noexcept
{
return loanSample().and_then([&](auto& sample) {
*sample.get() = val; // Copy assignment of value into sample's memory allocation.
Expand All @@ -65,7 +65,7 @@ inline cxx::expected<AllocationError> Publisher<T, H, BasePublisher_t>::publishC
}

template <typename T, typename H, typename BasePublisher_t>
inline cxx::expected<Sample<T, H>, AllocationError> Publisher<T, H, BasePublisher_t>::loanSample() noexcept
inline cxx::expected<Sample<T, H>, AllocationError> PublisherImpl<T, H, BasePublisher_t>::loanSample() noexcept
{
static constexpr uint32_t USER_HEADER_SIZE{std::is_same<H, mepoo::NoUserHeader>::value ? 0U : sizeof(H)};

Expand All @@ -81,15 +81,15 @@ inline cxx::expected<Sample<T, H>, AllocationError> Publisher<T, H, BasePublishe
}

template <typename T, typename H, typename BasePublisher_t>
inline void Publisher<T, H, BasePublisher_t>::publish(Sample<T, H>&& sample) noexcept
inline void PublisherImpl<T, H, BasePublisher_t>::publish(Sample<T, H>&& sample) noexcept
{
auto userPayload = sample.release(); // release the Samples ownership of the chunk before publishing
auto chunkHeader = mepoo::ChunkHeader::fromUserPayload(userPayload);
port().sendChunk(chunkHeader);
}

template <typename T, typename H, typename BasePublisher_t>
inline cxx::optional<Sample<T, H>> Publisher<T, H, BasePublisher_t>::loanPreviousSample() noexcept
inline cxx::optional<Sample<T, H>> PublisherImpl<T, H, BasePublisher_t>::loanPreviousSample() noexcept
{
auto result = port().tryGetPreviousChunk();
if (result.has_value())
Expand All @@ -101,7 +101,7 @@ inline cxx::optional<Sample<T, H>> Publisher<T, H, BasePublisher_t>::loanPreviou

template <typename T, typename H, typename BasePublisher_t>
inline Sample<T, H>
Publisher<T, H, BasePublisher_t>::convertChunkHeaderToSample(mepoo::ChunkHeader* const header) noexcept
PublisherImpl<T, H, BasePublisher_t>::convertChunkHeaderToSample(mepoo::ChunkHeader* const header) noexcept
{
return Sample<T, H>(cxx::unique_ptr<T>(reinterpret_cast<T*>(header->userPayload()), m_sampleDeleter), *this);
}
Expand Down
Loading

0 comments on commit 79db27b

Please sign in to comment.