From 4882850483bc19e6b150eebc053b38715823a301 Mon Sep 17 00:00:00 2001 From: William Woodall Date: Thu, 29 Nov 2018 21:32:46 -0800 Subject: [PATCH] refactor init to allow options to be passed and to not be global (#154) * refactor init to allow options to be passed and to not be global Signed-off-by: William Woodall * use implementation identifier in init and shutdown functions Signed-off-by: William Woodall * refactors and renames Signed-off-by: William Woodall * refactor init_options into its own files Signed-off-by: William Woodall --- rmw/CMakeLists.txt | 2 + rmw/include/rmw/init.h | 115 ++++++++++++++++++++++++ rmw/include/rmw/init_options.h | 159 +++++++++++++++++++++++++++++++++ rmw/include/rmw/ret_types.h | 41 +++++++++ rmw/include/rmw/rmw.h | 93 +++++++++++++++++-- rmw/include/rmw/types.h | 16 ++-- rmw/src/init.c | 35 ++++++++ rmw/src/init_options.c | 36 ++++++++ 8 files changed, 479 insertions(+), 18 deletions(-) create mode 100644 rmw/include/rmw/init.h create mode 100644 rmw/include/rmw/init_options.h create mode 100644 rmw/include/rmw/ret_types.h create mode 100644 rmw/src/init.c create mode 100644 rmw/src/init_options.c diff --git a/rmw/CMakeLists.txt b/rmw/CMakeLists.txt index 50d35ac0..cf643706 100644 --- a/rmw/CMakeLists.txt +++ b/rmw/CMakeLists.txt @@ -27,6 +27,8 @@ include_directories(include) set(rmw_sources "src/allocators.c" "src/convert_rcutils_ret_to_rmw_ret.c" + "src/init.c" + "src/init_options.c" "src/names_and_types.c" "src/sanity_checks.c" "src/node_security_options.c" diff --git a/rmw/include/rmw/init.h b/rmw/include/rmw/init.h new file mode 100644 index 00000000..5d4426b9 --- /dev/null +++ b/rmw/include/rmw/init.h @@ -0,0 +1,115 @@ +// Copyright 2014-2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef RMW__INIT_H_ +#define RMW__INIT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#include "rmw/init_options.h" +#include "rmw/macros.h" +#include "rmw/ret_types.h" +#include "rmw/visibility_control.h" + +/// Implementation defined context structure returned by rmw_init(). +/** + * This should be defined by the rmw implementation. + */ +typedef struct rmw_context_impl_t rmw_context_impl_t; + +/// Initialization context structure which is used to store init specific information. +typedef struct RMW_PUBLIC_TYPE rmw_context_t +{ + /// Locally (process local) unique ID that represents this init/shutdown cycle. + uint64_t instance_id; + /// Implementation identifier, used to ensure two different implementations are not being mixed. + const char * implementation_identifier; + /// Implementation defined context information. + /** May be NULL if there is no implementation defined context information. */ + rmw_context_impl_t * impl; +} rmw_context_t; + +/// Return a zero initialized context structure. +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_context_t +rmw_get_zero_initialized_context(void); + +/// Initialize the middleware with the given options, and yielding an context. +/** + * The given context must be zero initialized, and is filled with + * middleware specific data upon success of this function. + * The context is used when initializing some entities like nodes and + * guard conditions, and is also required to properly call rmw_shutdown(). + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * This should be defined by the rmw implementation. + * + * \param[in] options initialization options to be used during initialization + * \param[out] context resulting context struct + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the implementation + * identifier does not match, or + * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are null or invalid, or + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_init(const rmw_init_options_t * options, rmw_context_t * context); + +/// Shutdown the middleware for a given context. +/** + * The given context must be a valid context which has been initialized + * with rmw_init(). + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * This should be defined by the rmw implementation. + * + * \param[in] context resulting context struct + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the implementation + * identifier does not match, or + * \return `RMW_RET_INVALID_ARGUMENT` if the argument is null or invalid, or + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_shutdown(rmw_context_t * context); + +#ifdef __cplusplus +} +#endif + +#endif // RMW__INIT_H_ diff --git a/rmw/include/rmw/init_options.h b/rmw/include/rmw/init_options.h new file mode 100644 index 00000000..8d8a64cc --- /dev/null +++ b/rmw/include/rmw/init_options.h @@ -0,0 +1,159 @@ +// Copyright 2014-2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef RMW__INIT_OPTIONS_H_ +#define RMW__INIT_OPTIONS_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#include "rcutils/allocator.h" +#include "rmw/macros.h" +#include "rmw/ret_types.h" +#include "rmw/visibility_control.h" + +/// Implementation defined options structure used during rmw_init(). +/** + * This should be defined by the rmw implementation. + */ +typedef struct rmw_init_options_impl_t rmw_init_options_impl_t; + +/// Options structure used during rmw_init(). +typedef struct RMW_PUBLIC_TYPE rmw_init_options_t +{ + /// Locally (process local) unique ID that represents this init/shutdown cycle. + /** + * This should be set by the caller of `rmw_init()` to a number that is + * unique within this process. + * It is designed to be used with `rcl_init()` and `rcl_get_instance_id()`. + */ + uint64_t instance_id; + /// Implementation identifier, used to ensure two different implementations are not being mixed. + const char * implementation_identifier; + // TODO(wjwwood): replace with rmw_allocator_t when that refactor happens + /// Allocator used during internal allocation of init options, if needed. + rcutils_allocator_t allocator; + /// Implementation defined init options. + /** May be NULL if there are no implementation defined options. */ + rmw_init_options_impl_t * impl; +} rmw_init_options_t; + +/// Return a zero initialized init options structure. +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_init_options_t +rmw_get_zero_initialized_init_options(void); + +/// Initialize given init_options with the default values and implementation specific values. +/** + * The given allocator is used, if required, during setup of the init options, + * but is also used during initialization. + * + * In either case the given allocator is stored in the returned init options. + * + * The `impl` pointer should not be changed manually. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | Yes + * Lock-Free | Yes + * + * This should be defined by the rmw implementation. + * + * \param[inout] init_options object to be setup + * \param[in] allocator to be used during setup and during initialization + * \return `RMW_RET_OK` if setup is successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if init_options has already be initialized, or + * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_BAD_ALLOC` if allocating memory failed, or + * \return `RMW_RET_ERROR` if an unspecified error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_init_options_init(rmw_init_options_t * init_options, rcutils_allocator_t allocator); + +/// Copy the given source init options to the destination init options. +/** + * The allocator from the source is used for any allocations and stored in the + * destination. + * + * The destination should either be zero initialized with + * `rmw_get_zero_initialized_init_options()` or should have had + * `rmw_init_options_fini()` called on it. + * Giving an already initialized init options for the destination will result + * in a failure with return code `RMW_RET_INVALID_ARGUMENT`. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | Yes + * Lock-Free | Yes + * + * This should be defined by the rmw implementation. + * + * \param[in] src rcl_init_options_t object to be copied from + * \param[out] dst rcl_init_options_t object to be copied into + * \return `RMW_RET_OK` if the copy is successful, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the implementation + * identifier for src does not match the implementation of this function, or + * \return `RMW_RET_INVALID_ARGUMENT` if the dst has already be initialized, or + * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_BAD_ALLOC` if allocating memory failed, or + * \return `RMW_RET_ERROR` if an unspecified error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_init_options_copy(const rmw_init_options_t * src, rmw_init_options_t * dst); + +/// Finalize the given init_options. +/** + * The given init_options must be non-`NULL` and valid, i.e. had + * `rmw_init_options_init()` called on it but not this function yet. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | Yes + * Lock-Free | Yes + * + * This should be defined by the rmw implementation. + * + * \param[inout] init_options object to be setup + * \return `RMW_RET_OK` if setup is successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_ERROR` if an unspecified error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_init_options_fini(rmw_init_options_t * init_options); + +#ifdef __cplusplus +} +#endif + +#endif // RMW__INIT_OPTIONS_H_ diff --git a/rmw/include/rmw/ret_types.h b/rmw/include/rmw/ret_types.h new file mode 100644 index 00000000..32179c78 --- /dev/null +++ b/rmw/include/rmw/ret_types.h @@ -0,0 +1,41 @@ +// Copyright 2014-2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef RMW__RET_TYPES_H_ +#define RMW__RET_TYPES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +typedef int32_t rmw_ret_t; +#define RMW_RET_OK 0 +#define RMW_RET_ERROR 1 +#define RMW_RET_TIMEOUT 2 + +/// Failed to allocate memory return code. +#define RMW_RET_BAD_ALLOC 10 +/// Invalid argument return code. +#define RMW_RET_INVALID_ARGUMENT 11 +/// Incorrect rmw implementation. +#define RMW_RET_INCORRECT_RMW_IMPLEMENTATION 12 + +#ifdef __cplusplus +} +#endif + +#endif // RMW__RET_TYPES_H_ diff --git a/rmw/include/rmw/rmw.h b/rmw/include/rmw/rmw.h index afb509c3..a47767d2 100644 --- a/rmw/include/rmw/rmw.h +++ b/rmw/include/rmw/rmw.h @@ -17,6 +17,8 @@ * `rmw` defines an interface of middleware primitives that are used by the higher level ROS API's. * It consists of these main components: * + * - Initialization and Shutdown: + * - rmw/init.h * - Nodes * - rmw/rmw.h * - Publisher @@ -90,6 +92,7 @@ extern "C" #include "rosidl_generator_c/message_type_support_struct.h" #include "rosidl_generator_c/service_type_support_struct.h" +#include "rmw/init.h" #include "rmw/macros.h" #include "rmw/qos_profiles.h" #include "rmw/types.h" @@ -117,20 +120,63 @@ RMW_WARN_UNUSED const char * rmw_get_serialization_format(void); -RMW_PUBLIC -RMW_WARN_UNUSED -rmw_ret_t -rmw_init(void); - +// TODO(wjwwood): refactor this API to return a return code when updated to use an allocator +/// Create a node and return a handle to that node. +/** + * This function can fail, and therefore return `NULL`, if: + * - context, name, namespace_, or security_options is `NULL` + * - context, security_options is invalid + * - memory allocation fails during node creation + * - an unspecified error occurs + * + * The context must be non-null and valid, i.e. it has been initialized + * by `rmw_init()` and has not been finalized by `rmw_shutdown()`. + * + * The name and namespace_ should be valid node name and namespace, + * and this should be asserted by the caller (e.g. `rcl`). + * + * The domain ID should be used to physically separate nodes at the + * communication graph level by the middleware. + * For RTPS/DDS this maps naturally to their concept of domain id. + * + * The security options should always be non-null and encapsulate the + * essential security configurations for the node and its entities. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No [1] + * Lock-Free | No [1] + * [1] rmw implementation defined, check the implementation documentation + * + * This should be defined by the rmw implementation. + * + * \param[in] context init context that this node should be associated with + * \param[in] name the node name + * \param[in] namespace_ the node namespace + * \param[in] domain_id the id of the domain that the node should join + * \param[in] security_options the security configurations for the node + * \return rmw node handle or `NULL` if there was an error + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_node_t * rmw_create_node( + rmw_context_t * context, const char * name, const char * namespace_, size_t domain_id, const rmw_node_security_options_t * security_options); +/// Finalize a given node handle, reclaim the resources, and deallocate the node handle. +/** + * \param node the node handle to be destroyed + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if node is null, or + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_ret_t @@ -162,7 +208,6 @@ rmw_destroy_node(rmw_node_t * node); * * \param[in] node pointer to the rmw node * \return rmw guard condition handle if successful, otherwise `NULL` - * */ RMW_PUBLIC RMW_WARN_UNUSED @@ -425,11 +470,45 @@ rmw_send_response( rmw_request_id_t * request_header, void * ros_response); +// TODO(wjwwood): refactor this API to return a return code when updated to use an allocator +/// Create a guard condition and return a handle to that guard condition. +/** + * This function can fail, and therefore return `NULL`, if: + * - context is `NULL` + * - context is invalid + * - memory allocation fails during guard condition creation + * - an unspecified error occurs + * + * The context must be non-null and valid, i.e. it has been initialized + * by `rmw_init()` and has not been finalized by `rmw_shutdown()`. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No [1] + * Lock-Free | No [1] + * [1] rmw implementation defined, check the implementation documentation + * + * This should be defined by the rmw implementation. + * + * \param[in] context init context that this node should be associated with + * \return rmw guard condition handle or `NULL` if there was an error + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_guard_condition_t * -rmw_create_guard_condition(void); +rmw_create_guard_condition(rmw_context_t * context); + +/// Finalize a given guard condition handle, reclaim the resources, and deallocate the handle. +/** + * \param guard_condition the guard condition handle to be destroyed + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if guard_condition is null, or + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_ret_t diff --git a/rmw/include/rmw/types.h b/rmw/include/rmw/types.h index b484147c..577205b5 100644 --- a/rmw/include/rmw/types.h +++ b/rmw/include/rmw/types.h @@ -27,19 +27,11 @@ extern "C" // map rcutils specific log levels to rmw speicfic type #include +#include "rmw/init.h" +#include "rmw/ret_types.h" #include "rmw/serialized_message.h" #include "rmw/visibility_control.h" -typedef int rmw_ret_t; -#define RMW_RET_OK 0 -#define RMW_RET_ERROR 1 -#define RMW_RET_TIMEOUT 2 - -/// Failed to allocate memory return code. -#define RMW_RET_BAD_ALLOC 10 -/// Invalid argument return code. -#define RMW_RET_INVALID_ARGUMENT 11 - // 24 bytes is the most memory needed to represent the GID by any current // implementation. It may need to be increased in the future. #define RMW_GID_STORAGE_SIZE 24 @@ -50,6 +42,7 @@ typedef struct RMW_PUBLIC_TYPE rmw_node_t void * data; const char * name; const char * namespace_; + rmw_context_t * context; } rmw_node_t; typedef struct RMW_PUBLIC_TYPE rmw_publisher_t @@ -84,9 +77,10 @@ typedef struct RMW_PUBLIC_TYPE rmw_guard_condition_t { const char * implementation_identifier; void * data; + rmw_context_t * context; } rmw_guard_condition_t; -/// Array of subsciber handles. +/// Array of subscriber handles. /** * An array of void * pointers representing type-erased middleware-specific subscriptions. * The number of non-null entries may be smaller than the allocated size of the array. diff --git a/rmw/src/init.c b/rmw/src/init.c new file mode 100644 index 00000000..7e0136a9 --- /dev/null +++ b/rmw/src/init.c @@ -0,0 +1,35 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "rmw/init.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +rmw_context_t +rmw_get_zero_initialized_context(void) +{ + return (const rmw_context_t) { + .instance_id = 0, + .impl = NULL + }; // NOLINT(readability/braces): false positive +} + +#ifdef __cplusplus +} +#endif diff --git a/rmw/src/init_options.c b/rmw/src/init_options.c new file mode 100644 index 00000000..de7701c2 --- /dev/null +++ b/rmw/src/init_options.c @@ -0,0 +1,36 @@ +// Copyright 2018 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "rmw/init_options.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +rmw_init_options_t +rmw_get_zero_initialized_init_options(void) +{ + return (const rmw_init_options_t) { + .instance_id = 0, + .implementation_identifier = NULL, + .impl = NULL, + }; // NOLINT(readability/braces): false positive +} + +#ifdef __cplusplus +} +#endif