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_);
163 }
catch (
const std::exception & exc) {
164 RCLCPP_ERROR(
rclcpp::get_logger(
"rclcpp"),
"unhandled exception in ~Context(): %s", exc.what());
177 rclcpp::get_logger(
"rclcpp"),
"rcl context unexpectedly not shutdown during cleanup");
184 "failed to finalize context: %s", rcl_get_error_string().str);
195 char const *
const * argv,
198 std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
205 throw std::runtime_error(
"failed to allocate memory for rcl context");
211 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to initialize rcl");
213 rcl_context_.reset(context, __delete_context);
217 logging_mutex_ = get_global_logging_mutex();
218 std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
219 size_t & count = get_logging_reference_count();
222 &rcl_context_->global_arguments,
224 rclcpp_logging_output_handler);
226 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to configure logging");
231 "logging was initialized more than once");
236 std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
238 if (!unparsed_ros_arguments.empty()) {
242 init_options_ = init_options;
244 weak_contexts_ = get_weak_contexts();
245 weak_contexts_->add_context(this->shared_from_this());
246 }
catch (
const std::exception & e) {
248 rcl_context_.reset();
250 std::ostringstream oss;
251 oss <<
"While handling: " << e.what() << std::endl <<
252 " another exception was thrown";
253 rclcpp::exceptions::throw_from_rcl_error(ret, oss.str());
263 auto local_rcl_context = rcl_context_;
264 if (!local_rcl_context) {
273 return init_options_;
279 return init_options_;
288 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to get domain id from context");
296 std::lock_guard<std::recursive_mutex> lock(init_mutex_);
297 return shutdown_reason_;
304 std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
313 std::lock_guard<std::recursive_mutex> lock{pre_shutdown_callbacks_mutex_};
317 auto cpy = pre_shutdown_callbacks_;
318 for (
const auto & callback : cpy) {
319 auto it = std::find(pre_shutdown_callbacks_.begin(), pre_shutdown_callbacks_.end(), callback);
320 if(it != pre_shutdown_callbacks_.end()) {
329 rclcpp::exceptions::throw_from_rcl_error(ret);
332 shutdown_reason_ = reason;
335 std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
339 auto cpy = on_shutdown_callbacks_;
340 for (
const auto & callback : cpy) {
341 auto it = std::find(on_shutdown_callbacks_.begin(), on_shutdown_callbacks_.end(), callback);
342 if(it != on_shutdown_callbacks_.end()) {
351 weak_contexts_->remove_context(
this);
353 if (logging_mutex_) {
355 std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
356 size_t & count = get_logging_reference_count();
360 RCUTILS_SAFE_FWRITE_TO_STDERR(
361 RCUTILS_STRINGIFY(__file__)
":"
362 RCUTILS_STRINGIFY(__LINE__)
363 " failed to fini logging");
371 rclcpp::Context::OnShutdownCallback
381 return add_shutdown_callback<ShutdownType::on_shutdown>(callback);
387 return remove_shutdown_callback<ShutdownType::on_shutdown>(callback_handle);
393 return add_shutdown_callback<ShutdownType::pre_shutdown>(callback);
400 return remove_shutdown_callback<ShutdownType::pre_shutdown>(callback_handle);
403 template<Context::ShutdownType shutdown_type>
405 Context::add_shutdown_callback(
406 ShutdownCallback callback)
408 auto callback_shared_ptr =
409 std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
412 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
414 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
415 std::lock_guard<std::recursive_mutex> lock(pre_shutdown_callbacks_mutex_);
416 pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
418 std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
419 on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
422 ShutdownCallbackHandle callback_handle;
423 callback_handle.callback = callback_shared_ptr;
424 return callback_handle;
427 template<Context::ShutdownType shutdown_type>
429 Context::remove_shutdown_callback(
430 const ShutdownCallbackHandle & callback_handle)
432 const auto callback_shared_ptr = callback_handle.callback.lock();
433 if (callback_shared_ptr ==
nullptr) {
437 const auto remove_callback = [&callback_shared_ptr](
auto & mutex,
auto & callback_vector) {
438 const std::lock_guard<std::recursive_mutex> lock(mutex);
439 auto iter = callback_vector.begin();
440 for (; iter != callback_vector.end(); iter++) {
441 if ((*iter).get() == callback_shared_ptr.get()) {
445 if (iter == callback_vector.end()) {
448 callback_vector.erase(iter);
453 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
455 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
456 return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
458 return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
462 std::vector<rclcpp::Context::OnShutdownCallback>
465 return get_shutdown_callback<ShutdownType::on_shutdown>();
468 std::vector<rclcpp::Context::PreShutdownCallback>
471 return get_shutdown_callback<ShutdownType::pre_shutdown>();
474 template<Context::ShutdownType shutdown_type>
475 std::vector<rclcpp::Context::ShutdownCallback>
476 Context::get_shutdown_callback()
const
478 const auto get_callback_vector = [](
auto & mutex,
auto & callback_set) {
479 const std::lock_guard<std::recursive_mutex> lock(mutex);
480 std::vector<rclcpp::Context::ShutdownCallback> callbacks;
481 for (
auto & callback : callback_set) {
482 callbacks.push_back(*callback);
488 shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
490 if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
491 return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
493 return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
497 std::shared_ptr<rcl_context_t>
506 std::chrono::nanoseconds time_left = nanoseconds;
509 std::unique_lock<std::mutex> lock(interrupt_mutex_);
510 auto start = std::chrono::steady_clock::now();
512 interrupt_condition_variable_.wait_for(lock, time_left);
513 time_left -= std::chrono::steady_clock::now() - start;
515 }
while (time_left > std::chrono::nanoseconds::zero() && this->
is_valid());
523 interrupt_condition_variable_.notify_all();
529 shutdown_reason_ =
"";
530 rcl_context_.reset();
531 sub_contexts_.clear();
534 std::vector<Context::SharedPtr>
537 WeakContextsWrapper::SharedPtr weak_contexts = get_weak_contexts();
538 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.
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.