Compare commits

...

6 Commits

Author SHA1 Message Date
Chris Lalancette
ea31f94eb4 23.0.0 2023-09-08 20:47:00 +00:00
Chris Lalancette
f496291e81 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 20:46:51 +00:00
Chris Lalancette
dd6fad6d42 Fix the return type of Rate::period. (#2301)
In a recent commit (bc435776a2),
we reworked how the Rate class worked so it could be
used with ROS time as well.  Unfortunately, we also
accidentally broke the API of it by changing the return
type of Rate::period to a Duration instead of a
std::chrono::nanoseconds .  Put this back to a std::chrono::nanoseconds;
if we want to change it to a Duration, we'll have to
add a new method and deprecate this one.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 16:40:09 -04:00
Christophe Bedard
38734d769a Update API docs links in package READMEs (#2302)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-09-08 13:59:15 -04:00
jmachowinski
e103b8d37e fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks (#2267)
* fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks

This prevents deadlocks in cases, were e.g. get_status() would
be called on the handle in a callback of the handle.

* test(rclcpp_action): Added test for deadlocks during access of a goal handle

This test checks, if the code deadlocks, if methods on the goal handle are
called from the callbacks.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-07 17:37:35 -04:00
Chris Lalancette
253d395d4e Cleanup flaky timers_manager tests. (#2299)
* Cleanup flaky timers_manager tests.

The timers_manager tests were relying too heavily on
specific timings; this caused them to be flaky on the
buildfarm, particularly on Windows.

Here, we increase the timeouts, and remove one test which
just relies too heavily on specific timeouts.  This should
make this test much less flaky on the buildfarm.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-07 15:17:16 -04:00
20 changed files with 143 additions and 95 deletions

View File

@@ -2,6 +2,13 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23.0.0 (2023-09-08)
-------------------
* Fix the return type of Rate::period. (`#2301 <https://github.com/ros2/rclcpp/issues/2301>`_)
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* Cleanup flaky timers_manager tests. (`#2299 <https://github.com/ros2/rclcpp/issues/2299>`_)
* Contributors: Chris Lalancette, Christophe Bedard
22.2.0 (2023-09-07)
-------------------
* Topic correct typeadapter deduction (`#2294 <https://github.com/ros2/rclcpp/issues/2294>`_)

View File

@@ -2,7 +2,7 @@
The ROS client library in C++.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components and features.
The link to the latest rclcpp API documentation, which includes a complete list of its main components and features, can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
## Quality Declaration

View File

@@ -527,7 +527,7 @@ private:
void execute_ready_timers_unsafe();
// Callback to be called when timer is ready
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_ = nullptr;
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_;
// Thread used to run the timers execution task
std::thread timers_thread_;

View File

@@ -163,7 +163,7 @@ public:
reset();
RCLCPP_PUBLIC
Duration
std::chrono::nanoseconds
period() const;
private:

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>22.2.0</version>
<version>23.0.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -28,9 +28,9 @@ using rclcpp::experimental::TimersManager;
TimersManager::TimersManager(
std::shared_ptr<rclcpp::Context> context,
std::function<void(const rclcpp::TimerBase *)> on_ready_callback)
: on_ready_callback_(on_ready_callback),
context_(context)
{
context_ = context;
on_ready_callback_ = on_ready_callback;
}
TimersManager::~TimersManager()

View File

@@ -14,6 +14,7 @@
#include "rclcpp/rate.hpp"
#include <chrono>
#include <stdexcept>
namespace rclcpp
@@ -87,10 +88,10 @@ Rate::reset()
last_interval_ = clock_->now();
}
Duration
std::chrono::nanoseconds
Rate::period() const
{
return period_;
return std::chrono::nanoseconds(period_.nanoseconds());
}
WallRate::WallRate(const double rate)

View File

@@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <cmath>
#include <memory>
#include <utility>
@@ -65,8 +66,10 @@ TEST_F(TestTimersManager, empty_manager)
TEST_F(TestTimersManager, add_run_remove_timer)
{
size_t t_runs = 0;
std::chrono::milliseconds timer_period(10);
auto t = TimerT::make_shared(
10ms,
timer_period,
[&t_runs]() {
t_runs++;
},
@@ -79,7 +82,7 @@ TEST_F(TestTimersManager, add_run_remove_timer)
timers_manager->add_timer(t);
// Sleep for more 3 times the timer period
std::this_thread::sleep_for(30ms);
std::this_thread::sleep_for(3 * timer_period);
// The timer is executed only once, even if we slept 3 times the period
execute_all_ready_timers(timers_manager);
@@ -191,67 +194,6 @@ TEST_F(TestTimersManager, head_not_ready)
EXPECT_EQ(0u, t_runs);
}
TEST_F(TestTimersManager, timers_order)
{
auto timers_manager = std::make_shared<TimersManager>(
rclcpp::contexts::get_global_default_context());
size_t t1_runs = 0;
auto t1 = TimerT::make_shared(
10ms,
[&t1_runs]() {
t1_runs++;
},
rclcpp::contexts::get_global_default_context());
size_t t2_runs = 0;
auto t2 = TimerT::make_shared(
30ms,
[&t2_runs]() {
t2_runs++;
},
rclcpp::contexts::get_global_default_context());
size_t t3_runs = 0;
auto t3 = TimerT::make_shared(
100ms,
[&t3_runs]() {
t3_runs++;
},
rclcpp::contexts::get_global_default_context());
// Add timers in a random order
timers_manager->add_timer(t2);
timers_manager->add_timer(t3);
timers_manager->add_timer(t1);
std::this_thread::sleep_for(10ms);
execute_all_ready_timers(timers_manager);
EXPECT_EQ(1u, t1_runs);
EXPECT_EQ(0u, t2_runs);
EXPECT_EQ(0u, t3_runs);
std::this_thread::sleep_for(30ms);
execute_all_ready_timers(timers_manager);
EXPECT_EQ(2u, t1_runs);
EXPECT_EQ(1u, t2_runs);
EXPECT_EQ(0u, t3_runs);
std::this_thread::sleep_for(100ms);
execute_all_ready_timers(timers_manager);
EXPECT_EQ(3u, t1_runs);
EXPECT_EQ(2u, t2_runs);
EXPECT_EQ(1u, t3_runs);
timers_manager->remove_timer(t1);
std::this_thread::sleep_for(30ms);
execute_all_ready_timers(timers_manager);
EXPECT_EQ(3u, t1_runs);
EXPECT_EQ(3u, t2_runs);
EXPECT_EQ(1u, t3_runs);
}
TEST_F(TestTimersManager, start_stop_timers_thread)
{
auto timers_manager = std::make_shared<TimersManager>(
@@ -274,7 +216,7 @@ TEST_F(TestTimersManager, timers_thread)
auto timers_manager = std::make_shared<TimersManager>(
rclcpp::contexts::get_global_default_context());
size_t t1_runs = 0;
int t1_runs = 0;
auto t1 = TimerT::make_shared(
1ms,
[&t1_runs]() {
@@ -282,7 +224,7 @@ TEST_F(TestTimersManager, timers_thread)
},
rclcpp::contexts::get_global_default_context());
size_t t2_runs = 0;
int t2_runs = 0;
auto t2 = TimerT::make_shared(
1ms,
[&t2_runs]() {
@@ -296,12 +238,12 @@ TEST_F(TestTimersManager, timers_thread)
// Run timers thread for a while
timers_manager->start();
std::this_thread::sleep_for(5ms);
std::this_thread::sleep_for(50ms);
timers_manager->stop();
EXPECT_LT(1u, t1_runs);
EXPECT_LT(1u, t2_runs);
EXPECT_EQ(t1_runs, t2_runs);
EXPECT_LE(std::abs(t1_runs - t2_runs), 1);
}
TEST_F(TestTimersManager, destructor)
@@ -365,13 +307,13 @@ TEST_F(TestTimersManager, add_remove_while_thread_running)
timers_manager->start();
// After a while remove t1 and add t2
std::this_thread::sleep_for(5ms);
std::this_thread::sleep_for(50ms);
timers_manager->remove_timer(t1);
size_t tmp_t1 = t1_runs;
timers_manager->add_timer(t2);
// Wait some more time and then stop
std::this_thread::sleep_for(5ms);
std::this_thread::sleep_for(50ms);
timers_manager->stop();
// t1 has stopped running

View File

@@ -3,6 +3,12 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23.0.0 (2023-09-08)
-------------------
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks (`#2267 <https://github.com/ros2/rclcpp/issues/2267>`_)
* Contributors: Christophe Bedard, jmachowinski
22.2.0 (2023-09-07)
-------------------
* Correct the position of a comment. (`#2290 <https://github.com/ros2/rclcpp/issues/2290>`_)

View File

@@ -2,7 +2,8 @@
Adds action APIs for C++.
Visit the [rclcpp_action API documentation](http://docs.ros2.org/latest/api/rclcpp_action/) for a complete list of its main components and features. For more information about Actions in ROS 2, see the [design document](http://design.ros2.org/articles/actions.html).
The link to the latest rclcpp_action API documentation, which includes a complete list of its main components and features, can be found on the rclcpp_action package info page, at the [ROS Index](https://index.ros.org/p/rclcpp_action/).
For more information about Actions in ROS 2, see the [design document](http://design.ros2.org/articles/actions.html).
## Quality Declaration

View File

@@ -163,7 +163,7 @@ private:
ResultCallback result_callback_{nullptr};
int8_t status_{GoalStatus::STATUS_ACCEPTED};
std::mutex handle_mutex_;
std::recursive_mutex handle_mutex_;
};
} // namespace rclcpp_action

View File

@@ -59,7 +59,7 @@ template<typename ActionT>
std::shared_future<typename ClientGoalHandle<ActionT>::WrappedResult>
ClientGoalHandle<ActionT>::async_get_result()
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
if (!is_result_aware_) {
throw exceptions::UnawareGoalHandleError();
}
@@ -70,7 +70,7 @@ template<typename ActionT>
void
ClientGoalHandle<ActionT>::set_result(const WrappedResult & wrapped_result)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
status_ = static_cast<int8_t>(wrapped_result.code);
result_promise_.set_value(wrapped_result);
if (result_callback_) {
@@ -82,7 +82,7 @@ template<typename ActionT>
void
ClientGoalHandle<ActionT>::set_feedback_callback(FeedbackCallback callback)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
feedback_callback_ = callback;
}
@@ -90,7 +90,7 @@ template<typename ActionT>
void
ClientGoalHandle<ActionT>::set_result_callback(ResultCallback callback)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
result_callback_ = callback;
}
@@ -98,7 +98,7 @@ template<typename ActionT>
int8_t
ClientGoalHandle<ActionT>::get_status()
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
return status_;
}
@@ -106,7 +106,7 @@ template<typename ActionT>
void
ClientGoalHandle<ActionT>::set_status(int8_t status)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
status_ = status;
}
@@ -114,7 +114,7 @@ template<typename ActionT>
bool
ClientGoalHandle<ActionT>::is_feedback_aware()
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
return feedback_callback_ != nullptr;
}
@@ -122,7 +122,7 @@ template<typename ActionT>
bool
ClientGoalHandle<ActionT>::is_result_aware()
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
return is_result_aware_;
}
@@ -130,7 +130,7 @@ template<typename ActionT>
bool
ClientGoalHandle<ActionT>::set_result_awareness(bool awareness)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
bool previous = is_result_aware_;
is_result_aware_ = awareness;
return previous;
@@ -140,7 +140,7 @@ template<typename ActionT>
void
ClientGoalHandle<ActionT>::invalidate(const exceptions::UnawareGoalHandleError & ex)
{
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
// Guard against multiple calls
if (is_invalidated()) {
return;
@@ -168,7 +168,7 @@ ClientGoalHandle<ActionT>::call_feedback_callback(
RCLCPP_ERROR(rclcpp::get_logger("rclcpp_action"), "Sent feedback to wrong goal handle.");
return;
}
std::lock_guard<std::mutex> guard(handle_mutex_);
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
if (nullptr == feedback_callback_) {
// Normal, some feedback messages may arrive after the goal result.
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp_action"), "Received feedback but goal ignores it.");

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_action</name>
<version>22.2.0</version>
<version>23.0.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -852,6 +852,86 @@ TEST_F(TestClientAgainstServer, async_cancel_some_goals_with_callback)
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_CANCELED, goal_handle0->get_status());
}
TEST_F(TestClientAgainstServer, deadlock_in_callbacks)
{
std::atomic<bool> feedback_callback_called = false;
std::atomic<bool> response_callback_called = false;
std::atomic<bool> result_callback_called = false;
std::atomic<bool> no_deadlock = false;
std::thread tr = std::thread(
[&]() {
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
ActionGoal goal;
using GoalHandle = rclcpp_action::ClientGoalHandle<ActionType>;
rclcpp_action::Client<ActionType>::SendGoalOptions ops;
ops.feedback_callback =
[&feedback_callback_called](const GoalHandle::SharedPtr handle,
ActionType::Feedback::ConstSharedPtr) {
// call functions on the handle that acquire the lock
handle->get_status();
handle->is_feedback_aware();
handle->is_result_aware();
feedback_callback_called = true;
};
ops.goal_response_callback = [&response_callback_called](
const GoalHandle::SharedPtr & handle) {
// call functions on the handle that acquire the lock
handle->get_status();
handle->is_feedback_aware();
handle->is_result_aware();
response_callback_called = true;
};
ops.result_callback = [&result_callback_called](
const GoalHandle::WrappedResult &) {
result_callback_called = true;
};
goal.order = 6;
auto future_goal_handle = action_client->async_send_goal(goal, ops);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
ASSERT_TRUE(goal_handle);
ASSERT_EQ(RCL_RET_OK, rcl_set_ros_time_override(clock.get_clock_handle(), RCL_S_TO_NS(2)));
auto result_future = action_client->async_get_result(goal_handle);
dual_spin_until_future_complete(result_future);
EXPECT_TRUE(result_future.valid());
auto result = result_future.get();
no_deadlock = true;
});
auto start_time = std::chrono::system_clock::now();
while (std::chrono::system_clock::now() - start_time < std::chrono::milliseconds(2000) &&
!no_deadlock)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (no_deadlock) {
tr.join();
} else {
// In case of a failure, the thread is assumed to be in a deadlock.
// We detach the thread so we don't block further tests.
tr.detach();
}
EXPECT_TRUE(no_deadlock);
EXPECT_TRUE(response_callback_called);
EXPECT_TRUE(result_callback_called);
EXPECT_TRUE(feedback_callback_called);
}
TEST_F(TestClientAgainstServer, send_rcl_errors)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);

View File

@@ -2,6 +2,11 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23.0.0 (2023-09-08)
-------------------
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* Contributors: Christophe Bedard
22.2.0 (2023-09-07)
-------------------

View File

@@ -2,7 +2,7 @@
Package containing tools for dynamically loadable components.
Visit the [rclcpp_components API documentation](http://docs.ros2.org/latest/api/rclcpp_components/) for a complete list of its main components and features.
The link to the latest rclcpp_components API documentation, which includes a complete list of its main components and features, can be found on the rclcpp_components package info page, at the [ROS Index](https://index.ros.org/p/rclcpp_components/).
## Quality Declaration

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_components</name>
<version>22.2.0</version>
<version>23.0.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -3,6 +3,11 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23.0.0 (2023-09-08)
-------------------
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* Contributors: Christophe Bedard
22.2.0 (2023-09-07)
-------------------
* add logger level service to lifecycle node. (`#2277 <https://github.com/ros2/rclcpp/issues/2277>`_)

View File

@@ -2,7 +2,8 @@
Package containing a prototype for lifecycle implementation.
Visit the [rclcpp_lifecycle API documentation](http://docs.ros2.org/latest/api/rclcpp_lifecycle/) for a complete list of its main components and features. For more information about LifeCycle in ROS 2, see the [design document](http://design.ros2.org/articles/node_lifecycle.html).
The link to the latest rclcpp_lifecycle API documentation, which includes a complete list of its main components and features, can be found on the rclcpp_lifecycle package info page, at the [ROS Index](https://index.ros.org/p/rclcpp_lifecycle/).
For more information about LifeCycle in ROS 2, see the [design document](http://design.ros2.org/articles/node_lifecycle.html).
## Quality Declaration

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_lifecycle</name>
<version>22.2.0</version>
<version>23.0.0</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>