Skip to content

Commit 5622f7e

Browse files
facontidavideclaude
andcommitted
fix(StatusChangeLogger): release mutex before calling user callback
Prevent recursive mutex locking when multiple nodes change status during a single tree tick. The callback lambda now copies state under the lock, releases it, then calls user code. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cb33b3a commit 5622f7e

1 file changed

Lines changed: 14 additions & 8 deletions

File tree

include/behaviortree_cpp/loggers/abstract_logger.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,24 @@ inline void StatusChangeLogger::subscribeToTreeChanges(TreeNode* root_node)
8686

8787
auto subscribeCallback = [this](TimePoint timestamp, const TreeNode& node,
8888
NodeStatus prev, NodeStatus status) {
89-
std::unique_lock lk(callback_mutex_);
90-
if(enabled_ && (status != NodeStatus::IDLE || show_transition_to_idle_))
89+
// Copy state under lock, then release before calling user code
90+
// This prevents recursive mutex locking when multiple nodes change status
91+
bool should_callback = false;
92+
Duration adjusted_timestamp;
9193
{
92-
if(type_ == TimestampType::absolute)
94+
std::unique_lock lk(callback_mutex_);
95+
if(enabled_ && (status != NodeStatus::IDLE || show_transition_to_idle_))
9396
{
94-
this->callback(timestamp.time_since_epoch(), node, prev, status);
95-
}
96-
else
97-
{
98-
this->callback(timestamp - first_timestamp_, node, prev, status);
97+
should_callback = true;
98+
adjusted_timestamp = (type_ == TimestampType::absolute) ?
99+
timestamp.time_since_epoch() :
100+
(timestamp - first_timestamp_);
99101
}
100102
}
103+
if(should_callback)
104+
{
105+
this->callback(adjusted_timestamp, node, prev, status);
106+
}
101107
};
102108

103109
auto visitor = [this, subscribeCallback](TreeNode* node) {

0 commit comments

Comments
 (0)