ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
context.c
1 // Copyright 2018 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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include "rcl/context.h"
21 
22 #include <stdbool.h>
23 
24 #include "./common.h"
25 #include "./context_impl.h"
26 #include "rcutils/stdatomic_helper.h"
27 
30 {
31  rcl_context_t context = {
32  .impl = NULL,
33  .instance_id_storage = {0},
34  };
35  // this is not constexpr so it cannot be in the struct initialization
37  // ensure assumption about static storage
38  static_assert(
39  sizeof(context.instance_id_storage) >= sizeof(atomic_uint_least64_t),
40  "expected rcl_context_t's instance id storage to be >= size of atomic_uint_least64_t");
41  // initialize atomic
42  atomic_init((atomic_uint_least64_t *)(&context.instance_id_storage), 0);
43  return context;
44 }
45 
46 // See `rcl_init()` for initialization of the context.
47 
50 {
51  RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
52  if (!context->impl) {
53  // Context is zero-initialized
54  return RCL_RET_OK;
55  }
56  if (rcl_context_is_valid(context)) {
57  RCL_SET_ERROR_MSG("rcl_shutdown() not called on the given context");
59  }
61  &(context->impl->allocator), "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
62  return __cleanup_context(context);
63 }
64 
65 // See `rcl_shutdown()` for invalidation of the context.
66 
67 const rcl_init_options_t *
69 {
70  RCL_CHECK_ARGUMENT_FOR_NULL(context, NULL);
71  RCL_CHECK_FOR_NULL_WITH_MSG(context->impl, "context is zero-initialized", return NULL);
72  return &(context->impl->init_options);
73 }
74 
77 {
78  RCL_CHECK_ARGUMENT_FOR_NULL(context, 0);
79  return rcutils_atomic_load_uint64_t((atomic_uint_least64_t *)(&context->instance_id_storage));
80 }
81 
83 rcl_context_get_domain_id(rcl_context_t * context, size_t * domain_id)
84 {
85  if (!rcl_context_is_valid(context)) {
87  }
88  RCL_CHECK_ARGUMENT_FOR_NULL(domain_id, RCL_RET_INVALID_ARGUMENT);
89  *domain_id = context->impl->rmw_context.actual_domain_id;
90  return RCL_RET_OK;
91 }
92 
93 bool
95 {
96  RCL_CHECK_ARGUMENT_FOR_NULL(context, false);
97  return 0 != rcl_context_get_instance_id(context);
98 }
99 
100 rmw_context_t *
102 {
103  RCL_CHECK_ARGUMENT_FOR_NULL(context, NULL);
104  RCL_CHECK_FOR_NULL_WITH_MSG(context->impl, "context is zero-initialized", return NULL);
105  return &(context->impl->rmw_context);
106 }
107 
108 rcl_ret_t
109 __cleanup_context(rcl_context_t * context)
110 {
111  rcl_ret_t ret = RCL_RET_OK;
112  // reset the instance id to 0 to indicate "invalid" (should already be 0, but this is defensive)
113  rcutils_atomic_store((atomic_uint_least64_t *)(&context->instance_id_storage), 0);
114 
115  // clean up global_arguments if initialized
116  if (NULL != context->global_arguments.impl) {
117  ret = rcl_arguments_fini(&(context->global_arguments));
118  if (RCL_RET_OK != ret) {
119  RCUTILS_SAFE_FWRITE_TO_STDERR(
120  "[rcl|context.c:" RCUTILS_STRINGIFY(__LINE__)
121  "] failed to finalize global arguments while cleaning up context, memory may be leaked: ");
122  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
123  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
124  rcl_reset_error();
125  }
126  }
127 
128  // if impl is null, nothing else can be cleaned up
129  if (NULL != context->impl) {
130  // pull allocator out for use during deallocation
131  rcl_allocator_t allocator = context->impl->allocator;
132 
133  // finalize init options if valid
134  if (NULL != context->impl->init_options.impl) {
135  rcl_ret_t init_options_fini_ret = rcl_init_options_fini(&(context->impl->init_options));
136  if (RCL_RET_OK != init_options_fini_ret) {
137  if (RCL_RET_OK == ret) {
138  ret = init_options_fini_ret;
139  }
140  RCUTILS_SAFE_FWRITE_TO_STDERR(
141  "[rcl|context.c:" RCUTILS_STRINGIFY(__LINE__)
142  "] failed to finalize init options while cleaning up context, memory may be leaked: ");
143  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
144  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
145  rcl_reset_error();
146  }
147  }
148 
149  // clean up rmw_context
150  if (NULL != context->impl->rmw_context.implementation_identifier) {
151  rmw_ret_t rmw_context_fini_ret = rmw_context_fini(&(context->impl->rmw_context));
152  if (RMW_RET_OK != rmw_context_fini_ret) {
153  if (RCL_RET_OK == ret) {
154  ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_context_fini_ret);
155  }
156  RCUTILS_SAFE_FWRITE_TO_STDERR(
157  "[rcl|context.c:" RCUTILS_STRINGIFY(__LINE__)
158  "] failed to finalize rmw context while cleaning up context, memory may be leaked: ");
159  RCUTILS_SAFE_FWRITE_TO_STDERR(rcutils_get_error_string().str);
160  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
161  rcutils_reset_error();
162  }
163  }
164 
165  // clean up copy of argv if valid
166  if (NULL != context->impl->argv) {
167  int64_t i;
168  for (i = 0; i < context->impl->argc; ++i) {
169  if (NULL != context->impl->argv[i]) {
170  allocator.deallocate(context->impl->argv[i], allocator.state);
171  }
172  }
173  allocator.deallocate(context->impl->argv, allocator.state);
174  }
175  allocator.deallocate(context->impl, allocator.state);
176  } // if (NULL != context->impl)
177 
178  // zero-initialize the context
180 
181  return ret;
182 }
183 
184 #ifdef __cplusplus
185 }
186 #endif
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_arguments_fini(rcl_arguments_t *args)
Reclaim resources held inside rcl_arguments_t structure.
RCL_PUBLIC RCL_WARN_UNUSED rcl_arguments_t rcl_get_zero_initialized_arguments(void)
Return a rcl_arguments_t struct with members initialized to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_context_instance_id_t rcl_context_get_instance_id(const rcl_context_t *context)
Returns an unsigned integer that is unique to the given context, or 0 if invalid.
Definition: context.c:76
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 const rcl_init_options_t * rcl_context_get_init_options(const rcl_context_t *context)
Return the init options used during initialization for this context.
Definition: context.c:68
RCL_PUBLIC RCL_WARN_UNUSED rmw_context_t * rcl_context_get_rmw_context(rcl_context_t *context)
Return pointer to the rmw context if the given context is currently valid, otherwise NULL.
Definition: context.c:101
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
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
uint64_t rcl_context_instance_id_t
A unique ID per context instance.
Definition: context.h:44
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_init_options_fini(rcl_init_options_t *init_options)
Finalize the given init_options.
Definition: init_options.c:132
rcl_arguments_impl_t * impl
Private implementation pointer.
Definition: arguments.h:38
char ** argv
Copy of argv used during init (may be NULL).
Definition: context_impl.h:38
rmw_context_t rmw_context
rmw context.
Definition: context_impl.h:40
int64_t argc
Length of argv (may be 0).
Definition: context_impl.h:36
rcl_init_options_t init_options
Copy of init options given during init.
Definition: context_impl.h:34
rcl_allocator_t allocator
Allocator used during init and shutdown.
Definition: context_impl.h:32
Encapsulates the non-global state of an init/shutdown cycle.
Definition: context.h:114
rcl_context_impl_t * impl
Implementation specific pointer.
Definition: context.h:120
rcl_arguments_t global_arguments
Global arguments for all nodes which share this context.
Definition: context.h:117
Encapsulation of init options and implementation defined init options.
Definition: init_options.h:36
rcl_init_options_impl_t * impl
Implementation specific pointer.
Definition: init_options.h:38
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24