ROS 2 rclcpp + rcl - kilted  kilted
ROS 2 C++ Client Library with ROS Client Library
node_type_cache.c
1 // Copyright 2023 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 "rcl/node_type_cache.h"
16 #include "rcl/type_description_conversions.h"
17 
18 #include "rcl/error_handling.h"
19 #include "rcutils/logging_macros.h"
20 #include "rcutils/types/hash_map.h"
21 
22 #include "./context_impl.h"
23 #include "./node_impl.h"
24 
26 {
29 
33 
34 static size_t get_type_hash_hashmap_key(const void * key)
35 {
36  // Reinterpret-cast the first sizeof(size_t) bytes of the hash value
37  const rosidl_type_hash_t * type_hash = key;
38  return *(size_t *)type_hash->value;
39 }
40 
41 static int cmp_type_hash(const void * val1, const void * val2)
42 {
43  return memcmp(val1, val2, sizeof(rosidl_type_hash_t));
44 }
45 
46 rcl_ret_t rcl_node_type_cache_init(rcl_node_t * node)
47 {
48  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
49  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
50  if (NULL != node->impl->registered_types_by_type_hash.impl) {
51  // already initialized
52  return RCL_RET_OK;
53  }
54 
55  rcutils_ret_t ret = rcutils_hash_map_init(
56  &node->impl->registered_types_by_type_hash, 2, sizeof(rosidl_type_hash_t),
58  get_type_hash_hashmap_key, cmp_type_hash,
59  &node->context->impl->allocator);
60 
61  if (RCUTILS_RET_OK != ret) {
62  rcl_reset_error();
63  RCL_SET_ERROR_MSG("Failed to initialize type cache hash map");
64  return RCL_RET_ERROR;
65  }
66 
67  return RCL_RET_OK;
68 }
69 
70 rcl_ret_t rcl_node_type_cache_fini(rcl_node_t * node)
71 {
72  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
73  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
74 
75  // Clean up any remaining types.
76  rosidl_type_hash_t key;
77  rcl_type_info_with_registration_count_t type_info_with_registrations;
78  rcutils_ret_t hash_map_ret = rcutils_hash_map_get_next_key_and_data(
79  &node->impl->registered_types_by_type_hash, NULL, &key,
80  &type_info_with_registrations);
81 
82  if (RCUTILS_RET_NOT_INITIALIZED == hash_map_ret) {
83  return RCL_RET_NOT_INIT;
84  }
85 
86  while (RCUTILS_RET_OK == hash_map_ret) {
87  hash_map_ret = rcutils_hash_map_unset(
88  &node->impl->registered_types_by_type_hash, &key);
89  if (hash_map_ret != RCUTILS_RET_OK) {
90  RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING(
91  "Failed to clear out type informations [%s] during shutdown; memory "
92  "will be leaked.",
93  rcutils_get_error_string().str);
94  break;
95  }
96 
97  type_description_interfaces__msg__TypeDescription__destroy(
98  type_info_with_registrations.type_info.type_description);
99  type_description_interfaces__msg__TypeSource__Sequence__destroy(
100  type_info_with_registrations.type_info.type_sources);
101 
102  hash_map_ret = rcutils_hash_map_get_next_key_and_data(
103  &node->impl->registered_types_by_type_hash, NULL, &key,
104  &type_info_with_registrations);
105  }
106 
107  rcutils_ret_t rcutils_ret =
108  rcutils_hash_map_fini(&node->impl->registered_types_by_type_hash);
109 
110  return RCUTILS_RET_OK == rcutils_ret ? RCL_RET_OK : RCL_RET_ERROR;
111 }
112 
113 rcl_ret_t rcl_node_type_cache_get_type_info(
114  const rcl_node_t * node,
115  const rosidl_type_hash_t * type_hash,
116  rcl_type_info_t * type_info)
117 {
118  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
119  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
120  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
121  RCL_CHECK_ARGUMENT_FOR_NULL(type_info, RCL_RET_INVALID_ARGUMENT);
122 
123  rcl_type_info_with_registration_count_t type_info_with_registrations;
124 
125  rcutils_ret_t ret =
126  rcutils_hash_map_get(
127  &node->impl->registered_types_by_type_hash,
128  type_hash, &type_info_with_registrations);
129  if (RCUTILS_RET_OK == ret) {
130  *type_info = type_info_with_registrations.type_info;
131  return RCL_RET_OK;
132  } else if (RCUTILS_RET_NOT_INITIALIZED == ret) {
133  return RCL_RET_NOT_INIT;
134  }
135 
136  return RCL_RET_ERROR;
137 }
138 
139 rcl_ret_t rcl_node_type_cache_register_type(
140  const rcl_node_t * node, const rosidl_type_hash_t * type_hash,
141  const rosidl_runtime_c__type_description__TypeDescription * type_description,
142  const rosidl_runtime_c__type_description__TypeSource__Sequence * type_description_sources)
143 {
144  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
145  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
146  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
147  RCL_CHECK_ARGUMENT_FOR_NULL(type_description, RCL_RET_INVALID_ARGUMENT);
148  RCL_CHECK_ARGUMENT_FOR_NULL(type_description_sources, RCL_RET_INVALID_ARGUMENT);
149 
150  rcl_type_info_with_registration_count_t type_info_with_registrations;
151 
152  const rcutils_ret_t rcutils_ret = rcutils_hash_map_get(
153  &node->impl->registered_types_by_type_hash,
154  type_hash, &type_info_with_registrations);
155 
156  if (RCUTILS_RET_OK == rcutils_ret) {
157  // If the type already exists, we only have to increment the registration
158  // count.
159  type_info_with_registrations.num_registrations++;
160  } else if (RCUTILS_RET_NOT_FOUND == rcutils_ret) {
161  // First registration of this type
162  type_info_with_registrations.num_registrations = 1;
163 
164  // Convert type description struct to type description message struct.
165  type_info_with_registrations.type_info.type_description =
166  rcl_convert_type_description_runtime_to_msg(type_description);
167  if (type_info_with_registrations.type_info.type_description == NULL) {
168  // rcl_convert_type_description_runtime_to_msg already does rcutils_set_error
169  return RCL_RET_ERROR;
170  }
171 
172  // Convert type sources struct to type sources message struct.
173  type_info_with_registrations.type_info.type_sources =
174  rcl_convert_type_source_sequence_runtime_to_msg(type_description_sources);
175  if (type_info_with_registrations.type_info.type_sources == NULL) {
176  // rcl_convert_type_source_sequence_runtime_to_msg already does rcutils_set_error
177  type_description_interfaces__msg__TypeDescription__destroy(
178  type_info_with_registrations.type_info.type_description);
179  return RCL_RET_ERROR;
180  }
181  } else {
182  return RCL_RET_ERROR;
183  }
184 
185  // Update the hash map entry.
186  if (RCUTILS_RET_OK !=
187  rcutils_hash_map_set(
188  &node->impl->registered_types_by_type_hash,
189  type_hash, &type_info_with_registrations))
190  {
191  // Reset the error since rcutils_hash_map_set already set it
192  rcutils_reset_error();
193  RCL_SET_ERROR_MSG("Failed to update type info");
194  type_description_interfaces__msg__TypeDescription__destroy(
195  type_info_with_registrations.type_info.type_description);
196  type_description_interfaces__msg__TypeSource__Sequence__destroy(
197  type_info_with_registrations.type_info.type_sources);
198  return RCL_RET_ERROR;
199  }
200 
201  return RCL_RET_OK;
202 }
203 
204 rcl_ret_t rcl_node_type_cache_unregister_type(
205  const rcl_node_t * node,
206  const rosidl_type_hash_t * type_hash)
207 {
209 
210  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
211  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
212  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
213 
214  if (RCUTILS_RET_OK !=
215  rcutils_hash_map_get(
216  &node->impl->registered_types_by_type_hash,
217  type_hash, &type_info))
218  {
219  RCL_SET_ERROR_MSG("Failed to unregister type, hash not present in map.");
220  return RCL_RET_ERROR;
221  }
222 
223  if (--type_info.num_registrations > 0) {
224  if (RCUTILS_RET_OK !=
225  rcutils_hash_map_set(
226  &node->impl->registered_types_by_type_hash,
227  type_hash, &type_info))
228  {
229  RCL_SET_ERROR_MSG("Failed to update type info");
230  return RCL_RET_ERROR;
231  }
232  } else {
233  if (RCUTILS_RET_OK !=
234  rcutils_hash_map_unset(
235  &node->impl->registered_types_by_type_hash,
236  type_hash))
237  {
238  RCL_SET_ERROR_MSG("Failed to unregister type info");
239  return RCL_RET_ERROR;
240  }
241 
242  type_description_interfaces__msg__TypeDescription__destroy(
243  type_info.type_info.type_description);
244  type_description_interfaces__msg__TypeSource__Sequence__destroy(
245  type_info.type_info.type_sources);
246  }
247 
248  return RCL_RET_OK;
249 }
rcl_allocator_t allocator
Allocator used during init and shutdown.
Definition: context_impl.h:32
rcl_context_impl_t * impl
Implementation specific pointer.
Definition: context.h:120
Structure which encapsulates a ROS Node.
Definition: node.h:45
rcl_node_impl_t * impl
Private implementation pointer.
Definition: node.h:50
rcl_context_t * context
Context associated with this node.
Definition: node.h:47
size_t num_registrations
Counter to keep track of registrations.
rcl_type_info_t type_info
The actual type info.
#define RCL_RET_NOT_INIT
rcl_init() not yet called return code.
Definition: types.h:43
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:29
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
Definition: types.h:59
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24