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