Skip to content

Commit

Permalink
fix(start/goal_planner): fix multi thread memory crash (autowarefound…
Browse files Browse the repository at this point in the history
…ation#6322)

Signed-off-by: kosuke55 <kosuke.tnp@gmail.com>
  • Loading branch information
kosuke55 committed Feb 6, 2024
1 parent c6cbd0a commit 8c0de1c
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <autoware_auto_planning_msgs/msg/path_with_lane_id.hpp>
#include <autoware_auto_vehicle_msgs/msg/hazard_lights_command.hpp>

#include <atomic>
#include <deque>
#include <limits>
#include <memory>
Expand Down Expand Up @@ -290,6 +291,35 @@ class GoalPlannerModule : public SceneModuleInterface
std::unordered_map<std::string, std::shared_ptr<ObjectsOfInterestMarkerInterface>> &
objects_of_interest_marker_interface_ptr_map);

~GoalPlannerModule()
{
if (lane_parking_timer_) {
lane_parking_timer_->cancel();
}
if (freespace_parking_timer_) {
freespace_parking_timer_->cancel();
}

while (is_lane_parking_cb_running_.load() || is_freespace_parking_cb_running_.load()) {
const std::string running_callbacks = std::invoke([&]() {
if (is_lane_parking_cb_running_ && is_freespace_parking_cb_running_) {
return "lane parking and freespace parking";
}
if (is_lane_parking_cb_running_) {
return "lane parking";
}
return "freespace parking";
});
RCLCPP_INFO_THROTTLE(
getLogger(), *clock_, 1000, "Waiting for %s callback to finish...",
running_callbacks.c_str());
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

RCLCPP_INFO_THROTTLE(
getLogger(), *clock_, 1000, "lane parking and freespace parking callbacks finished");
}

void updateModuleParams(const std::any & parameters) override
{
parameters_ = std::any_cast<std::shared_ptr<GoalPlannerParameters>>(parameters);
Expand Down Expand Up @@ -330,6 +360,18 @@ class GoalPlannerModule : public SceneModuleInterface
CandidateOutput planCandidate() const override { return CandidateOutput{}; }

private:
// Flag class for managing whether a certain callback is running in multi-threading
class ScopedFlag
{
public:
explicit ScopedFlag(std::atomic<bool> & flag) : flag_(flag) { flag_.store(true); }

~ScopedFlag() { flag_.store(false); }

private:
std::atomic<bool> & flag_;
};

/*
* state transitions and plan function used in each state
*
Expand Down Expand Up @@ -404,10 +446,12 @@ class GoalPlannerModule : public SceneModuleInterface
// pre-generate lane parking paths in a separate thread
rclcpp::TimerBase::SharedPtr lane_parking_timer_;
rclcpp::CallbackGroup::SharedPtr lane_parking_timer_cb_group_;
std::atomic<bool> is_lane_parking_cb_running_;

// generate freespace parking paths in a separate thread
rclcpp::TimerBase::SharedPtr freespace_parking_timer_;
rclcpp::CallbackGroup::SharedPtr freespace_parking_timer_cb_group_;
std::atomic<bool> is_freespace_parking_cb_running_;

// debug
mutable GoalPlannerDebugData debug_data_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ GoalPlannerModule::GoalPlannerModule(
parameters_{parameters},
vehicle_info_{vehicle_info_util::VehicleInfoUtil(node).getVehicleInfo()},
thread_safe_data_{mutex_, clock_},
is_lane_parking_cb_running_{false},
is_freespace_parking_cb_running_{false},
debug_stop_pose_with_info_{&stop_pose_}
{
LaneDepartureChecker lane_departure_checker{};
Expand Down Expand Up @@ -171,6 +173,8 @@ bool GoalPlannerModule::hasDeviatedFromCurrentPreviousModulePath() const
// generate pull over candidate paths
void GoalPlannerModule::onTimer()
{
const ScopedFlag flag(is_lane_parking_cb_running_);

if (getCurrentStatus() == ModuleStatus::IDLE) {
return;
}
Expand Down Expand Up @@ -287,6 +291,8 @@ void GoalPlannerModule::onTimer()

void GoalPlannerModule::onFreespaceParkingTimer()
{
const ScopedFlag flag(is_freespace_parking_cb_running_);

if (getCurrentStatus() == ModuleStatus::IDLE) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include <tf2/utils.h>

#include <atomic>
#include <deque>
#include <memory>
#include <string>
Expand Down Expand Up @@ -83,6 +84,21 @@ class StartPlannerModule : public SceneModuleInterface
std::unordered_map<std::string, std::shared_ptr<ObjectsOfInterestMarkerInterface>> &
objects_of_interest_marker_interface_ptr_map);

~StartPlannerModule()
{
if (freespace_planner_timer_) {
freespace_planner_timer_->cancel();
}

while (is_freespace_planner_cb_running_.load()) {
RCLCPP_INFO_THROTTLE(
getLogger(), *clock_, 1000, "Waiting for freespace planner callback to finish...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

RCLCPP_INFO_THROTTLE(getLogger(), *clock_, 1000, "freespace planner callback finished");
}

void updateModuleParams(const std::any & parameters) override
{
parameters_ = std::any_cast<std::shared_ptr<StartPlannerParameters>>(parameters);
Expand Down Expand Up @@ -135,6 +151,18 @@ class StartPlannerModule : public SceneModuleInterface
bool isFreespacePlanning() const { return status_.planner_type == PlannerType::FREESPACE; }

private:
// Flag class for managing whether a certain callback is running in multi-threading
class ScopedFlag
{
public:
explicit ScopedFlag(std::atomic<bool> & flag) : flag_(flag) { flag_.store(true); }

~ScopedFlag() { flag_.store(false); }

private:
std::atomic<bool> & flag_;
};

bool canTransitSuccessState() override;

bool canTransitFailureState() override { return false; }
Expand Down Expand Up @@ -202,6 +230,8 @@ class StartPlannerModule : public SceneModuleInterface
std::unique_ptr<PullOutPlannerBase> freespace_planner_;
rclcpp::TimerBase::SharedPtr freespace_planner_timer_;
rclcpp::CallbackGroup::SharedPtr freespace_planner_timer_cb_group_;
std::atomic<bool> is_freespace_planner_cb_running_;

// TODO(kosuke55)
// Currently, we only do lock when updating a member of status_.
// However, we need to ensure that the value does not change when referring to it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ StartPlannerModule::StartPlannerModule(
objects_of_interest_marker_interface_ptr_map)
: SceneModuleInterface{name, node, rtc_interface_ptr_map, objects_of_interest_marker_interface_ptr_map}, // NOLINT
parameters_{parameters},
vehicle_info_{vehicle_info_util::VehicleInfoUtil(node).getVehicleInfo()}
vehicle_info_{vehicle_info_util::VehicleInfoUtil(node).getVehicleInfo()},
is_freespace_planner_cb_running_{false}
{
lane_departure_checker_ = std::make_shared<LaneDepartureChecker>();
lane_departure_checker_->setVehicleInfo(vehicle_info_);
Expand Down Expand Up @@ -85,6 +86,8 @@ StartPlannerModule::StartPlannerModule(

void StartPlannerModule::onFreespacePlannerTimer()
{
const ScopedFlag flag(is_freespace_planner_cb_running_);

if (getCurrentStatus() == ModuleStatus::IDLE) {
return;
}
Expand Down

0 comments on commit 8c0de1c

Please sign in to comment.