Skip to content
Merged
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
122 changes: 116 additions & 6 deletions include/realtime_tools/realtime_box.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class RealtimeBoxBase
// We do not need to lock our own mutex because we are currently in the process of being created
value_ = o.value_;
}

// Copy assignment constructor
constexpr RealtimeBoxBase & operator=(const RealtimeBoxBase & o)
{
Expand All @@ -88,13 +89,15 @@ class RealtimeBoxBase
}
return *this;
}

constexpr RealtimeBoxBase(RealtimeBoxBase && o)
{
// Lock the other box mutex
std::unique_lock<mutex_t> lock(o.lock_);
// We do not need to lock our own mutex because we are currently in the process of being created
value_ = std::move(o.value_);
}

// Only enabled for types that can be constructed from an initializer list
template <typename U = T>
constexpr RealtimeBoxBase(
Expand All @@ -103,6 +106,7 @@ class RealtimeBoxBase
: value_(init)
{
}

constexpr RealtimeBoxBase & operator=(RealtimeBoxBase && o)
{
// Check for self assignment (and a potential deadlock)
Expand Down Expand Up @@ -131,6 +135,7 @@ class RealtimeBoxBase
value_ = value;
return true;
}

/**
* @brief access the content readable with best effort
* @return false if the mutex could not be locked
Expand All @@ -146,6 +151,38 @@ class RealtimeBoxBase
func(value_);
return true;
}

/**
* @brief set a new content with best effort
* @return false if mutex could not be locked
* @note disabled for pointer types
* @deprecated Use try_set(const T & value) instead!
*/
template <typename U = T>
[[deprecated("Use try_set(const T & value) instead!")]]
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, bool> trySet(const T & value)
{
std::unique_lock<mutex_t> guard(lock_, std::defer_lock);
if (!guard.try_lock()) {
return false;
}
value_ = value;
return true;
}

/**
* @brief access the content readable with best effort
* @return false if the mutex could not be locked
* @note only safe way to access pointer type content (rw)
* @deprecated Use try_set(const std::function<void(T &)> & func) instead!
*/
template <typename U = T>
[[deprecated("Use try_set(const std::function<void(T &)> & func) instead!")]]
bool trySet(const std::function<void(T &)> & func)
{
return try_set(func);
}

/**
* @brief get the content with best effort
* @return std::nullopt if content could not be access, otherwise the content is returned
Expand All @@ -159,6 +196,7 @@ class RealtimeBoxBase
}
return value_;
}

/**
* @brief access the content (r) with best effort
* @return false if the mutex could not be locked
Expand All @@ -176,8 +214,34 @@ class RealtimeBoxBase
}

/**
* @brief set the content and wait until the mutex could be locked (RealtimeBox behavior)
* @return true
* @brief get the content with best effort
* @return std::nullopt if content could not be access, otherwise the content is returned
* @deprecated Use try_get() instead!
*/
template <typename U = T>
[[deprecated("Use try_get() instead!")]] [[nodiscard]]
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, std::optional<U>> tryGet() const
{
return try_get();
}

/**
* @brief access the content (r) with best effort
* @return false if the mutex could not be locked
* @note only safe way to access pointer type content (r)
* @deprecated Use try_get(const std::function<void(const T &)> & func) instead!
*/
template <typename U = T>
[[deprecated("Use try_get(const std::function<void(const T &)> & func) instead!")]]
bool tryGet(const std::function<void(const T &)> & func)
{
return try_get(func);
}

/**
* @brief Wait until the mutex can be locked and set the content (RealtimeBox behavior)
* @note disabled for pointer types
* @note same signature as in the existing RealtimeBox<T>
*/
template <typename U = T>
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, void> set(const T & value)
Expand All @@ -186,17 +250,39 @@ class RealtimeBoxBase
// cppcheck-suppress missingReturn
value_ = value;
}

/**
* @brief access the content (rw) and wait until the mutex could locked
* @brief Wait until the mutex can be locked and set the content (RealtimeBox behavior)
* @note same signature as in the existing RealtimeBox<T>
* @note Not the safest way to access pointer type content (rw)
* @deprecated Use set(const std::function<void(T &)> & func) instead!
*/
template <typename U = T>
[[deprecated("Use set(const std::function<void(T &)> & func) instead!")]]
typename std::enable_if_t<is_ptr_or_smart_ptr<U>, void> set(const T & value)
{
std::lock_guard<mutex_t> guard(lock_);
// cppcheck-suppress missingReturn
value_ = value;
}

/**
* @brief wait until the mutex could be locked and access the content (rw)
*/
void set(const std::function<void(T &)> & func)
{
std::lock_guard<mutex_t> guard(lock_);
if (!func) {
if constexpr (is_ptr_or_smart_ptr<T>) {
value_ = nullptr;
return;
}
}
func(value_);
}

/**
* @brief get the content and wait until the mutex could be locked (RealtimeBox behaviour)
* @brief Wait until the mutex could be locked and get the content (RealtimeBox behaviour)
* @return copy of the value
*/
template <typename U = T>
Expand All @@ -205,8 +291,9 @@ class RealtimeBoxBase
std::lock_guard<mutex_t> guard(lock_);
return value_;
}

/**
* @brief get the content and wait until the mutex could be locked
* @brief Wait until the mutex could be locked and get the content (r)
* @note same signature as in the existing RealtimeBox<T>
*/
template <typename U = T>
Expand All @@ -216,8 +303,24 @@ class RealtimeBoxBase
// cppcheck-suppress missingReturn
in = value_;
}

/**
* @brief access the content (r) and wait until the mutex could be locked
* @brief Wait until the mutex could be locked and get the content (r)
* @note same signature as in the existing RealtimeBox<T>
* @note Not the safest way to access pointer type content (r)
* @deprecated Use get(const std::function<void(const T &)> & func) instead!
*/
template <typename U = T>
[[deprecated("Use get(const std::function<void(const T &)> & func) instead!")]]
typename std::enable_if_t<is_ptr_or_smart_ptr<U>, void> get(T & in) const
{
std::lock_guard<mutex_t> guard(lock_);
// cppcheck-suppress missingReturn
in = value_;
}

/**
* @brief Wait until the mutex could be locked and access the content (r)
* @note only safe way to access pointer type content (r)
* @note same signature as in the existing RealtimeBox<T>
*/
Expand Down Expand Up @@ -247,6 +350,7 @@ class RealtimeBoxBase
// Only makes sense with the getNonRT method otherwise we would return an std::optional
return get();
}

/**
* @brief provide a custom conversion operator
* @note Can be used from non-RT and RT contexts
Expand All @@ -264,6 +368,12 @@ class RealtimeBoxBase
[[nodiscard]] const mutex_t & get_mutex() const { return lock_; }
[[nodiscard]] mutex_t & get_mutex() { return lock_; }

[[nodiscard]] [[deprecated("Use get_mutex() instead!")]] mutex_t & getMutex() { return lock_; }
[[nodiscard]] [[deprecated("Use get_mutex() instead!")]] const mutex_t & getMutex() const
{
return lock_;
}

private:
T value_;

Expand Down
29 changes: 29 additions & 0 deletions include/realtime_tools/realtime_box_best_effort.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2024 ros2_control Development Team
//
// 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 REALTIME_TOOLS__REALTIME_BOX_BEST_EFFORT_H_
#define REALTIME_TOOLS__REALTIME_BOX_BEST_EFFORT_H_

#include "realtime_tools/realtime_box.h"

// Deprecation notice
#ifdef _WIN32
#pragma message( \
"This header include is deprecated. Please update your code to use 'realtime_box.h' header.") //NOLINT
#else
#warning \
"This header include is deprecated. Please update your code to use 'realtime_box.h' header." //NOLINT
#endif

#endif // REALTIME_TOOLS__REALTIME_BOX_BEST_EFFORT_H_
4 changes: 4 additions & 0 deletions test/realtime_box_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ TEST(RealtimeBox, smart_ptr_type)
box.try_set([](const auto & p) { *p = 10; });

box.try_get([](const auto & p) { EXPECT_EQ(*p, 10); });

// Test that we are able to set the nullptr for pointer types
RealtimeBox<std::shared_ptr<int>> box2;
box2.set(nullptr);
}

// These are the tests from the old RealtimeBox implementation
Expand Down
Loading