15 #include "rclcpp/context.hpp"
22 #include <unordered_set>
28 #include "rclcpp/detail/utilities.hpp"
29 #include "rclcpp/exceptions.hpp"
30 #include "rclcpp/logging.hpp"
32 #include "rcutils/error_handling.h"
33 #include "rcutils/macros.h"
35 #include "./logging_mutex.hpp"
48 add_context(
const Context::SharedPtr & context)
50 std::lock_guard<std::mutex> guard(mutex_);
51 weak_contexts_.push_back(context);
55 remove_context(
const Context * context)
57 std::lock_guard<std::mutex> guard(mutex_);
60 weak_contexts_.begin(),
62 [context](
const Context::WeakPtr weak_context) {
63 auto locked_context = weak_context.lock();
64 if (!locked_context) {
68 return locked_context.get() == context;
71 weak_contexts_.end());
74 std::vector<Context::SharedPtr>
77 std::lock_guard<std::mutex> lock(mutex_);
78 std::vector<Context::SharedPtr> shared_contexts;
79 for (
auto it = weak_contexts_.begin(); it != weak_contexts_.end(); ) {
80 auto context_ptr = it->lock();
83 it = weak_contexts_.erase(it);
86 shared_contexts.push_back(context_ptr);
89 return shared_contexts;
93 std::vector<std::weak_ptr<rclcpp::Context>> weak_contexts_;
102 WeakContextsWrapper::SharedPtr
105 static WeakContextsWrapper::SharedPtr weak_contexts = WeakContextsWrapper::make_shared();
106 if (!weak_contexts) {
107 throw std::runtime_error(
"weak contexts vector is not valid");
109 return weak_contexts;
115 get_logging_reference_count()
117 static size_t ref_count = 0;
125 rclcpp_logging_output_handler(
126 const rcutils_log_location_t * location,
127 int severity,
const char * name, rcutils_time_point_value_t timestamp,
128 const char * format, va_list * args)
131 std::shared_ptr<std::recursive_mutex> logging_mutex;
132 logging_mutex = get_global_logging_mutex();
133 std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
135 location, severity, name, timestamp, format, args);
136 }
catch (std::exception & ex) {
137 RCUTILS_SAFE_FWRITE_TO_STDERR(ex.what());
138 RCUTILS_SAFE_FWRITE_TO_STDERR(
"\n");
140 RCUTILS_SAFE_FWRITE_TO_STDERR(
"failed to take global rclcpp logging mutex\n");
146 : rcl_context_(nullptr),
147 shutdown_reason_(
""),
148 logging_mutex_(nullptr)
155 std::lock_guard<std::recursive_mutex> lock(init_mutex_);
157 this->
shutdown(
"context destructor was called while still not shutdown");
161 }
catch (
const std::exception & exc) {
162 RCLCPP_ERROR(
rclcpp::get_logger(
"rclcpp"),
"unhandled exception in ~Context(): %s", exc.what());
175 rclcpp::get_logger(
"rclcpp"),
"rcl context unexpectedly not shutdown during cleanup");
182 "failed to finalize context: %s", rcl_get_error_string().str);
193 char const *
const * argv,
196 std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
203 throw std::runtime_error(
"failed to allocate memory for rcl context");
209 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to initialize rcl");
211 rcl_context_.reset(context, __delete_context);
214 logging_mutex_ = get_global_logging_mutex();
215 std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
216 size_t & count = get_logging_reference_count();
219 &rcl_context_->global_arguments,
221 rclcpp_logging_output_handler);
223 rcl_context_.reset();
224 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to configure logging");
229 "logging was initialized more than once");
235 std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
237 if (!unparsed_ros_arguments.empty()) {
241 init_options_ = init_options;
243 weak_contexts_ = get_weak_contexts();
244 weak_contexts_->add_context(this->shared_from_this());
245 }
catch (
const std::exception & e) {
247 rcl_context_.reset();
249 std::ostringstream oss;
250 oss <<
"While handling: " << e.what() << std::endl <<
251 " another exception was thrown";
252 rclcpp::exceptions::throw_from_rcl_error(ret, oss.str());
262 auto local_rcl_context = rcl_context_;
263 if (!local_rcl_context) {
272 return init_options_;
278 return init_options_;
287 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to get domain id from context");
295 std::lock_guard<std::recursive_mutex> lock(init_mutex_);
296 return shutdown_reason_;
303 std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
312 std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
313 for (
const auto & callback : pre_shutdown_callbacks_) {
321 rclcpp::exceptions::throw_from_rcl_error(ret);
324 shutdown_reason_ = reason;
327 std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
328 for (
const auto & callback : on_shutdown_callbacks_) {
336 weak_contexts_->remove_context(
this);
338 if (logging_mutex_) {
340 std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
341 size_t & count = get_logging_reference_count();
345 RCUTILS_SAFE_FWRITE_TO_STDERR(
346 RCUTILS_STRINGIFY(__file__)
":"
347 RCUTILS_STRINGIFY(__LINE__)
348 " failed to fini logging");
356 rclcpp::Context::OnShutdownCallback
366 return add_shutdown_callback(ShutdownType::on_shutdown, callback);
372 return remove_shutdown_callback(ShutdownType::on_shutdown, callback_handle);
378 return add_shutdown_callback(ShutdownType::pre_shutdown, callback);
385 return remove_shutdown_callback(ShutdownType::pre_shutdown, callback_handle);
389 Context::add_shutdown_callback(
390 ShutdownType shutdown_type,
391 ShutdownCallback callback)
393 auto callback_shared_ptr =
394 std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
396 switch (shutdown_type) {
397 case ShutdownType::pre_shutdown:
399 std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
400 pre_shutdown_callbacks_.emplace(callback_shared_ptr);
403 case ShutdownType::on_shutdown:
405 std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
406 on_shutdown_callbacks_.emplace(callback_shared_ptr);
411 ShutdownCallbackHandle callback_handle;
412 callback_handle.callback = callback_shared_ptr;
413 return callback_handle;
417 Context::remove_shutdown_callback(
418 ShutdownType shutdown_type,
419 const ShutdownCallbackHandle & callback_handle)
421 std::mutex * mutex_ptr =
nullptr;
423 std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
425 switch (shutdown_type) {
426 case ShutdownType::pre_shutdown:
427 mutex_ptr = &pre_shutdown_callbacks_mutex_;
428 callback_list_ptr = &pre_shutdown_callbacks_;
430 case ShutdownType::on_shutdown:
431 mutex_ptr = &on_shutdown_callbacks_mutex_;
432 callback_list_ptr = &on_shutdown_callbacks_;
436 std::lock_guard<std::mutex> lock(*mutex_ptr);
437 auto callback_shared_ptr = callback_handle.callback.lock();
438 if (callback_shared_ptr ==
nullptr) {
441 return callback_list_ptr->erase(callback_shared_ptr) == 1;
444 std::vector<rclcpp::Context::OnShutdownCallback>
447 return get_shutdown_callback(ShutdownType::on_shutdown);
450 std::vector<rclcpp::Context::PreShutdownCallback>
453 return get_shutdown_callback(ShutdownType::pre_shutdown);
456 std::vector<rclcpp::Context::ShutdownCallback>
457 Context::get_shutdown_callback(ShutdownType shutdown_type)
const
459 std::mutex * mutex_ptr =
nullptr;
460 const std::unordered_set<
461 std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
463 switch (shutdown_type) {
464 case ShutdownType::pre_shutdown:
465 mutex_ptr = &pre_shutdown_callbacks_mutex_;
466 callback_list_ptr = &pre_shutdown_callbacks_;
468 case ShutdownType::on_shutdown:
469 mutex_ptr = &on_shutdown_callbacks_mutex_;
470 callback_list_ptr = &on_shutdown_callbacks_;
474 std::vector<rclcpp::Context::ShutdownCallback> callbacks;
476 std::lock_guard<std::mutex> lock(*mutex_ptr);
477 for (
auto & iter : *callback_list_ptr) {
478 callbacks.emplace_back(*iter);
485 std::shared_ptr<rcl_context_t>
494 std::chrono::nanoseconds time_left = nanoseconds;
497 std::unique_lock<std::mutex> lock(interrupt_mutex_);
498 auto start = std::chrono::steady_clock::now();
500 interrupt_condition_variable_.wait_for(lock, time_left);
501 time_left -= std::chrono::steady_clock::now() - start;
503 }
while (time_left > std::chrono::nanoseconds::zero() && this->
is_valid());
511 interrupt_condition_variable_.notify_all();
517 shutdown_reason_ =
"";
518 rcl_context_.reset();
519 sub_contexts_.clear();
522 std::vector<Context::SharedPtr>
525 WeakContextsWrapper::SharedPtr weak_contexts = get_weak_contexts();
526 return weak_contexts->get_contexts();
#define rcl_get_default_allocator
Return a properly initialized rcl_allocator_t with default values.
Thrown when init is called on an already initialized context.
Context which encapsulates shared state between nodes and other similar entities.
virtual RCLCPP_PUBLIC void init(int argc, char const *const *argv, const rclcpp::InitOptions &init_options=rclcpp::InitOptions())
Initialize the context, and the underlying elements like the rcl context.
RCLCPP_PUBLIC std::vector< OnShutdownCallback > get_on_shutdown_callbacks() const
Return the shutdown callbacks.
RCLCPP_PUBLIC std::vector< PreShutdownCallback > get_pre_shutdown_callbacks() const
Return the pre-shutdown callbacks.
RCLCPP_PUBLIC size_t get_domain_id() const
Return actual domain id.
RCLCPP_PUBLIC std::string shutdown_reason() const
Return the shutdown reason, or empty string if not shutdown.
RCLCPP_PUBLIC const rclcpp::InitOptions & get_init_options() const
Return the init options used during init.
RCLCPP_PUBLIC bool sleep_for(const std::chrono::nanoseconds &nanoseconds)
Sleep for a given period of time or until shutdown() is called.
virtual RCLCPP_PUBLIC void interrupt_all_sleep_for()
Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
virtual RCLCPP_PUBLIC OnShutdownCallback on_shutdown(OnShutdownCallback callback)
Add a on_shutdown callback to be called when shutdown is called for this context.
virtual RCLCPP_PUBLIC OnShutdownCallbackHandle add_on_shutdown_callback(OnShutdownCallback callback)
Add a on_shutdown callback to be called when shutdown is called for this context.
virtual RCLCPP_PUBLIC bool remove_pre_shutdown_callback(const PreShutdownCallbackHandle &callback_handle)
Remove an registered pre_shutdown callback.
RCLCPP_PUBLIC bool is_valid() const
Return true if the context is valid, otherwise false.
virtual RCLCPP_PUBLIC PreShutdownCallbackHandle add_pre_shutdown_callback(PreShutdownCallback callback)
Add a pre_shutdown callback to be called before shutdown is called for this context.
virtual RCLCPP_PUBLIC bool remove_on_shutdown_callback(const OnShutdownCallbackHandle &callback_handle)
Remove an registered on_shutdown callbacks.
virtual RCLCPP_PUBLIC bool shutdown(const std::string &reason)
Shutdown the context, making it uninitialized and therefore invalid for derived entities.
RCLCPP_PUBLIC std::shared_ptr< rcl_context_t > get_rcl_context()
Return the internal rcl context.
Encapsulation of options for initializing rclcpp.
RCLCPP_PUBLIC const rcl_init_options_t * get_rcl_init_options() const
Return the rcl init options.
RCLCPP_PUBLIC bool auto_initialize_logging() const
Return true if logging should be initialized when rclcpp::Context::init is called.
Class to manage vector of weak pointers to all created contexts.
Thrown when unparsed ROS specific arguments are found.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_context_fini(rcl_context_t *context)
Finalize a context.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_context_get_domain_id(rcl_context_t *context, size_t *domain_id)
Returns the context domain id.
struct rcl_context_s rcl_context_t
Encapsulates the non-global state of an init/shutdown cycle.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_context_is_valid(const rcl_context_t *context)
Return true if the given context is currently valid, otherwise false.
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_t rcl_get_zero_initialized_context(void)
Return a zero initialization context object.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_shutdown(rcl_context_t *context)
Shutdown a given rcl context.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_init(int argc, char const *const *argv, const rcl_init_options_t *options, rcl_context_t *context)
Initialization of rcl.
RCL_PUBLIC RCL_WARN_UNUSED const rcl_allocator_t * rcl_init_options_get_allocator(const rcl_init_options_t *init_options)
Return the allocator stored in the init_options.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_fini(void)
RCL_PUBLIC void rcl_logging_multiple_output_handler(const rcutils_log_location_t *location, int severity, const char *name, rcutils_time_point_value_t timestamp, const char *format, va_list *args)
Default output handler used by rcl.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_configure_with_output_handler(const rcl_arguments_t *global_args, const rcl_allocator_t *allocator, rcl_logging_output_handler_t output_handler)
Configure the logging system with the provided output handler.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::vector< Context::SharedPtr > get_contexts()
Return a copy of the list of context shared pointers.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Encapsulates the non-global state of an init/shutdown cycle.
#define RCL_RET_OK
Success return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.