1414
1515#include " rclcpp/context.hpp"
1616
17+ #include < map>
1718#include < memory>
1819#include < mutex>
1920#include < sstream>
@@ -142,11 +143,52 @@ rclcpp_logging_output_handler(
142143}
143144} // extern "C"
144145
146+ /* *
147+ * Global storage for pre and post shutdown recursive mutexes.
148+ * Note, this is a ABI compatibility hack.
149+ */
150+ class MutexLookup
151+ {
152+ std::mutex m;
153+
154+ struct MutexHolder
155+ {
156+ std::recursive_mutex on_shutdown_callbacks_mutex_;
157+ std::recursive_mutex pre_shutdown_callbacks_mutex_;
158+ };
159+
160+ std::map<const Context *, std::unique_ptr<MutexHolder>> mutexMap;
161+
162+ public:
163+ MutexHolder & getMutexes (const Context *forContext)
164+ {
165+ auto it = mutexMap.find (forContext);
166+ if (it == mutexMap.end ()) {
167+ it = mutexMap.emplace (forContext, std::make_unique<MutexHolder>()).first ;
168+ }
169+
170+ return *(it->second );
171+ }
172+
173+ /* *
174+ * Only supposed to be called on deletion of context
175+ */
176+ void removeMutexes (const Context *forContext)
177+ {
178+ mutexMap.erase (forContext);
179+ }
180+ };
181+
182+ MutexLookup mutexStorage;
183+
145184Context::Context ()
146185: rcl_context_(nullptr ),
147186 shutdown_reason_(" " ),
148187 logging_mutex_(nullptr )
149- {}
188+ {
189+ // allocate mutexes
190+ mutexStorage.getMutexes (this );
191+ }
150192
151193Context::~Context ()
152194{
@@ -165,6 +207,9 @@ Context::~Context()
165207 } catch (...) {
166208 RCLCPP_ERROR (rclcpp::get_logger (" rclcpp" ), " unhandled exception in ~Context()" );
167209 }
210+
211+ // delete mutexes
212+ mutexStorage.removeMutexes (this );
168213}
169214
170215RCLCPP_LOCAL
@@ -311,9 +356,17 @@ Context::shutdown(const std::string & reason)
311356
312357 // call each pre-shutdown callback
313358 {
314- std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
315- for (const auto & callback : pre_shutdown_callbacks_) {
316- (*callback)();
359+ std::lock_guard<std::recursive_mutex> lock{mutexStorage.getMutexes (
360+ this ).pre_shutdown_callbacks_mutex_ };
361+ // callbacks may delete other callbacks during the execution,
362+ // therefore we need to save a copy and check before execution
363+ // if the next callback is still present
364+ auto cpy = pre_shutdown_callbacks_;
365+ for (const auto & callback : cpy) {
366+ auto it = std::find (pre_shutdown_callbacks_.begin (), pre_shutdown_callbacks_.end (), callback);
367+ if (it != pre_shutdown_callbacks_.end ()) {
368+ (*callback)();
369+ }
317370 }
318371 }
319372
@@ -326,9 +379,17 @@ Context::shutdown(const std::string & reason)
326379 shutdown_reason_ = reason;
327380 // call each shutdown callback
328381 {
329- std::lock_guard<std::mutex> lock (on_shutdown_callbacks_mutex_);
330- for (const auto & callback : on_shutdown_callbacks_) {
331- (*callback)();
382+ std::lock_guard<std::recursive_mutex> lock (mutexStorage.getMutexes (
383+ this ).on_shutdown_callbacks_mutex_ );
384+ // callbacks may delete other callbacks during the execution,
385+ // therefore we need to save a copy and check before execution
386+ // if the next callback is still present
387+ auto cpy = on_shutdown_callbacks_;
388+ for (const auto & callback : cpy) {
389+ auto it = std::find (on_shutdown_callbacks_.begin (), on_shutdown_callbacks_.end (), callback);
390+ if (it != on_shutdown_callbacks_.end ()) {
391+ (*callback)();
392+ }
332393 }
333394 }
334395
@@ -399,10 +460,12 @@ Context::add_shutdown_callback(
399460 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
400461
401462 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
402- std::lock_guard<std::mutex> lock (pre_shutdown_callbacks_mutex_);
463+ std::lock_guard<std::recursive_mutex> lock (mutexStorage.getMutexes (
464+ this ).pre_shutdown_callbacks_mutex_ );
403465 pre_shutdown_callbacks_.emplace_back (callback_shared_ptr);
404466 } else {
405- std::lock_guard<std::mutex> lock (on_shutdown_callbacks_mutex_);
467+ std::lock_guard<std::recursive_mutex> lock (mutexStorage.getMutexes (
468+ this ).on_shutdown_callbacks_mutex_ );
406469 on_shutdown_callbacks_.emplace_back (callback_shared_ptr);
407470 }
408471
@@ -422,7 +485,7 @@ Context::remove_shutdown_callback(
422485 }
423486
424487 const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
425- const std::lock_guard<std::mutex > lock (mutex);
488+ const std::lock_guard<std::recursive_mutex > lock (mutex);
426489 auto iter = callback_vector.begin ();
427490 for (; iter != callback_vector.end (); iter++) {
428491 if ((*iter).get () == callback_shared_ptr.get ()) {
@@ -433,16 +496,19 @@ Context::remove_shutdown_callback(
433496 return false ;
434497 }
435498 callback_vector.erase (iter);
499+
436500 return true ;
437501 };
438502
439503 static_assert (
440504 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
441505
442506 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
443- return remove_callback (pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
507+ return remove_callback (mutexStorage.getMutexes (this ).pre_shutdown_callbacks_mutex_ ,
508+ pre_shutdown_callbacks_);
444509 } else {
445- return remove_callback (on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
510+ return remove_callback (mutexStorage.getMutexes (this ).on_shutdown_callbacks_mutex_ ,
511+ on_shutdown_callbacks_);
446512 }
447513}
448514
@@ -463,7 +529,7 @@ std::vector<rclcpp::Context::ShutdownCallback>
463529Context::get_shutdown_callback () const
464530{
465531 const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
466- const std::lock_guard<std::mutex > lock (mutex);
532+ const std::lock_guard<std::recursive_mutex > lock (mutex);
467533 std::vector<rclcpp::Context::ShutdownCallback> callbacks;
468534 for (auto & callback : callback_set) {
469535 callbacks.push_back (*callback);
@@ -475,9 +541,11 @@ Context::get_shutdown_callback() const
475541 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
476542
477543 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
478- return get_callback_vector (pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
544+ return get_callback_vector (mutexStorage.getMutexes (this ).pre_shutdown_callbacks_mutex_ ,
545+ pre_shutdown_callbacks_);
479546 } else {
480- return get_callback_vector (on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
547+ return get_callback_vector (mutexStorage.getMutexes (this ).on_shutdown_callbacks_mutex_ ,
548+ on_shutdown_callbacks_);
481549 }
482550}
483551
0 commit comments