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
1 change: 1 addition & 0 deletions rclcpp/include/rclcpp/executor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ class Executor
* that explicitly does not want to use the default implementation provided
* by this class.
*/
RCLCPP_PUBLIC
explicit Executor(const std::shared_ptr<rclcpp::Context> & context);

/// Add a node to executor, execute the next available unit of work, and remove the node.
Expand Down
12 changes: 8 additions & 4 deletions rclcpp/src/rclcpp/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ Executor::~Executor()
{
std::lock_guard<std::mutex> guard(mutex_);

notify_waitable_->remove_guard_condition(interrupt_guard_condition_);
notify_waitable_->remove_guard_condition(shutdown_guard_condition_);
// notify_waitable_ is null when a derived executor used the constructor that
// does not initialize the base functionality.
if (notify_waitable_) {
notify_waitable_->remove_guard_condition(interrupt_guard_condition_);
notify_waitable_->remove_guard_condition(shutdown_guard_condition_);
}
current_collection_.timers.update(
{}, {},
[this](auto timer) {wait_set_.remove_timer(std::move(timer));});
Expand All @@ -125,8 +129,8 @@ Executor::~Executor()
{}, {},
[this](auto waitable) {wait_set_.remove_waitable(std::move(waitable));});

// Remove shutdown callback handle registered to Context
if (!context_->remove_on_shutdown_callback(shutdown_callback_handle_)) {
// Remove shutdown callback handle registered to Context, if one was registered
if (notify_waitable_ && !context_->remove_on_shutdown_callback(shutdown_callback_handle_)) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to remove registered on_shutdown callback");
Expand Down
24 changes: 24 additions & 0 deletions rclcpp/test/rclcpp/test_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executor.hpp"
Expand Down Expand Up @@ -64,6 +65,21 @@ class DummyExecutor : public rclcpp::Executor
}
};

// Derived executor that uses the constructor which does not initialize the
// base class functionality.
class MinimalExecutor : public rclcpp::Executor
{
public:
MinimalExecutor()
: rclcpp::Executor(rclcpp::contexts::get_global_default_context())
{
}

void spin() override
{
}
};

class TestExecutor : public ::testing::Test
{
public:
Expand Down Expand Up @@ -117,6 +133,14 @@ TEST_F(TestExecutor, add_remove_node_thread_safe) {
future.get();
}

TEST_F(TestExecutor, destroy_executor_without_base_functionality) {
EXPECT_NO_THROW(
{
auto executor = std::make_unique<MinimalExecutor>();
executor.reset();
});
}

TEST_F(TestExecutor, constructor_bad_guard_condition_init) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_guard_condition_init, RCL_RET_ERROR);
Expand Down
Loading