ROS 2 rclcpp + rcl - rolling  rolling-e47c0848
ROS 2 C++ Client Library with ROS Client Library
context.cpp
1 // Copyright 2015-2020 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "rclcpp/context.hpp"
16 
17 #include <memory>
18 #include <mutex>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 #include <unordered_set>
23 #include <utility>
24 
25 #include "rcl/init.h"
26 #include "rcl/logging.h"
27 
28 #include "rclcpp/detail/utilities.hpp"
29 #include "rclcpp/exceptions.hpp"
30 #include "rclcpp/logging.hpp"
31 #include "rclcpp/graph_listener.hpp"
32 #include "rcutils/error_handling.h"
33 #include "rcutils/macros.h"
34 
35 #include "./logging_mutex.hpp"
36 
37 using rclcpp::Context;
38 
39 namespace rclcpp
40 {
43 {
44 public:
45  RCLCPP_SMART_PTR_DEFINITIONS(WeakContextsWrapper)
46 
47  void
48  add_context(const Context::SharedPtr & context)
49  {
50  std::lock_guard<std::mutex> guard(mutex_);
51  weak_contexts_.push_back(context);
52  }
53 
54  void
55  remove_context(const Context * context)
56  {
57  std::lock_guard<std::mutex> guard(mutex_);
58  weak_contexts_.erase(
59  std::remove_if(
60  weak_contexts_.begin(),
61  weak_contexts_.end(),
62  [context](const Context::WeakPtr & weak_context) {
63  auto locked_context = weak_context.lock();
64  if (!locked_context) {
65  // take advantage and removed expired contexts
66  return true;
67  }
68  return locked_context.get() == context;
69  }
70  ),
71  weak_contexts_.end());
72  }
73 
74  std::vector<Context::SharedPtr>
75  get_contexts()
76  {
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(); /* noop */) {
80  auto context_ptr = it->lock();
81  if (!context_ptr) {
82  // remove invalid weak context pointers
83  it = weak_contexts_.erase(it);
84  } else {
85  ++it;
86  shared_contexts.push_back(context_ptr);
87  }
88  }
89  return shared_contexts;
90  }
91 
92 private:
93  std::vector<std::weak_ptr<rclcpp::Context>> weak_contexts_;
94  std::mutex mutex_;
95 };
96 } // namespace rclcpp
97 
99 
101 static
102 WeakContextsWrapper::SharedPtr
103 get_weak_contexts()
104 {
105  static WeakContextsWrapper::SharedPtr weak_contexts = WeakContextsWrapper::make_shared();
106  if (!weak_contexts) {
107  throw std::runtime_error("weak contexts vector is not valid");
108  }
109  return weak_contexts;
110 }
111 
113 static
114 size_t &
115 get_logging_reference_count()
116 {
117  static size_t ref_count = 0;
118  return ref_count;
119 }
120 
121 extern "C"
122 {
123 static
124 void
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)
129 {
130  try {
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");
139  } catch (...) {
140  RCUTILS_SAFE_FWRITE_TO_STDERR("failed to take global rclcpp logging mutex\n");
141  }
142 }
143 } // extern "C"
144 
145 Context::Context()
146 : rcl_context_(nullptr),
147  shutdown_reason_(""),
148  logging_mutex_(nullptr),
149  graph_listener_(nullptr)
150 {}
151 
152 Context::~Context()
153 {
154  // acquire the init lock to prevent race conditions with init and shutdown
155  // this will not prevent errors, but will maybe make them easier to reproduce
156  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
157  try {
158  // Cannot rely on virtual dispatch in a destructor, so explicitly use the
159  // shutdown() provided by this base class.
160  Context::shutdown("context destructor was called while still not shutdown");
161  // at this point it is shutdown and cannot reinit
162  // clean_up will finalize the rcl context
163  this->clean_up();
164  } catch (const std::exception & exc) {
165  RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context(): %s", exc.what());
166  } catch (...) {
167  RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
168  }
169 }
170 
171 RCLCPP_LOCAL
172 void
173 __delete_context(rcl_context_t * context)
174 {
175  if (context) {
176  if (rcl_context_is_valid(context)) {
177  RCLCPP_ERROR(
178  rclcpp::get_logger("rclcpp"), "rcl context unexpectedly not shutdown during cleanup");
179  } else {
180  // if context pointer is not null and is shutdown, then it's ready for fini
181  rcl_ret_t ret = rcl_context_fini(context);
182  if (RCL_RET_OK != ret) {
183  RCLCPP_ERROR(
184  rclcpp::get_logger("rclcpp"),
185  "failed to finalize context: %s", rcl_get_error_string().str);
186  rcl_reset_error();
187  }
188  }
189  delete context;
190  }
191 }
192 
193 void
195  int argc,
196  char const * const * argv,
197  const rclcpp::InitOptions & init_options)
198 {
199  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
200  if (this->is_valid()) {
202  }
203  this->clean_up();
204  // allow shutdown() to be called again after re-initialization
205  is_shutting_down_.store(false);
206  rcl_context_t * context = new rcl_context_t;
207  if (!context) {
208  throw std::runtime_error("failed to allocate memory for rcl context");
209  }
211  rcl_ret_t ret = rcl_init(argc, argv, init_options.get_rcl_init_options(), context);
212  if (RCL_RET_OK != ret) {
213  delete context;
214  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to initialize rcl");
215  }
216  rcl_context_.reset(context, __delete_context);
217 
218  try {
219  if (init_options.auto_initialize_logging()) {
220  logging_mutex_ = get_global_logging_mutex();
221  std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
222  size_t & count = get_logging_reference_count();
223  if (0u == count) {
225  &rcl_context_->global_arguments,
227  rclcpp_logging_output_handler);
228  if (RCL_RET_OK != ret) {
229  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
230  }
231  } else {
232  RCLCPP_WARN(
233  rclcpp::get_logger("rclcpp"),
234  "logging was initialized more than once");
235  }
236  ++count;
237  }
238 
239  std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
240  argc, argv, &(rcl_context_->global_arguments), rcl_get_default_allocator());
241  if (!unparsed_ros_arguments.empty()) {
242  throw exceptions::UnknownROSArgsError(std::move(unparsed_ros_arguments));
243  }
244 
245  init_options_ = init_options;
246 
247  weak_contexts_ = get_weak_contexts();
248  weak_contexts_->add_context(this->shared_from_this());
249 
250 
251  std::lock_guard<std::recursive_mutex> lock (on_shutdown_callbacks_mutex_);
252 
253  graph_listener_ = std::make_shared<graph_listener::GraphListener>(shared_from_this());
254 
255  if (!graph_listener_->is_started()) {
256  // Register an on_shutdown hook to shutdown the graph listener.
257  // This is important to ensure that the wait set is finalized before
258  // destruction of static objects occurs.
259  std::weak_ptr<rclcpp::graph_listener::GraphListener> weak_graph_listener = graph_listener_;
260  on_shutdown ([weak_graph_listener]() {
261  auto shared_graph_listener = weak_graph_listener.lock();
262  if(shared_graph_listener) {
263  shared_graph_listener->shutdown(std::nothrow);
264  }
265  });
266  }
267  } catch (const std::exception & e) {
268  ret = rcl_shutdown(rcl_context_.get());
269  rcl_context_.reset();
270  if (RCL_RET_OK != ret) {
271  std::ostringstream oss;
272  oss << "While handling: " << e.what() << std::endl <<
273  " another exception was thrown";
274  rclcpp::exceptions::throw_from_rcl_error(ret, oss.str());
275  }
276  throw;
277  }
278 }
279 
280 bool
282 {
283  // Take a local copy of the shared pointer to avoid it getting nulled under our feet.
284  auto local_rcl_context = rcl_context_;
285  if (!local_rcl_context) {
286  return false;
287  }
288  return rcl_context_is_valid(local_rcl_context.get());
289 }
290 
291 const rclcpp::InitOptions &
293 {
294  return init_options_;
295 }
296 
299 {
300  return init_options_;
301 }
302 
303 size_t
305 {
306  size_t domain_id;
307  rcl_ret_t ret = rcl_context_get_domain_id(rcl_context_.get(), &domain_id);
308  if (RCL_RET_OK != ret) {
309  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to get domain id from context");
310  }
311  return domain_id;
312 }
313 
314 std::string
316 {
317  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
318  return shutdown_reason_;
319 }
320 
321 bool
322 Context::shutdown(const std::string & reason)
323 {
324  // Prevent double-shutdown: the signal handler thread and the main thread
325  // may both call shutdown() during Ctrl-C. Use an atomic flag to ensure
326  // only the first call proceeds; subsequent calls return immediately.
327  if (is_shutting_down_.exchange(true)) {
328  return false;
329  }
330  // prevent races
331  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
332  // ensure validity
333  if (!this->is_valid()) {
334  // if it is not valid, then it cannot be shutdown
335  return false;
336  }
337 
338  // call each pre-shutdown callback
339  {
340  std::lock_guard<std::recursive_mutex> lock{pre_shutdown_callbacks_mutex_};
341  // callbacks may delete other callbacks during the execution,
342  // therefore we need to save a copy and check before execution
343  // if the next callback is still present
344  auto cpy = pre_shutdown_callbacks_;
345  for (const auto & callback : cpy) {
346  auto it = std::find(pre_shutdown_callbacks_.begin(), pre_shutdown_callbacks_.end(), callback);
347  if(it != pre_shutdown_callbacks_.end()) {
348  (*callback)();
349  }
350  }
351  }
352 
353  // rcl shutdown
354  rcl_ret_t ret = rcl_shutdown(rcl_context_.get());
355  if (RCL_RET_OK != ret) {
356  rclcpp::exceptions::throw_from_rcl_error(ret);
357  }
358  // set shutdown reason
359  shutdown_reason_ = reason;
360  // call each shutdown callback
361  {
362  std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
363  // callbacks may delete other callbacks during the execution,
364  // therefore we need to save a copy and check before execution
365  // if the next callback is still present
366  auto cpy = on_shutdown_callbacks_;
367  for (const auto & callback : cpy) {
368  auto it = std::find(on_shutdown_callbacks_.begin(), on_shutdown_callbacks_.end(), callback);
369  if(it != on_shutdown_callbacks_.end()) {
370  (*callback)();
371  }
372  }
373  }
374 
375  // interrupt all blocking sleep_for() and all blocking executors or wait sets
376  this->interrupt_all_sleep_for();
377  // remove self from the global contexts
378  weak_contexts_->remove_context(this);
379  // shutdown logger
380  if (logging_mutex_) {
381  // logging was initialized by this context
382  std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
383  size_t & count = get_logging_reference_count();
384  if (0u == --count) {
385  rcl_ret_t rcl_ret = rcl_logging_fini();
386  if (RCL_RET_OK != rcl_ret) {
387  RCUTILS_SAFE_FWRITE_TO_STDERR(
388  RCUTILS_STRINGIFY(__file__) ":"
389  RCUTILS_STRINGIFY(__LINE__)
390  " failed to fini logging");
391  rcl_reset_error();
392  }
393  }
394  }
395  return true;
396 }
397 
398 rclcpp::Context::OnShutdownCallback
399 Context::on_shutdown(const OnShutdownCallback & callback)
400 {
401  add_on_shutdown_callback(callback);
402  return callback;
403 }
404 
406 Context::add_on_shutdown_callback(const OnShutdownCallback & callback)
407 {
408  return add_shutdown_callback<ShutdownType::on_shutdown>(callback);
409 }
410 
411 bool
413 {
414  return remove_shutdown_callback<ShutdownType::on_shutdown>(callback_handle);
415 }
416 
418 Context::add_pre_shutdown_callback(const PreShutdownCallback & callback)
419 {
420  return add_shutdown_callback<ShutdownType::pre_shutdown>(callback);
421 }
422 
423 bool
425  const PreShutdownCallbackHandle & callback_handle)
426 {
427  return remove_shutdown_callback<ShutdownType::pre_shutdown>(callback_handle);
428 }
429 
430 template<Context::ShutdownType shutdown_type>
432 Context::add_shutdown_callback(
433  const ShutdownCallback & callback)
434 {
435  auto callback_shared_ptr =
436  std::make_shared<rclcpp::ShutdownCallbackHandle::ShutdownCallbackType>(callback);
437 
438  static_assert(
439  shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
440 
441  if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
442  std::lock_guard<std::recursive_mutex> lock(pre_shutdown_callbacks_mutex_);
443  pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
444  } else {
445  std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
446  on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
447  }
448 
449  rclcpp::ShutdownCallbackHandle callback_handle;
450  callback_handle.callback = callback_shared_ptr;
451  return callback_handle;
452 }
453 
454 template<Context::ShutdownType shutdown_type>
455 bool
456 Context::remove_shutdown_callback(
457  const rclcpp::ShutdownCallbackHandle & callback_handle)
458 {
459  const auto callback_shared_ptr = callback_handle.callback.lock();
460  if (callback_shared_ptr == nullptr) {
461  return false;
462  }
463 
464  const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
465  const std::lock_guard<std::recursive_mutex> lock(mutex);
466  auto iter = callback_vector.begin();
467  for (; iter != callback_vector.end(); iter++) {
468  if ((*iter).get() == callback_shared_ptr.get()) {
469  break;
470  }
471  }
472  if (iter == callback_vector.end()) {
473  return false;
474  }
475  callback_vector.erase(iter);
476  return true;
477  };
478 
479  static_assert(
480  shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
481 
482  if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
483  return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
484  } else {
485  return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
486  }
487 }
488 
489 std::vector<rclcpp::Context::OnShutdownCallback>
491 {
492  return get_shutdown_callback<ShutdownType::on_shutdown>();
493 }
494 
495 std::vector<rclcpp::Context::PreShutdownCallback>
497 {
498  return get_shutdown_callback<ShutdownType::pre_shutdown>();
499 }
500 
501 template<Context::ShutdownType shutdown_type>
502 std::vector<rclcpp::Context::ShutdownCallback>
503 Context::get_shutdown_callback() const
504 {
505  const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
506  const std::lock_guard<std::recursive_mutex> lock(mutex);
507  std::vector<rclcpp::Context::ShutdownCallback> callbacks;
508  callbacks.reserve(callback_set.size());
509  for (auto & callback : callback_set) {
510  callbacks.emplace_back(*callback);
511  }
512  return callbacks;
513  };
514 
515  static_assert(
516  shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
517 
518  if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
519  return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
520  } else {
521  return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
522  }
523 }
524 
525 std::shared_ptr<rcl_context_t>
527 {
528  return rcl_context_;
529 }
530 
531 std::shared_ptr<rclcpp::graph_listener::GraphListener>
532 Context::get_graph_listener()
533 {
534  return graph_listener_;
535 }
536 
537 bool
538 Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
539 {
540  std::chrono::nanoseconds time_left = nanoseconds;
541  do {
542  {
543  std::unique_lock<std::mutex> lock(interrupt_mutex_);
544  auto start = std::chrono::steady_clock::now();
545  // this will release the lock while waiting
546  interrupt_condition_variable_.wait_for(lock, time_left);
547  time_left -= std::chrono::steady_clock::now() - start;
548  }
549  } while (time_left > std::chrono::nanoseconds::zero() && this->is_valid());
550  // Return true if the timeout elapsed successfully, otherwise false.
551  return this->is_valid();
552 }
553 
554 void
556 {
557  interrupt_condition_variable_.notify_all();
558 }
559 
560 void
561 Context::clean_up()
562 {
563  shutdown_reason_ = "";
564  rcl_context_.reset();
565  sub_contexts_.clear();
566 }
567 
568 std::vector<Context::SharedPtr>
570 {
571  WeakContextsWrapper::SharedPtr weak_contexts = get_weak_contexts();
572  return weak_contexts->get_contexts();
573 }
#define rcl_get_default_allocator
Return a properly initialized rcl_allocator_t with default values.
Definition: allocator.h:37
Thrown when init is called on an already initialized context.
Definition: context.hpp:47
Context which encapsulates shared state between nodes and other similar entities.
Definition: context.hpp:80
virtual RCLCPP_PUBLIC PreShutdownCallbackHandle add_pre_shutdown_callback(const PreShutdownCallback &callback)
Add a pre_shutdown callback to be called before shutdown is called for this context.
Definition: context.cpp:418
virtual RCLCPP_PUBLIC OnShutdownCallbackHandle add_on_shutdown_callback(const OnShutdownCallback &callback)
Add a on_shutdown callback to be called when shutdown is called for this context.
Definition: context.cpp:406
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.
Definition: context.cpp:194
RCLCPP_PUBLIC std::vector< OnShutdownCallback > get_on_shutdown_callbacks() const
Return the shutdown callbacks.
Definition: context.cpp:490
RCLCPP_PUBLIC std::vector< PreShutdownCallback > get_pre_shutdown_callbacks() const
Return the pre-shutdown callbacks.
Definition: context.cpp:496
RCLCPP_PUBLIC size_t get_domain_id() const
Return actual domain id.
Definition: context.cpp:304
RCLCPP_PUBLIC std::string shutdown_reason() const
Return the shutdown reason, or empty string if not shutdown.
Definition: context.cpp:315
RCLCPP_PUBLIC const rclcpp::InitOptions & get_init_options() const
Return the init options used during init.
Definition: context.cpp:292
RCLCPP_PUBLIC bool sleep_for(const std::chrono::nanoseconds &nanoseconds)
Sleep for a given period of time or until shutdown() is called.
Definition: context.cpp:538
RCLCPP_PUBLIC void interrupt_all_sleep_for()
Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
Definition: context.cpp:555
virtual RCLCPP_PUBLIC OnShutdownCallback on_shutdown(const OnShutdownCallback &callback)
Add a on_shutdown callback to be called when shutdown is called for this context.
Definition: context.cpp:399
virtual RCLCPP_PUBLIC bool remove_pre_shutdown_callback(const PreShutdownCallbackHandle &callback_handle)
Remove an registered pre_shutdown callback.
Definition: context.cpp:424
RCLCPP_PUBLIC bool is_valid() const
Return true if the context is valid, otherwise false.
Definition: context.cpp:281
virtual RCLCPP_PUBLIC bool remove_on_shutdown_callback(const OnShutdownCallbackHandle &callback_handle)
Remove an registered on_shutdown callbacks.
Definition: context.cpp:412
virtual RCLCPP_PUBLIC bool shutdown(const std::string &reason)
Shutdown the context, making it uninitialized and therefore invalid for derived entities.
Definition: context.cpp:322
RCLCPP_PUBLIC std::shared_ptr< rcl_context_t > get_rcl_context()
Return the internal rcl context.
Definition: context.cpp:526
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.
Definition: context.cpp:43
Thrown when unparsed ROS specific arguments are found.
Definition: exceptions.hpp:206
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_context_fini(rcl_context_t *context)
Finalize a context.
Definition: context.c:49
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.
Definition: context.c:83
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.
Definition: context.c:94
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_t rcl_get_zero_initialized_context(void)
Return a zero initialization context object.
Definition: context.c:29
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_shutdown(rcl_context_t *context)
Shutdown a given rcl context.
Definition: init.c:286
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.
Definition: init.c:50
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.
Definition: init_options.c:175
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_fini(void)
Definition: logging.c:127
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.
Definition: logging.c:154
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.
Definition: logging.c:57
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.
Definition: context.cpp:569
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:32
Encapsulates the non-global state of an init/shutdown cycle.
Definition: context.h:114
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24