Skip to content

Commit

Permalink
iox-eclipse-iceoryx#25: first skeletons for chunk receiver and its test
Browse files Browse the repository at this point in the history
Signed-off-by: Poehnl Michael (CC-AD/ESW1) <[email protected]>
  • Loading branch information
Poehnl Michael (CC-AD/ESW1) committed Apr 6, 2020
1 parent 5a9fdc7 commit 33548dd
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 22 deletions.
3 changes: 2 additions & 1 deletion iceoryx_posh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ add_library(iceoryx_posh
source/popo/sender_port.cpp
source/popo/sender_port_data.cpp
source/popo/receiver_handler.cpp
source/popo/building_blocks/chunk_queue.cpp
source/popo/building_blocks/chunk_queue.cpp
source/popo/building_blocks/chunk_receiver.cpp
source/runtime/message_queue_interface.cpp
source/runtime/message_queue_message.cpp
source/runtime/port_config_info.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef IOX_POSH_POPO_CHUNK_RECEIVER_HPP_
#define IOX_POSH_POPO_CHUNK_RECEIVER_HPP_

#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_receiver_data.hpp"
#include "iceoryx_posh/mepoo/chunk_header.hpp"
#include "iceoryx_utils/cxx/expected.hpp"
#include "iceoryx_utils/cxx/optional.hpp"

namespace iox
{
namespace popo
{
enum class ChunkReceiverError
{
TOO_MANY_CHUNKS_HELD_IN_PARALLEL
};

/// @brief The ChunkReceiver is a building block of the shared memory communication infrastructure. It extends
/// the functionality of a ChunkQueue with the abililty to pass chunks to the user side (user process).
/// Together with the ChunkSender, they are the next abstraction layer on top of ChunkDistributor and ChunkQueue. The
/// ChunkRceiver holds the ownership of the SharedChunks and does a bookkeeping which chunks are currently passed to the
/// user side.
class ChunkReceiver : public ChunkQueue
{
public:
using MemberType_t = ChunkReceiverData;

ChunkReceiver(MemberType_t* const chunkReceiverDataPtr) noexcept;

ChunkReceiver(const ChunkReceiver& other) = delete;
ChunkReceiver& operator=(const ChunkReceiver&) = delete;
ChunkReceiver(ChunkReceiver&& rhs) = default;
ChunkReceiver& operator=(ChunkReceiver&& rhs) = default;
~ChunkReceiver() = default;

/// @brief Tries to get the next received chunk. If there is a new one the ChunkHeader of this new chunk is received
/// The ownerhip of the SharedChunk remains in the ChunkReceiver for being able to cleanup if the user process
/// disappears
/// @return optional that has a new chunk header or no value if there are no new chunks in the underlying queue,
/// ChunkReceiverError on error
cxx::expected<cxx::optional<const mepoo::ChunkHeader*>, ChunkReceiverError> get() noexcept;

/// @brief Release a chunk that was obtained with get
/// @param[in] chunkHeader, pointer to the ChunkHeader to free
void release(const mepoo::ChunkHeader* chunkHeader) noexcept;

/// @brief Release all the chunks that are currently held. Caution: Only call this if the user process is no more
/// running E.g. This cleans up chunks that were held by a user process that died unexpectetly, for avoiding lost
/// chunks in the system
void releaseAll() noexcept;

private:
const MemberType_t* getMembers() const noexcept;
MemberType_t* getMembers() noexcept;
};

} // namespace popo
} // namespace iox

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_data.hpp"
#include "iceoryx_posh/internal/popo/used_chunk_list.hpp"
#include "iceoryx_posh/mepoo/memory_info.hpp"
#include "iceoryx_utils/cxx/variant_queue.hpp"

namespace iox
{
namespace popo
{
struct ChunkReceiverData : public ChunkQueueData
{
ChunkReceiverData(const mepoo::MemoryInfo& memoryInfo = mepoo::MemoryInfo()) noexcept
: m_memoryInfo(memoryInfo)
ChunkReceiverData(cxx::VariantQueueTypes queueType,
const mepoo::MemoryInfo& memoryInfo = mepoo::MemoryInfo()) noexcept
: ChunkQueueData(queueType)
, m_memoryInfo(memoryInfo)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
#define IOX_POSH_POPO_CHUNK_SENDER_HPP_

#include "iceoryx_posh/internal/mepoo/shared_chunk.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_distributor.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_sender.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_sender_data.hpp"
#include "iceoryx_posh/mepoo/chunk_header.hpp"
#include "iceoryx_utils/cxx/expected.hpp"
Expand All @@ -28,11 +26,10 @@ namespace iox
{
namespace popo
{
/// @brief error which can occur in the VariantQueue
enum class ChunkSenderError
{
RUNNING_OUT_OF_CHUNKS,
TOO_MANY_CHUKS_ALLOCATED_IN_PARALLEL
TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL
};

/// @brief The ChunkSender is a building block of the shared memory communication infrastructure. It extends
Expand Down Expand Up @@ -75,12 +72,12 @@ class ChunkSender : public ChunkDistributorType

/// @brief Returns the last sent chunk if there is one
/// @return pointer to the ChunkHeader of the last sent Chunk if there is one, empty optional if not
cxx::optional<const mepoo::ChunkHeader*> getLastChunk() const noexcept;
cxx::optional<const mepoo::ChunkHeader*> getLast() const noexcept;

/// @brief Release all the chunks that are currently held. Caution: Only call this if the user process is no more
/// running E.g. This cleans up chunks that were held by a user process that died unexpectetly, for avoiding lost
/// chunks in the system
void releaseAllChunks() noexcept;
void releaseAll() noexcept;

private:
/// @brief Get the SharedChunk from the provided ChunkHeader and do all that is required to send the chunk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ ChunkSender<ChunkDistributorType>::allocate(const uint32_t payloadSize) noexcept
}
else
{
return cxx::error<ChunkSenderError>(ChunkSenderError::TOO_MANY_CHUKS_ALLOCATED_IN_PARALLEL);
return cxx::error<ChunkSenderError>(ChunkSenderError::TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL);
}
}
else
Expand All @@ -75,7 +75,7 @@ ChunkSender<ChunkDistributorType>::allocate(const uint32_t payloadSize) noexcept
{
// release the allocated chunk
chunk = nullptr;
return cxx::error<ChunkSenderError>(ChunkSenderError::TOO_MANY_CHUKS_ALLOCATED_IN_PARALLEL);
return cxx::error<ChunkSenderError>(ChunkSenderError::TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL);
}
}
else
Expand Down Expand Up @@ -122,7 +122,7 @@ inline void ChunkSender<ChunkDistributorType>::pushToHistory(mepoo::ChunkHeader*
}

template <typename ChunkDistributorType>
inline cxx::optional<const mepoo::ChunkHeader*> ChunkSender<ChunkDistributorType>::getLastChunk() const noexcept
inline cxx::optional<const mepoo::ChunkHeader*> ChunkSender<ChunkDistributorType>::getLast() const noexcept
{
if (getMembers()->m_lastChunk)
{
Expand All @@ -135,7 +135,7 @@ inline cxx::optional<const mepoo::ChunkHeader*> ChunkSender<ChunkDistributorType
}

template <typename ChunkDistributorType>
inline void ChunkSender<ChunkDistributorType>::releaseAllChunks() noexcept
inline void ChunkSender<ChunkDistributorType>::releaseAll() noexcept
{
getMembers()->m_chunksInUse.cleanup();
this->cleanup();
Expand Down
52 changes: 52 additions & 0 deletions iceoryx_posh/source/popo/building_blocks/chunk_receiver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "iceoryx_posh/internal/popo/building_blocks/chunk_receiver.hpp"

#include "iceoryx_posh/internal/log/posh_logging.hpp"

namespace iox
{
namespace popo
{
ChunkReceiver::ChunkReceiver(MemberType_t* const chunkReceiverDataPtr) noexcept
: ChunkQueue(chunkReceiverDataPtr)
{
}

const ChunkReceiver::MemberType_t* ChunkReceiver::getMembers() const noexcept
{
return reinterpret_cast<const MemberType_t*>(ChunkQueue::getMembers());
}

ChunkReceiver::MemberType_t* ChunkReceiver::getMembers() noexcept
{
return reinterpret_cast<MemberType_t*>(ChunkQueue::getMembers());
}

cxx::expected<cxx::optional<const mepoo::ChunkHeader*>, ChunkReceiverError> get() noexcept
{
return cxx::error<ChunkReceiverError>(ChunkReceiverError::TOO_MANY_CHUNKS_HELD_IN_PARALLEL);
}

void release(const mepoo::ChunkHeader* chunkHeader) noexcept
{
}

void releaseAll() noexcept
{
}

} // namespace popo
} // namespace iox
80 changes: 80 additions & 0 deletions iceoryx_posh/test/moduletests/test_popo_chunk_receiver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "iceoryx_posh/iceoryx_posh_types.hpp"
#include "iceoryx_posh/internal/mepoo/memory_manager.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_receiver.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_receiver_data.hpp"
#include "iceoryx_posh/mepoo/mepoo_config.hpp"
#include "iceoryx_utils/error_handling/error_handling.hpp"
#include "iceoryx_utils/internal/posix_wrapper/shared_memory_object/allocator.hpp"
#include "test.hpp"

#include <memory>

using namespace ::testing;

struct DummySample
{
uint64_t dummy{42};
};

class ChunkReceiver_testBase : public Test
{
protected:
ChunkReceiver_testBase()
{
m_mempoolconf.addMemPool({CHUNK_SIZE, NUM_CHUNKS_IN_POOL});
m_memoryManager.configureMemoryManager(m_mempoolconf, &m_memoryAllocator, &m_memoryAllocator);
}

~ChunkReceiver_testBase()
{
}

void SetUp()
{
}

void TearDown()
{
}

static constexpr size_t MEMORY_SIZE = 1024 * 1024;
uint8_t m_memory[1024 * 1024];
static constexpr uint32_t NUM_CHUNKS_IN_POOL = 20;
static constexpr uint32_t CHUNK_SIZE = 128;

iox::posix::Allocator m_memoryAllocator{m_memory, MEMORY_SIZE};
iox::mepoo::MePooConfig m_mempoolconf;
iox::mepoo::MemoryManager m_memoryManager;

iox::popo::ChunkReceiverData m_chunkReceiverData{iox::cxx::VariantQueueTypes::SoFi_SingleProducerSingleConsumer};
iox::popo::ChunkReceiver m_chunkReceiver{&m_chunkReceiverData};
};

class ChunkReceiver_test : public ChunkReceiver_testBase
{
public:
ChunkReceiver_test()
: ChunkReceiver_testBase()
{
}
};

TEST_F(ChunkReceiver_test, get_OneChunk)
{
auto sharedChunk = m_memoryManager.getChunk(sizeof(DummySample));
EXPECT_TRUE(sharedChunk);
}
18 changes: 9 additions & 9 deletions iceoryx_posh/test/moduletests/test_popo_chunk_sender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ TEST_F(ChunkSender_test, allocate_Overflow)
// Allocate one more sample for overflow
auto chunk = m_chunkSender.allocate(sizeof(DummySample));
EXPECT_TRUE(chunk.has_error());
EXPECT_THAT(chunk.get_error(), Eq(iox::popo::ChunkSenderError::TOO_MANY_CHUKS_ALLOCATED_IN_PARALLEL));
EXPECT_THAT(chunk.get_error(), Eq(iox::popo::ChunkSenderError::TOO_MANY_CHUNKS_ALLOCATED_IN_PARALLEL));
EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks, Eq(iox::MAX_CHUNKS_ALLOCATE_PER_SENDER));
}

Expand Down Expand Up @@ -200,7 +200,7 @@ TEST_F(ChunkSender_test, sendMultipleWithoutReceiverAndAlwaysLast)
{
auto chunk = m_chunkSender.allocate(sizeof(DummySample));
EXPECT_FALSE(chunk.has_error());
auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
if (i > 0)
{
EXPECT_TRUE(lastChunk.has_value());
Expand All @@ -227,7 +227,7 @@ TEST_F(ChunkSender_test, sendMultipleWithoutReceiverWithHistoryNoLastReuse)
{
auto chunk = m_chunkSenderWithHistory.allocate(sizeof(DummySample));
EXPECT_FALSE(chunk.has_error());
auto lastChunk = m_chunkSenderWithHistory.getLastChunk();
auto lastChunk = m_chunkSenderWithHistory.getLast();
if (i > 0)
{
EXPECT_TRUE(lastChunk.has_value());
Expand Down Expand Up @@ -423,7 +423,7 @@ TEST_F(ChunkSender_test, sendMultipleWithReceiverNoLastReuse)
{
auto chunk = m_chunkSender.allocate(sizeof(DummySample));
EXPECT_FALSE(chunk.has_error());
auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
if (i > 0)
{
EXPECT_TRUE(lastChunk.has_value());
Expand Down Expand Up @@ -452,7 +452,7 @@ TEST_F(ChunkSender_test, sendMultipleWithReceiverLastReuseBecauseAlreadyConsumed
{
auto chunk = m_chunkSender.allocate(sizeof(DummySample));
EXPECT_FALSE(chunk.has_error());
auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
if (i > 0)
{
EXPECT_TRUE(lastChunk.has_value());
Expand Down Expand Up @@ -494,7 +494,7 @@ TEST_F(ChunkSender_test, ReuseLastIfSmaller)
EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks, Eq(0u));
EXPECT_THAT(m_memoryManager.getMemPoolInfo(1).m_usedChunks, Eq(1u));

auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
EXPECT_TRUE(lastChunk.has_value());
// We get the last chunk again
EXPECT_TRUE(*chunkSmaller == *lastChunk);
Expand All @@ -517,7 +517,7 @@ TEST_F(ChunkSender_test, NoReuseOfLastIfBigger)
EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks, Eq(1u));
EXPECT_THAT(m_memoryManager.getMemPoolInfo(1).m_usedChunks, Eq(1u));

auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
EXPECT_TRUE(lastChunk.has_value());
// not the last chunk
EXPECT_FALSE(*chunkBigger == *lastChunk);
Expand All @@ -540,7 +540,7 @@ TEST_F(ChunkSender_test, ReuseOfLastIfBiggerButFitsInChunk)
EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks, Eq(1u));
EXPECT_THAT(m_memoryManager.getMemPoolInfo(1).m_usedChunks, Eq(0u));

auto lastChunk = m_chunkSender.getLastChunk();
auto lastChunk = m_chunkSender.getLast();
EXPECT_TRUE(lastChunk.has_value());
// not the last chunk
EXPECT_TRUE(*chunkBigger == *lastChunk);
Expand All @@ -567,7 +567,7 @@ TEST_F(ChunkSender_test, Cleanup)
EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks,
Eq(HISTORY_CAPACITY + iox::MAX_CHUNKS_ALLOCATE_PER_SENDER));

m_chunkSenderWithHistory.releaseAllChunks();
m_chunkSenderWithHistory.releaseAll();

EXPECT_THAT(m_memoryManager.getMemPoolInfo(0).m_usedChunks, Eq(0u));
}

0 comments on commit 33548dd

Please sign in to comment.