ROS 2 rclcpp + rcl - jazzy  jazzy
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_SET_ERROR_MSG("Failed to initialize type cache hash map");
63  return RCL_RET_ERROR;
64  }
65 
66  return RCL_RET_OK;
67 }
68 
69 rcl_ret_t rcl_node_type_cache_fini(rcl_node_t * node)
70 {
71  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
72  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
73 
74  // Clean up any remaining types.
75  rosidl_type_hash_t key;
76  rcl_type_info_with_registration_count_t type_info_with_registrations;
77  rcutils_ret_t hash_map_ret = rcutils_hash_map_get_next_key_and_data(
78  &node->impl->registered_types_by_type_hash, NULL, &key,
79  &type_info_with_registrations);
80 
81  if (RCUTILS_RET_NOT_INITIALIZED == hash_map_ret) {
82  return RCL_RET_NOT_INIT;
83  }
84 
85  while (RCUTILS_RET_OK == hash_map_ret) {
86  hash_map_ret = rcutils_hash_map_unset(
87  &node->impl->registered_types_by_type_hash, &key);
88  if (hash_map_ret != RCUTILS_RET_OK) {
89  RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING(
90  "Failed to clear out type informations [%s] during shutdown; memory "
91  "will be leaked.",
92  rcutils_get_error_string().str);
93  break;
94  }
95 
96  type_description_interfaces__msg__TypeDescription__destroy(
97  type_info_with_registrations.type_info.type_description);
98  type_description_interfaces__msg__TypeSource__Sequence__destroy(
99  type_info_with_registrations.type_info.type_sources);
100 
101  hash_map_ret = rcutils_hash_map_get_next_key_and_data(
102  &node->impl->registered_types_by_type_hash, NULL, &key,
103  &type_info_with_registrations);
104  }
105 
106  rcutils_ret_t rcutils_ret =
107  rcutils_hash_map_fini(&node->impl->registered_types_by_type_hash);
108 
109  return RCUTILS_RET_OK == rcutils_ret ? RCL_RET_OK : RCL_RET_ERROR;
110 }
111 
112 rcl_ret_t rcl_node_type_cache_get_type_info(
113  const rcl_node_t * node,
114  const rosidl_type_hash_t * type_hash,
115  rcl_type_info_t * type_info)
116 {
117  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
118  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
119  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
120  RCL_CHECK_ARGUMENT_FOR_NULL(type_info, RCL_RET_INVALID_ARGUMENT);
121 
122  rcl_type_info_with_registration_count_t type_info_with_registrations;
123 
124  rcutils_ret_t ret =
125  rcutils_hash_map_get(
126  &node->impl->registered_types_by_type_hash,
127  type_hash, &type_info_with_registrations);
128  if (RCUTILS_RET_OK == ret) {
129  *type_info = type_info_with_registrations.type_info;
130  return RCL_RET_OK;
131  } else if (RCUTILS_RET_NOT_INITIALIZED == ret) {
132  return RCL_RET_NOT_INIT;
133  }
134 
135  return RCL_RET_ERROR;
136 }
137 
138 rcl_ret_t rcl_node_type_cache_register_type(
139  const rcl_node_t * node, const rosidl_type_hash_t * type_hash,
140  const rosidl_runtime_c__type_description__TypeDescription * type_description,
141  const rosidl_runtime_c__type_description__TypeSource__Sequence * type_description_sources)
142 {
143  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
144  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
145  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
146  RCL_CHECK_ARGUMENT_FOR_NULL(type_description, RCL_RET_INVALID_ARGUMENT);
147  RCL_CHECK_ARGUMENT_FOR_NULL(type_description_sources, RCL_RET_INVALID_ARGUMENT);
148 
149  rcl_type_info_with_registration_count_t type_info_with_registrations;
150 
151  const rcutils_ret_t rcutils_ret = rcutils_hash_map_get(
152  &node->impl->registered_types_by_type_hash,
153  type_hash, &type_info_with_registrations);
154 
155  if (RCUTILS_RET_OK == rcutils_ret) {
156  // If the type already exists, we only have to increment the registration
157  // count.
158  type_info_with_registrations.num_registrations++;
159  } else if (RCUTILS_RET_NOT_FOUND == rcutils_ret) {
160  // First registration of this type
161  type_info_with_registrations.num_registrations = 1;
162 
163  // Convert type description struct to type description message struct.
164  type_info_with_registrations.type_info.type_description =
165  rcl_convert_type_description_runtime_to_msg(type_description);
166  if (type_info_with_registrations.type_info.type_description == NULL) {
167  // rcl_convert_type_description_runtime_to_msg already does rcutils_set_error
168  return RCL_RET_ERROR;
169  }
170 
171  // Convert type sources struct to type sources message struct.
172  type_info_with_registrations.type_info.type_sources =
173  rcl_convert_type_source_sequence_runtime_to_msg(type_description_sources);
174  if (type_info_with_registrations.type_info.type_sources == NULL) {
175  // rcl_convert_type_source_sequence_runtime_to_msg already does rcutils_set_error
176  type_description_interfaces__msg__TypeDescription__destroy(
177  type_info_with_registrations.type_info.type_description);
178  return RCL_RET_ERROR;
179  }
180  } else {
181  return RCL_RET_ERROR;
182  }
183 
184  // Update the hash map entry.
185  if (RCUTILS_RET_OK !=
186  rcutils_hash_map_set(
187  &node->impl->registered_types_by_type_hash,
188  type_hash, &type_info_with_registrations))
189  {
190  RCL_SET_ERROR_MSG("Failed to update type info");
191  type_description_interfaces__msg__TypeDescription__destroy(
192  type_info_with_registrations.type_info.type_description);
193  type_description_interfaces__msg__TypeSource__Sequence__destroy(
194  type_info_with_registrations.type_info.type_sources);
195  return RCL_RET_ERROR;
196  }
197 
198  return RCL_RET_OK;
199 }
200 
201 rcl_ret_t rcl_node_type_cache_unregister_type(
202  const rcl_node_t * node,
203  const rosidl_type_hash_t * type_hash)
204 {
206 
207  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
208  RCL_CHECK_ARGUMENT_FOR_NULL(node->impl, RCL_RET_NODE_INVALID);
209  RCL_CHECK_ARGUMENT_FOR_NULL(type_hash, RCL_RET_INVALID_ARGUMENT);
210 
211  if (RCUTILS_RET_OK !=
212  rcutils_hash_map_get(
213  &node->impl->registered_types_by_type_hash,
214  type_hash, &type_info))
215  {
216  RCL_SET_ERROR_MSG("Failed to unregister type, hash not present in map.");
217  return RCL_RET_ERROR;
218  }
219 
220  if (--type_info.num_registrations > 0) {
221  if (RCUTILS_RET_OK !=
222  rcutils_hash_map_set(
223  &node->impl->registered_types_by_type_hash,
224  type_hash, &type_info))
225  {
226  RCL_SET_ERROR_MSG("Failed to update type info");
227  return RCL_RET_ERROR;
228  }
229  } else {
230  if (RCUTILS_RET_OK !=
231  rcutils_hash_map_unset(
232  &node->impl->registered_types_by_type_hash,
233  type_hash))
234  {
235  RCL_SET_ERROR_MSG("Failed to unregister type info");
236  return RCL_RET_ERROR;
237  }
238 
239  type_description_interfaces__msg__TypeDescription__destroy(
240  type_info.type_info.type_description);
241  type_description_interfaces__msg__TypeSource__Sequence__destroy(
242  type_info.type_info.type_sources);
243  }
244 
245  return RCL_RET_OK;
246 }
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