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