Skip to content

Commit

Permalink
iox-eclipse-iceoryx#605 add doxygen documentation
Browse files Browse the repository at this point in the history
Signed-off-by: Marika Lehmann <[email protected]>
  • Loading branch information
FerdinandSpitzschnueffler committed Mar 17, 2021
1 parent 9618538 commit e3ee6b7
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 47 deletions.
4 changes: 2 additions & 2 deletions iceoryx_utils/include/iceoryx_utils/cxx/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ class vector
// is undefined if the element at index does not exist.
T& at(const uint64_t index) noexcept;

/// @brief returns a cost reference to the element stored at index. the
/// @brief returns a const reference to the element stored at index. the
/// behavior is undefined if the element at index does not exist.
const T& at(const uint64_t index) const noexcept;

/// @brief returns a reference to the element stored at index. the behavior
// is undefined if the element at index does not exist.
T& operator[](const uint64_t index) noexcept;

/// @brief returns a cost reference to the element stored at index. the
/// @brief returns a const reference to the element stored at index. the
/// behavior is undefined if the element at index does not exist.
const T& operator[](const uint64_t index) const noexcept;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,45 @@ namespace iox
{
namespace rp
{
/// @brief minimalistic relocatable pointer that can be written and read atomically
/// and can be stored safely in shared memory.
/// As the basic relocatable_ptr, it must point to something in the same shared memory segment as itself
/// since the internally used offset must be an invariant different across adress spaces.
/// Rationale: the default relocatable_ptr cannot be used in an atomic since the copy ctor is nontrivial.
/// @brief minimalistic relocatable pointer that can be written and read atomically and can be stored safely in shared
/// memory.
/// As the basic RelocatablePointer, it must point to something in the same shared memory segment as itself since the
/// internally used offset must be an invariant different across adress spaces. Rationale: the default
/// RelocatablePointer cannot be used in an atomic since the copy ctor is nontrivial.
template <typename T>
class atomic_relocatable_ptr
{
public:
using offset_t = std::ptrdiff_t;
static constexpr offset_t NULL_POINTER_OFFSET = std::numeric_limits<offset_t>::max();

/// @brief creates atomic_relocatable_ptr pointing to ptr
/// @param[in] ptr pointee
atomic_relocatable_ptr(const T* ptr = nullptr) noexcept;

///@todo: can be implemented when needed, note that the offset must be recomputed during the move/copy
/// @todo: can be implemented when needed, note that the offset must be recomputed during the move/copy
atomic_relocatable_ptr(const atomic_relocatable_ptr&) = delete;
atomic_relocatable_ptr& operator=(const atomic_relocatable_ptr& other) = delete;

atomic_relocatable_ptr(atomic_relocatable_ptr&& other) = delete;
atomic_relocatable_ptr& operator=(atomic_relocatable_ptr&& other) = delete;

/// @note minimal set of required operators, can be extended later

/// @brief assign atomic_relocatable_ptr to point to ptr
/// @param[in] ptr pointee
/// @return reference to self
atomic_relocatable_ptr& operator=(const T* ptr) noexcept;

/// @brief access to the underlying object in shared memory
/// @return a pointer to the underlying object
T* operator->() const noexcept;

/// @brief dereferencing operator which returns a reference to the pointee
/// @return a reference to the pointee
T& operator*() const noexcept;

/// @brief converts the atomic_relocatable_ptr to a pointer of type of the underlying object
/// @return a pointer of type T pointing to the underlying object
operator T*() const noexcept;

private:
Expand All @@ -61,7 +72,6 @@ class atomic_relocatable_ptr

inline offset_t computeOffset(const void* ptr) const noexcept;
};

} // namespace rp
} // namespace iox

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ namespace iox
{
namespace rp
{
/// @brief pointer type to use when pointer and pointee are located in different shared memory segments
/// We can have the following scenario:
/// Pointer p is stored in segment S1 and points to object X of type T in segment S2.
///
/// Shared Memory S1: p S2: X
/// |___________________^
/// App1 a1 b1 c1 d1
/// App2 a2 b2 c2 d2
///
/// Now it is no longer true in general that both segments will be offset by the same difference in App2 and therefore
/// relocatable pointers are no longer sufficient.
/// Relative pointers solve this problem by incorporating the information from where they need to measure differences
/// (i.e. relative to the given address). This requires an additional registration mechanism to be used by all
/// applications where the start addresses and the size of all segments to be used are registered. Since these start
/// address may differ between applications, each segment is identified by a unique id, which can be provided upon
/// registration by the first application. In the figure, this means that the starting addresses of both segments(a1, a2
/// and c1, c2) would have to be registered in both applications.
/// Once this registration is done, relative pointers can be constructed from raw pointers similar to relocatable
/// pointers.
/// @note It should be noted that relocating a memory segment will invalidate relative pointers, i.e. relative pointers
/// are NOT relocatable. This is because the registration mechanism cannot be automatically informed about the copy of a
/// whole segment, such a segment would have to be registered on its own (and the original segment deregistered).
class BaseRelativePointer
{
public:
Expand All @@ -33,69 +55,118 @@ class BaseRelativePointer
using const_ptr_t = const void* const;
using offset_t = std::uintptr_t;

/// @brief constructs a BaseRelativePointer pointing to ptr in a segment identified by id
/// @param[in] ptr is the pointee
/// @param[in] id is the unique id of the segment
BaseRelativePointer(ptr_t ptr, id_t id) noexcept;

/// @brief constructs a BaseRelativePointer from a given offset and segment id
/// @param[in] offset is the offset
/// @param[in] id is the unique id of the segment
BaseRelativePointer(offset_t offset, id_t id) noexcept;

/// @brief constructs a BaseRelativePointer pointing to ptr
/// @param[in] ptr is the pointee
BaseRelativePointer(ptr_t ptr = nullptr) noexcept;

/// @brief copy constructor
/// @param[in] other is the copy origin
BaseRelativePointer(const BaseRelativePointer& other) noexcept;

/// @brief move constructor
/// @param[in] other is the move origin
BaseRelativePointer(BaseRelativePointer&& other) noexcept;

/// @brief copy assignment
/// @param[in] other is the copy origin
/// @return a reference to self
BaseRelativePointer& operator=(const BaseRelativePointer& other) noexcept;

/// @brief assigns the BaseRelativePointer to point to ptr
/// @param[in] ptr is the pointee
/// @return reference to self
BaseRelativePointer& operator=(void* ptr) noexcept;

/// @brief move assignment
/// @param[in] other is the move origin
/// @return a reference to self
BaseRelativePointer& operator=(BaseRelativePointer&& other) noexcept;

/// @brief access to the underlying object
/// @return a poiter to the underlying object
ptr_t get() const noexcept;

/// @brief returns the id which identifies the segment
/// @return the id which identifies the segment
id_t getId() const noexcept;

/// @brief returns the offset
/// @return the offset
offset_t getOffset() const noexcept;

/// @brief get the base pointer associated with this' id
/// @return the registered base pointer
ptr_t getBasePtr() const noexcept;

//*********************************id operations********************************************

/// @brief registers a memory segment at ptr with size of a new id
/// @return id id it was registered to
/// @param[in] ptr starting address of the segment to be registered
/// @param[in] size is the size of the segment
/// @return id it was registered to
static id_t registerPtr(const ptr_t ptr, uint64_t size = 0U) noexcept;

/// @brief registers a memory segment at ptr with size of given id
/// @param[in] id is the id of the segment
/// @param[in] ptr starting address of the segment to be registered
/// @param[in] size is the size of the segment
/// @return true if successful (id not occupied), false otherwise
static bool registerPtr(const id_t id, const ptr_t ptr, uint64_t size = 0U) noexcept;

/// @brief unregister ptr with given id
/// @brief unregisters ptr with given id
/// @param[in] id is the id of the segment
/// @return true if successful (ptr was registered with this id before), false otherwise
static bool unregisterPtr(const id_t id) noexcept;

/// @brief get the base ptr associated with the given id
/// @param[in] id is the id of the segment
/// @return ptr registered at the given id, nullptr if none was registered
static ptr_t getBasePtr(const id_t id) noexcept;

/// @brief unregister all ptr id pairs (leads to initial state)
/// @brief unregisters all ptr id pairs (leads to initial state)
static void unregisterAll() noexcept;

/// @brief get the offset from id and ptr
/// @param[in] id is the id of the segment and is used to get the bease pointer
/// @param[in] ptr is the pointer whose offset should be calculated
/// @return offset
static offset_t getOffset(const id_t id, const_ptr_t ptr) noexcept;

/// @brief get the pointer from id and offset ("inverse" to getOffset)
/// @return ptr
/// @param[in] id is the id of the segment and is used to get the bease pointer
/// @param[in] offset is the offset for which the pointer should be calculated
/// @return the pointer from id and offset
static ptr_t getPtr(const id_t id, const offset_t offset) noexcept;

/// @brief get the id for a given ptr
/// @param[in] ptr the pointer whose corresponding id is searched for
/// @return id the pointer was registered to
static id_t searchId(ptr_t ptr) noexcept;

/// @brief checks if given id is valid
/// @param[in] id is the id to be checked
/// @return true if the given id is valid, otherwise false
static bool isValid(id_t id) noexcept;

/// @brief returns the pointer repository
/// @return the pointer repository
static PointerRepository<id_t, ptr_t>& getRepository() noexcept;

//*****************************************************************************************

/// @brief get the offset from the start address of the segment and ptr
/// @param[in] ptr is the pointer whose offset should be calculated
/// @return offset
offset_t computeOffset(ptr_t ptr) const noexcept;

/// @brief get the pointer from stored id and offset
/// @return the pointer for stored id and offset
ptr_t computeRawPtr() const noexcept;

static constexpr id_t NULL_POINTER_ID = std::numeric_limits<id_t>::max();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ namespace iox
{
namespace rp
{
/// @brief pointer type to use when pointer and pointee are located in the same shared memory segment
/// We can have the following scenario:
/// Pointer p points to object X of type T and both are stored in shared memory segment S.
///
/// Shared Memory S: p X
/// |__________________^
/// App1 a1 b1 c1
/// App2 a2 b2 c2
///
/// Let a1, b1, c1 be the addresses of segment S, pointer p and object X in application 1 and similarly a2, b2, and c2
/// in application 2. If application 2 maps the memory differently they will be shifted by some common offset d
/// depending on the individual memory mapping: a2=a1+d, b2=b1+d, c2=c1+d
/// This is why storing a raw pointer to X will not be sufficient, the value of c1 will not point to X in application 2.
/// However, storing the difference between the location of p and X will work since it is an invariant in both address
/// spaces.
class BaseRelocatablePointer
{
template <typename T>
Expand All @@ -32,28 +47,54 @@ class BaseRelocatablePointer
public:
using offset_t = std::ptrdiff_t;

/// @brief default constructs a logical nullptr
BaseRelocatablePointer() noexcept;

/// @brief creates a relocatable pointer pointing to ptr
/// @param[in] ptr pointee
explicit BaseRelocatablePointer(const void* ptr) noexcept;

/// @brief copy constructor
/// @param[in] other is the copy origin
BaseRelocatablePointer(const BaseRelocatablePointer& other) noexcept;

/// @brief move constructor
/// @param[in] other is the move origin
BaseRelocatablePointer(BaseRelocatablePointer&& other) noexcept;

/// @brief copy assignment
/// @param[in] other is the copy origin
/// @return reference to self
BaseRelocatablePointer& operator=(const BaseRelocatablePointer& other) noexcept;

/// @brief assign BaseRelocatablePointer to point to rawPtr
/// @param[in] rawPtr pointee
/// @return reference to self
BaseRelocatablePointer& operator=(const void* rawPtr) noexcept;

/// @brief move assignment
/// @param[in] other is the move origin
/// @return reference to self
BaseRelocatablePointer& operator=(BaseRelocatablePointer&& other) noexcept;

/// @brief read-only access to the underlying object in shared memory
/// @return a const pointer to the underlying object
const void* operator*() const noexcept;

/// @brief checks if this is not a logical nullptr
/// @return true if this is not a logical nullptr, otherwise false
operator bool() const noexcept;

/// @brief checks if this is a logical nullptr
/// @return true if this is a logical nullptr, otherwise false
bool operator!() const noexcept;

/// @brief access to the underlying object in shared memory
/// @return a poiter to the underlying object
void* get() const noexcept;

/// @brief returns the offset
/// @return offset
offset_t getOffset() const noexcept;

static constexpr offset_t NULL_POINTER_OFFSET = std::numeric_limits<offset_t>::max();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,30 +50,54 @@ class PointerRepository
public:
static constexpr id_t INVALID_ID = std::numeric_limits<id_t>::max();

/// @brief default constructor
PointerRepository() noexcept;

/// @brief registers the start pointer of the segment in another application with a specific id
/// @param[in] id identifies the segment
/// @param[in] ptr is the start pointer of the segment
/// @param[in] size is the size of the segment
/// @return true if the registration was successful, otherwise false
bool registerPtr(id_t id, ptr_t ptr, uint64_t size) noexcept;

/// @brief registers the start pointer of a segment with a specific size
/// @param[in] ptr is the start pointer of the segment
/// @param[in] size is the size of the segment
/// @return the id that identifies the segment
id_t registerPtr(const ptr_t ptr, uint64_t size = 0U) noexcept;

/// @brief unregisters the id and also invalidates relative pointers using this id
/// @param[in] id is the id to be unregistered
/// @return true if successful, otherwise false
bool unregisterPtr(id_t id) noexcept;

/// @brief unregisters all ids and also invalidates all relative pointers
void unregisterAll() noexcept;

/// @brief gets the base pointer associated with id
/// @param[in] id is the segment id
/// @return the base pointer associated with the id
ptr_t getBasePtr(id_t id) const noexcept;

/// @brief returns the id for a given pointer ptr
/// @param[in] ptr is the pointer whose corresponding id is searched for
/// @return the id the pointer was registered to
id_t searchId(ptr_t ptr) const noexcept;

/// @brief checks if given id is valid
/// @param[in] id is the id to be checked
/// @return true if id is valid, otherwise false
bool isValid(id_t id) const noexcept;

/// @brief prints the ids and their associated base pointers
void print() const noexcept;

private:
/// @todo: if required protect vector against concurrent modification
// whether this is required depends on the use case, we currently do not need it
// we control the ids, so if they are consecutive we only need a vector/array to get the address
// this variable exists once per application using relative pointers,
// and each needs to initialize it via register calls above
/// whether this is required depends on the use case, we currently do not need it
/// we control the ids, so if they are consecutive we only need a vector/array to get the address
/// this variable exists once per application using relative pointers,
/// and each needs to initialize it via register calls above

iox::cxx::vector<Info, CAPACITY> m_info;
uint64_t m_maxRegistered{0U};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ inline ptr_t PointerRepository<id_t, ptr_t, CAPACITY>::getBasePtr(id_t id) const
return m_info[id].basePtr;
}

/// @note for id 0 nullptr is returned, meaning we will later interpret a relative pointer
/// by casting the offset into a pointer (i.e. we measure relative to 0)
/// @note for id 0 nullptr is returned, meaning we will later interpret a relative pointer by casting the offset
/// into a pointer (i.e. we measure relative to 0)

/// @note we cannot distinguish between not registered and nullptr registered, but we do not need to
return nullptr;
Expand Down
Loading

0 comments on commit e3ee6b7

Please sign in to comment.