Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,14 @@ class StaticExecutorEntitiesCollector final
void
init(
rcl_wait_set_t * p_wait_set,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr & memory_strategy,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy,
Comment thread
clalancette marked this conversation as resolved.
rcl_guard_condition_t * executor_guard_condition);

/// Finalize StaticExecutorEntitiesCollector to clear resources
RCLCPP_PUBLIC
void
fini();

RCLCPP_PUBLIC
void
execute() override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,16 @@ class StaticSingleThreadedExecutor : public rclcpp::Executor

entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);

rclcpp::FutureReturnCode ret = rclcpp::FutureReturnCode::INTERRUPTED;
while (rclcpp::ok(this->context_)) {
// Do one set of work.
entities_collector_->refresh_wait_set(timeout_left);
execute_ready_executables();
// Check if the future is set, return SUCCESS if it is.
status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return rclcpp::FutureReturnCode::SUCCESS;
ret = rclcpp::FutureReturnCode::SUCCESS;
break;
}
// If the original timeout is < 0, then this is blocking, never TIMEOUT.
if (timeout_ns < std::chrono::nanoseconds::zero()) {
Expand All @@ -210,14 +212,17 @@ class StaticSingleThreadedExecutor : public rclcpp::Executor
// Otherwise check if we still have time to wait, return TIMEOUT if not.
auto now = std::chrono::steady_clock::now();
if (now >= end_time) {
return rclcpp::FutureReturnCode::TIMEOUT;
ret = rclcpp::FutureReturnCode::TIMEOUT;
break;
}
// Subtract the elapsed time from the original timeout.
timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
}

entities_collector_->fini();

// The future did not complete before ok() returned false, return INTERRUPTED.
return rclcpp::FutureReturnCode::INTERRUPTED;
return ret;
}

/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ StaticExecutorEntitiesCollector::~StaticExecutorEntitiesCollector()
void
StaticExecutorEntitiesCollector::init(
rcl_wait_set_t * p_wait_set,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr & memory_strategy,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy,
rcl_guard_condition_t * executor_guard_condition)
{
// Empty initialize executable list
Expand All @@ -80,6 +80,13 @@ StaticExecutorEntitiesCollector::init(
execute();
}

void
StaticExecutorEntitiesCollector::fini()
{
memory_strategy_->clear_handles();
exec_list_.clear();
}

void
StaticExecutorEntitiesCollector::execute()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ StaticSingleThreadedExecutor::spin()
entities_collector_->refresh_wait_set();
execute_ready_executables();
}

entities_collector_->fini();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should fini also be called if an exception is thrown inside the while loop? That is, should this call be put in a SCOPE_EXIT block just after init(), or is it suitable just at the end here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that is a good idea I didn't think of earlier. It's pretty unlikely to happen (and if it did the test would fail, so a memory leak isn't the worst thing), but we may as well be complete while we are looking at it. @iuhilnehc-ynos do you mind making that last change?

Copy link
Copy Markdown
Collaborator Author

@iuhilnehc-ynos iuhilnehc-ynos Oct 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brawner

Thank you for pointing this.
Hmmm, I think I need to catch the exception to call fini() and then rethrow it,
and also update for using SCOPE_EXIT to call fini() in the test cases.

Edit: there exists RCLCPP_SCOPE_EXIT, I'll use it.

}

void
Expand Down
8 changes: 8 additions & 0 deletions rclcpp/test/rclcpp/executors/test_executors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ class TestWaitable : public rclcpp::Waitable
}
}

~TestWaitable()
{
rcl_ret_t ret = rcl_guard_condition_fini(&gc_);
if (RCL_RET_OK != ret) {
fprintf(stderr, "failed to call rcl_guard_condition_fini\n");
}
}

bool
add_to_wait_set(rcl_wait_set_t * wait_set) override
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, add_remove_basic_node) {

// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
entities_collector_->fini();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question for all these fini() calls. Should they go inside a SCOPE_EXIT block?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

}

TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_out_of_scope) {
Expand Down Expand Up @@ -224,6 +225,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_out_of_scope) {

// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
entities_collector_->fini();
}

class TestWaitable : public rclcpp::Waitable
Expand Down Expand Up @@ -303,6 +305,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_with_entities) {
EXPECT_EQ(0u, entities_collector_->get_number_of_clients());
// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, add_callback_group) {
Expand Down Expand Up @@ -365,7 +368,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_clear_
}

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_resize_error) {
Expand Down Expand Up @@ -395,7 +398,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_resize
}

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_not_initialized) {
Expand Down Expand Up @@ -432,7 +435,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_rcl_wait_failed) {
}

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_add_handles_to_wait_set_failed) {
Expand Down Expand Up @@ -483,7 +486,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_add_handles_to_wait
}

entities_collector_->remove_node(node->get_node_base_interface());
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, add_to_wait_set_nullptr) {
Expand Down Expand Up @@ -511,7 +514,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, add_to_wait_set_nullptr) {
rcl_reset_error();

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, fill_memory_strategy_invalid_group) {
Expand Down Expand Up @@ -543,7 +546,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, fill_memory_strategy_invalid_group)
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}

TEST_F(TestStaticExecutorEntitiesCollector, remove_callback_group_after_node) {
Expand Down Expand Up @@ -615,5 +618,5 @@ TEST_F(
entities_collector_->execute();

EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
entities_collector_->fini();
}