diff --git a/rmw/include/rmw/get_node_info_and_types.h b/rmw/include/rmw/get_node_info_and_types.h index e0924574..98d85fce 100644 --- a/rmw/include/rmw/get_node_info_and_types.h +++ b/rmw/include/rmw/get_node_info_and_types.h @@ -25,28 +25,66 @@ extern "C" #include "rmw/types.h" #include "rmw/visibility_control.h" -/// Return a list of subscribed topic names and their types. +/// Return all topic names and types for which a given remote node has subscriptions. /** - * This function returns a list of subscribed topic names and their types. - * - * The node parameter must not be `NULL`, and must point to a valid node. - * - * The topic_names_and_types parameter must be allocated and zero initialized. - * The topic_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. - * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[in] node_name the name of the node to get information for - * \param[in] node_namespace the namespace of the node to get information for - * \param[in] no_demangle if true, list all topics without any demangling - * \param[out] topic_names_and_types list of topic names and their types the node_name is subscribed to + * This function returns an array of topic names and types for which a given remote + * node has subscriptions, as discovered so far by the given local node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying subscribed topic names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `topic_names_and_types` + * while rmw_get_subscriber_names_and_types_by_node() uses it. + * - Access to node name and namespace is read-only but it is not synchronized. + * Concurrent `node_name` and `node_namespace` reads are safe, but concurrent reads and + * writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `topic_names_and_types` must be a zero-initialized array of names and types, + * as returned by rmw_get_zero_initialized_names_and_types(). + * + * \param[in] node Local node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `topic_names_and_types` array. + * \param[in] node_name Name of the remote node to get information for. + * \param[in] node_namespace Namespace of the remote node to get information for. + * \param[in] no_demangle Whether to demangle all topic names following ROS conventions or not. + * \param[out] topic_names_and_types Array of topic names and types the remote node has created + * a subscription for, populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on + * using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_name` is not valid, + * by rmw_validate_node_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespace` is not valid, + * by rmw_validate_namespace() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_NODE_NAME_NON_EXISTENT` if the node name wasn't found, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. @@ -60,30 +98,68 @@ rmw_get_subscriber_names_and_types_by_node( const char * node_name, const char * node_namespace, bool no_demangle, - rmw_names_and_types_t * topics_names_and_types); + rmw_names_and_types_t * topic_names_and_types); -/// Return a list of published topic names and their types. +/// Return all topic names and types for which a given remote node has publishers. /** - * This function returns a list of published topic names and their types. - * - * The node parameter must not be `NULL`, and must point to a valid node. - * - * The topic_names_and_types parameter must be allocated and zero initialized. - * The topic_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. - * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[in] node_name the name of the node to get information for - * \param[in] node_namespace the namespace of the node to get information for - * \param[in] no_demangle if true, list all topics without any demangling - * \param[out] topic_names_and_types list of topic names and their types the node_name is publishing + * This function returns an array of topic names and types for which a given remote + * node has created publishers, as discovered so far by the given local node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying published topic names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `topic_names_and_types` + * while rmw_get_publisher_names_and_types_by_node() uses it. + * - Access to node name and namespace is read-only but it is not synchronized. + * Concurrent `node_name` and `node_namespace` reads are safe, but concurrent reads and + * writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `topic_names_and_types` must be a zero-initialized array of names and types, + * as returned by rmw_get_zero_initialized_names_and_types(). + * + * \param[in] Local node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `topic_names_and_types` array. + * \param[in] node_name Name of the remote node to get information for. + * \param[in] node_namespace Namespace of the remote node to get information for. + * \param[in] no_demangle Whether to demangle all topic names following ROS conventions or not. + * \param[out] topic_names_and_types Array of topic names and types the remote node has created + * a publisher for, populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on + * using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_name` is not valid, + * by rmw_validate_node_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespace` is not valid, + * by rmw_validate_namespace() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_NODE_NAME_NON_EXISTENT` if the node name wasn't found, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. @@ -99,27 +175,61 @@ rmw_get_publisher_names_and_types_by_node( bool no_demangle, rmw_names_and_types_t * topic_names_and_types); -/// Return a list of service topic names and their types. +/// Return all service names and types for which a given remote node has servers. /** - * This function returns a list of service topic names and their types. - * - * The node parameter must not be `NULL`, and must point to a valid node. - * - * The topic_names_and_types parameter must be allocated and zero initialized. - * The topic_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. - * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[in] node_name the name of the node to get information for - * \param[in] node_namespace the namespace of the node to get information for - * \param[out] topic_names_and_types list of topic names and their types the node_name has created a service for + * This function returns an array of service names and types for which a given remote + * node has servers, as discovered so far by the given local node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying served service names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `service_names_and_types` + * while rmw_get_service_names_and_types_by_node() uses it. + * - Access to node name and namespace is read-only but it is not synchronized. + * Concurrent `node_name` and `node_namespace` reads are safe, but concurrent reads and + * writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \param[in] node Local node to query the ROS graph. + * \param[in] node_name Name of the remote node to get information for. + * \param[in] node_namespace Namespace of the remote node to get information for. + * \param[in] no_demangle Whether to demangle all topic names following ROS conventions or not. + * \param[out] service_names_and_types Array of service names and types the remote node has + * created a service server for, populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on + * using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_name` is not valid, + * by rmw_validate_node_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespace` is not valid, + * by rmw_validate_namespace() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_NODE_NAME_NON_EXISTENT` if the node name wasn't found, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. @@ -134,28 +244,61 @@ rmw_get_service_names_and_types_by_node( const char * node_namespace, rmw_names_and_types_t * service_names_and_types); -/// Return a list of service client topic names and their types. +/// Return all service names and types for which a given remote node has clients. /** - * This function returns a list of service client topic names and their types. - * - * The node parameter must not be `NULL`, and must point to a valid node. - * - * The topic_names_and_types parameter must be allocated and zero initialized. - * The topic_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. - * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[in] node_name the name of the node to get information for - * \param[in] node_namespace the namespace of the node to get information for - * \param[out] topic_names_and_types list of topic names and their types the - * node_name has created a service client for + * This function returns an array of service names and types for which a given remote + * node has clients, as discovered so far by the given local node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying served service names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `service_names_and_types` + * while rmw_get_client_names_and_types_by_node() uses it. + * - Access to C-style string arguments is read-only but it is not synchronized. + * Concurrent `node_name` and `node_namespace` reads are safe, but concurrent reads and + * writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \param[in] node Local node to query the ROS graph. + * \param[in] node_name Name of the remote node to get information for. + * \param[in] node_namespace Namespace of the remote node to get information for. + * \param[in] no_demangle Whether to demangle all topic names following ROS conventions or not. + * \param[out] service_names_and_types Array of service names and types the remote node has + * created a service client for, populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on + * using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_name` is not valid, + * by rmw_validate_node_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespace` is not valid, + * by rmw_validate_namespace() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_NODE_NAME_NON_EXISTENT` if the node name wasn't found, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. diff --git a/rmw/include/rmw/get_service_names_and_types.h b/rmw/include/rmw/get_service_names_and_types.h index 21a85681..5bf72491 100644 --- a/rmw/include/rmw/get_service_names_and_types.h +++ b/rmw/include/rmw/get_service_names_and_types.h @@ -25,25 +25,57 @@ extern "C" #include "rmw/types.h" #include "rmw/visibility_control.h" -/// Return a list of service names and their types. +/// Return all service names and types in the ROS graph. /** - * This function returns a list of service names in the ROS graph and their types. + * This function returns an array of all service names and types in the ROS graph + * i.e. for which a server and/or client exists, as discovered so far by the given + * local node. * - * The node parameter must not be `NULL`, and must point to a valid node. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation * - * The service_names_and_types parameter must be allocated and zero initialized. - * The service_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[out] service_names_and_types list of service names and their types + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying services names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `service_names_and_types` + * while rmw_get_service_names_and_types() uses it. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `services_names_and_types` must be a zero-initialized array of names and types, + * as returned by rmw_get_zero_initialized_names_and_types(). + * + * \param[in] node Node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `service_names_and_types` array. + * \param[out] service_names_and_types Array of service names and their types, + * populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later + * on using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `service_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ diff --git a/rmw/include/rmw/get_topic_endpoint_info.h b/rmw/include/rmw/get_topic_endpoint_info.h index efb5b42f..b9f6ae67 100644 --- a/rmw/include/rmw/get_topic_endpoint_info.h +++ b/rmw/include/rmw/get_topic_endpoint_info.h @@ -23,42 +23,65 @@ extern "C" #include "rmw/topic_endpoint_info_array.h" #include "rmw/visibility_control.h" -/// Retrieve the information for all publishers to a given topic. +/// Retrieve endpoint information for each known publisher of a given topic. /** - * The retrieved information will contain the publisher's node name, node namespace, - * associated topic type, publisher gid and qos profile. + * This function returns an array of endpoint information for each publisher + * of a given topic, as discovered so far by the given node. + * Endpoint information includes the publisher's node name and namespace, + * the associated topic type, the publisher's gid, and the publisher QoS profile. + * Names of non-existent topics are allowed, in which case an empty array will be returned. * - * The node parameter must not be `NULL` and must point to a valid node. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation * - * The topic_name parameter must not be `NULL` and must follow the topic naming rules - * mentioned at http://design.ros2.org/articles/topic_and_service_names.html - * Names of non-existent topics are allowed. - * In that case, this function will return an empty array. + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). * - * It is the responsibility of the caller to ensure that `publishers_info` parameter points - * to a valid struct of type rmw_topic_endpoint_info_array_t. - * The rmw_topic_endpoint_info_array_t struct must be zero initialized. - * \see rmw_get_zero_initialized_topic_endpoint_info_array + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying topic names and types: + * - Access to the array of topic endpoint information is not synchronized. + * It is not safe to read or write `publishers_info` + * while rmw_get_publishers_info_by_topic() uses it. + * - Access to C-style string arguments is read-only but it is not synchronized. + * Concurrent `topic_name` reads are safe, but concurrent reads and writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * The `allocator` will be used to allocate memory to the `info_array` member - * inside of `publishers_info`. - * Moreover, every `const char *` member inside of - * rmw_topic_endpoint_info_t will be assigned a copied value on allocated memory. - * \see rmw_topic_endpoint_info_set_topic_type - * \see rmw_topic_endpoint_info_set_node_name - * \see rmw_topic_endpoint_info_set_node_namespace - * However, it is the responsibility of the caller to - * reclaim any allocated resources to `publishers_info` to avoid leaking memory. - * \see rmw_topic_endpoint_info_array_fini + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `publishers_info` must be a zero-initialized array of endpoints' information, + * as returned by rmw_get_zero_initialized_topic_endpoint_info_array(). * - * \param[in] node the handle to the node being used to query the ROS graph. - * \param[in] allocator the allocator to be used when allocating space for the array. - * \param[in] topic_name the name of the topic for which the list of publishers will be retrieved. - * \param[in] no_mangle if true, the topic name will not be mangled. - * \param[out] publishers_info an array of rmw_topic_endpoint_info_t. + * \param[in] node Node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `publishers_info` array. + * \param[in] topic_name Name of the topic for publisher lookup, often a fully qualified + * topic name but not necessarily (see rmw_create_publisher()). + * \param[in] no_mangle Whether to mangle the topic name before publisher lookup or not. + * \param[out] publishers_info Array of publisher information, populated on success, + * left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on, + * using rmw_topic_endpoint_info_array_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `publishers_info` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `publishers_info` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ @@ -72,42 +95,63 @@ rmw_get_publishers_info_by_topic( bool no_mangle, rmw_topic_endpoint_info_array_t * publishers_info); -/// Retrieve the information for all subscriptions to a given topic. +/// Retrieve endpoint information for each known subscription of a given topic. /** - * The retrieved information will contain the subscriptions's node name, node namespace, - * associated topic type, subscription gid and qos profile. + * This function returns an array of endpoint information for each subscription + * of a given topic, as discovered so far by the given node. + * Endpoint information includes the subscription's node name and namespace, + * the associated topic type, the subscription's gid, and the subscription QoS profile. + * Names of non-existent topics are allowed, in which case an empty array will be returned. * - * The node parameter must not be `NULL` and must point to a valid node. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation * - * The topic_name parameter must not be `NULL` and must follow the topic naming rules - * mentioned at http://design.ros2.org/articles/topic_and_service_names.html - * Names of non-existent topics are allowed. - * They will return an empty array. + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). * - * It is the responsibility of the caller to ensure that `subscriptions_info` parameter points - * to a valid struct of type rmw_topic_endpoint_info_array_t. - * The rmw_topic_endpoint_info_array_t struct must be zero initialized. - * \see rmw_get_zero_initialized_topic_endpoint_info_array + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying subscriptions' information: + * - Access to the array of topic endpoint information is not synchronized. + * It is not safe to read or write `subscriptions_info` + * while rmw_get_subscriptions_info_by_topic() uses it. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * The `allocator` will be used to allocate memory to the `info_array` member - * inside of `publishers_info`. - * Moreover, every `const char *` member inside of - * rmw_topic_endpoint_info_t will be assigned a copied value on allocated memory. - * \see rmw_topic_endpoint_info_set_topic_type - * \see rmw_topic_endpoint_info_set_node_name - * \see rmw_topic_endpoint_info_set_node_namespace - * However, it is the responsibility of the caller to - * reclaim any allocated resources to `publishers_info` to avoid leaking memory. - * \see rmw_topic_endpoint_info_array_fini + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `subscriptions_info` must be a zero-initialized array of endpoints' information, + * as returned by rmw_get_zero_initialized_topic_endpoint_info_array(). * - * \param[in] node the handle to the node being used to query the ROS graph. - * \param[in] allocator the allocator to be used when allocating space for the array. - * \param[in] topic_name the name of the topic for which the list of subscriptions will be retrieved. - * \param[in] no_mangle if true, the topic name will not be mangled. - * \param[out] subscriptions_info an array of rmw_topic_endpoint_info_t.. + * \param[in] node Node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `subscriptions_info` array. + * \param[in] topic_name Name of the topic for subscription lookup, often a fully qualified + * topic name but not necessarily (see rmw_create_subscription()). + * \param[in] no_mangle Whether to mangle the topic name before subscription lookup or not. + * \param[out] publishers_info Array of subscription information, populated on success, + * left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on, + * using rmw_topic_endpoint_info_array_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, + * by rcutils_allocator_is_valid() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `subscriptions_info` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `subscriptions_info` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ diff --git a/rmw/include/rmw/get_topic_names_and_types.h b/rmw/include/rmw/get_topic_names_and_types.h index b4fbe46b..d070a351 100644 --- a/rmw/include/rmw/get_topic_names_and_types.h +++ b/rmw/include/rmw/get_topic_names_and_types.h @@ -25,49 +25,65 @@ extern "C" #include "rmw/types.h" #include "rmw/visibility_control.h" -/// Return a list of topic names and their types. +/// Return all topic names and types in the ROS graph. /** - * This function returns a list of topic names in the ROS graph and their types. + * This function returns an array of all topic names and types in the ROS graph + * i.e. for which a publisher and/or a subscription exists, as discovered so far + * by the given local node. * - * The node parameter must not be `NULL`, and must point to a valid node. + * Unless `no_demangle` is true, some demangling and filtering may take place when + * listing topics as implemented by the middleware. + * Whether demangling applies or not, and how it applies, depends on the underlying + * implementation. + * See http://design.ros2.org/articles/topic_and_service_names.html for an example + * on how it is used in DDS and RTPS based implementations. * - * The topic_names_and_types parameter must be allocated and zero initialized. - * The topic_names_and_types is the output for this function, and contains - * allocated memory. - * Therefore, it should be passed to rmw_names_and_types_fini() when - * it is no longer needed. - * Failing to do so will result in leaked memory. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined, check the implementation documentation * - * There may be some demangling that occurs when listing the topics from the - * middleware implementation. - * This is the mechanism by which this function can discriminate between ROS - * topics, non-ROS topics, and topics which may be used to implement other - * concepts like ROS Services. + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). * - * For example, if the underlying implementation is DDS or RTPS, ROS specific - * prefixes may be prepended to the user namespace, and the namespace may be - * stripped of leading and trailing slashes, see: + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, when querying topic names and types: + * - Access to the array of names and types is not synchronized. + * It is not safe to read or write `topic_names_and_types` + * while rmw_get_topic_names_and_types() uses it. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * http://design.ros2.org/articles/topic_and_service_names.html#ros-namespaces-with-dds-partitions + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `topic_names_and_types` must be a zero-initialized array of names and types, + * as returned by rmw_get_zero_initialized_names_and_types(). * - * As well as: - * - * http://design.ros2.org/articles/topic_and_service_names.html#communicating-with-non-ros-topics - * - * If the no_demangle argument is true, then the topic names given by the - * middleware will be returned without any demangling or filtering. - * For example, the ROS topic `/foo` may be returned as `rt/foo` or the DDS - * topic (non-ROS topic) with a partition list `['foo', 'bar']` and topic `baz` - * may be returned as `foo/baz` (note that only the first partition is used but - * it is still concatenated to the topic). - * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[in] allocator allocator to be used when allocating space for strings - * \param[in] no_demangle if true, list all topics without any demangling - * \param[out] topic_names_and_types list of topic names and their types + * \param[in] node Node to query the ROS graph. + * \param[in] allocator Allocator to be used when populating the `topic_names_and_types` array. + * \param[in] no_demangle Whether to demangle all topic names following ROS conventions or not. + * \param[out] topic_names_and_types Array of topic names and their types, + * populated on success but left unchanged on failure. + * If populated, it is up to the caller to finalize this array later on + * using rmw_names_and_types_fini(). * \return `RMW_RET_OK` if the query was successful, or - * \return `RMW_RET_INVALID_ARGUMENT` if the node is invalid, or - * \return `RMW_RET_INVALID_ARGUMENT` if any arguments are invalid, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `allocator` is not valid, by rcutils_allocator_is_valid() + * definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_names_and_types` is not a + * zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ diff --git a/rmw/include/rmw/names_and_types.h b/rmw/include/rmw/names_and_types.h index 050eceb1..a8318660 100644 --- a/rmw/include/rmw/names_and_types.h +++ b/rmw/include/rmw/names_and_types.h @@ -31,45 +31,77 @@ extern "C" /// Associative array of topic or service names and types. typedef struct RMW_PUBLIC_TYPE rmw_names_and_types_t { + /// Array of names rcutils_string_array_t names; - // The length of this array is the same as names.size + + /// Dynamic array of arrays of type names, with the same length as `names` rcutils_string_array_t * types; } rmw_names_and_types_t; -/// Return a rmw_names_and_types_t struct with members initialized to `NULL`. +/// Return a zero initialized array of names and types. RMW_PUBLIC RMW_WARN_UNUSED rmw_names_and_types_t rmw_get_zero_initialized_names_and_types(void); -/// Check that a rmw_topic_names_and_types_t struct is zero initialized. +/// Check that the given `names_and_types` array is zero initialized. /** - * Sets error message if names_and_types is not zero initialized + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \par Thread-safety + * Access to the array of names and types is read-only, but it is not synchronized. + * Concurrent `names_and_types` reads are safe, but concurrent reads and writes are not. * - * \param[in] names_and_types Object to check - * \return RMW_RET_OK if zero initialized, RMW_RET_INVALID_ARGUMENT otherwise + * \param[in] names_and_types Array to be checked. + * \return RMW_RET_OK if array is zero initialized, RMW_RET_INVALID_ARGUMENT otherwise. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED rmw_ret_t rmw_names_and_types_check_zero(rmw_names_and_types_t * names_and_types); -/// Initialize a rmw_names_and_types_t object. +/// Initialize an array of names and types. /** * This function initializes the string array for the names and allocates space * for all the string arrays for the types according to the given size, but * it does not initialize the string array for each setup of types. * However, the string arrays for each set of types is zero initialized. * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \par Thread-safety + * Initialization is a reentrant procedure, but: + * - Access to arrays of names and types is not synchronized. + * It is not safe to read or write `names_and_types` during initialization. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * \param[inout] names_and_types object to be initialized - * \param[in] size the number of names and sets of types to be stored - * \param[in] allocator to be used to allocate and deallocate memory - * \returns `RMW_RET_OK` on successfully running the check, or - * \returns `RMW_RET_INVALID_ARGUMENT` if names_and_types is NULL, or + * \param[inout] names_and_types Array to be initialized on success, + * but left unchanged on failure. + * \param[in] size Size of the array. + * \param[in] allocator Allocator to be used to populate `names_and_types`. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `names_and_types` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `names_and_types` is not + * a zero initialized array, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `allocator` is invalid, + * by rcutils_allocator_is_valid() definition, or * \returns `RMW_BAD_ALLOC` if memory allocation fails, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -79,23 +111,32 @@ rmw_names_and_types_init( size_t size, rcutils_allocator_t * allocator); -/// Finalize a rmw_names_and_types_t object. +/// Finalize an array of names and types. /** - * The names_and_types_t objects are populated by one of the - * rmw_get_*_names_and_types() functions. - * During which memory is allocated to store the names and types. - * This function will reclaim any resources within the object so it is safe - * to destroy without leaking memory. + * This function deallocates the string array of names and the array of string arrays of types, + * and zero initializes the given array. + * If a logical error, such as `RMW_RET_INVALID_ARGUMENT`, ensues, this function will return + * early, leaving the given array unchanged. + * Otherwise, it will proceed despite errors. * - * The allocator within the rmw_names_and_types_t object is used to deallocate - * memory. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Finalization is a reentrant procedure, but access to arrays of names and types + * is not synchronized. + * It is not safe to read or write `names_and_types` during initialization. * - * \param[inout] names_and_types object to be finalized - * \returns `RMW_RET_OK` on successfully running the check, or - * \returns `RMW_RET_INVALID_ARGUMENT` if names_and_types is NULL, or + * \param[inout] names_and_types Array to be finalized. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `names_and_types` is NULL, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED diff --git a/rmw/include/rmw/rmw.h b/rmw/include/rmw/rmw.h index 36871f0f..ab5c01a2 100644 --- a/rmw/include/rmw/rmw.h +++ b/rmw/include/rmw/rmw.h @@ -200,19 +200,38 @@ rmw_node_assert_liveliness(const rmw_node_t * node); /// Return a guard condition which is triggered when the ROS graph changes. /** - * The handle returned is a pointer to an internally held rmw guard condition. - * This function can fail, and therefore return `NULL`, if: - * - node is `NULL` - * - node is invalid - * - * The returned handle is made invalid if the node is destroyed or if - * rmw_shutdown() is called. - * - * The guard condition will be triggered anytime a change to the ROS graph - * occurs. - * A ROS graph change includes things like (but not limited to) a new publisher - * advertises, a new subscription is created, a new service becomes available, - * a subscription is canceled, etc. + * The guard condition will be triggered anytime a change to the ROS graph occurs. + * A ROS graph change occurs whenever: + * - A node joins or leaves the ROS graph. + * This change will be reflected in rmw_get_node_names() and + * rmw_get_node_names_with_enclaves() outcome. + * - A topic subscription joins or leaves the ROS graph. + * This change will be reflected in rmw_get_topic_names_and_types(), + * rmw_get_subscriber_names_and_types_by_node(), and + * rmw_get_subscriptions_info_by_topic() outcome. + * - A topic publisher joins or leaves the ROS graph. + * This change will be reflected in rmw_get_topic_names_and_types(), + * rmw_get_publisher_names_and_types_by_node(), and + * rmw_get_publishers_info_by_topic() outcome. + * - A topic subscription matches a topic publisher with compatible QoS policies. + * This change will be reflected in rmw_subscription_count_matched_publishers() outcome. + * - A topic publisher matches a topic subscription with compatible QoS policies. + * This change will be reflected in rmw_publisher_count_matched_subscriptions() outcome. + * - A service server joins or leaves the ROS graph. + * This change will be reflected in rmw_get_service_names_and_types() and + * rmw_get_service_names_and_types_by_node() outcome. + * - A service client joins or leaves the ROS graph. + * This change will be reflected in rmw_get_service_names_and_types() and + * rmw_get_client_names_and_types_by_node() outcome. + * - A service client matches a service server with compatible QoS policies. + * This change will be reflected in rmw_service_server_is_available() outcome. + * + * \note The state of the ROS graph, and any changes that may take place, + * are reported as seen by the associated `node`. + * + * The guard condition is owned and internally held by the `node`. + * It will be invalidated if `node` is finalized using rmw_destroy_node(). + * It is undefined behavior to use an invalidated guard condition. * *
* Attribute | Adherence @@ -222,8 +241,11 @@ rmw_node_assert_liveliness(const rmw_node_t * node); * Uses Atomics | No * Lock-Free | Yes * - * \param[in] node pointer to the rmw node - * \return rmw guard condition handle if successful, otherwise `NULL` + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * + * \param[in] node Node to retrieve the guard condition from. + * \return Guard condition if successful, or `NULL` if + * `node` is `NULL`, or an unspecified error occurs. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -1996,31 +2018,60 @@ rmw_wait( rmw_wait_set_t * wait_set, const rmw_time_t * wait_timeout); -/// Return a list of node name and namespaces discovered via a node. +/// Return the name and namespace of all nodes in the ROS graph. /** - * This function will return a list of node names and a list of node namespaces - * that are discovered via the middleware. - * The two lists represent pairs of namespace and name for each discovered - * node. - * The lists will be the same length and the same position will refer to the - * same node across lists. - * - * The node parameter must not be `NULL`, and must point to a valid node. + * This function will return an array of node names and an array of node namespaces, + * as discovered so far by the given node. + * The two arrays represent name and namespace pairs for each discovered node. + * Both arrays will be the same length and the same index will refer to the same node. * - * The node_names parameter must not be `NULL`, and must point to a valid - * string array. - * - * The node_namespaces parameter must not be `NULL`, and must point to a - * valid string array. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] implementation defined, check the implementation documentation * - * This function does manipulate heap memory. - * This function is not thread-safe. - * This function is lock-free. + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[out] node_names a list of discovered node names - * \param[out] node_namespaces a list of discovered node namespaces - * \return `RMW_RET_OK` if node the query was made successfully, or + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, access to string arrays is not synchronized. + * It is not safe to read or write `node_names` nor `node_namespaces` + * while rmw_get_node_names() uses them. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `node_names` must be a valid string array, zero-initialized + * as returned by rcutils_get_zero_initialized_string_array(). + * \pre Given `node_namespaces` must be a valid string array, zero-initialized + * as returned by rcutils_get_zero_initialized_string_array(). + * \post Given `node_names` and `node_namespaces` will remain valid arrays. + * These will be left unchanged if this function fails early due to a logical error, + * such as an invalid argument, or in an unknown yet valid state if it fails due to + * a runtime error. + * + * \param[in] node Node to query the ROS graph. + * \param[out] node_names Array of discovered node names, populated on success. + * It is up to the caller to finalize this array later on, using rcutils_string_array_fini(). + * \param[out] node_namespaces Array of discovered node namespaces, populated on success. + * It is up to the caller to finalize this array later on, using rcutils_string_array_fini(). + * \return `RMW_RET_OK` if the query was successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_names` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_names` is not a zero-initialized array, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespaces` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespaces` is not a zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or + * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ RMW_PUBLIC @@ -2031,15 +2082,63 @@ rmw_get_node_names( rcutils_string_array_t * node_names, rcutils_string_array_t * node_namespaces); -/// Return a list of node name and namespaces discovered via a node with its enclave. +/// Return the name, namespae, and enclave name of all nodes in the ROS graph. /** - * Similar to \ref rmw_get_node_names, but it also provides the enclave name. + * This is similar to rmw_get_node_names(), but it also provides enclave names. * - * \param[in] node the handle to the node being used to query the ROS graph - * \param[out] node_names a list of discovered node names - * \param[out] node_namespaces a list of discovered node namespaces - * \param[out] enclaves list of discovered nodes' enclave names - * \return `RMW_RET_OK` if node the query was made successfully, or + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is safe to query the ROS graph using the same node concurrently. + * However, access to string arrays is not synchronized. + * It is not safe to read or write `node_names`, `node_namespaces`, nor `enclaves` + * while rmw_get_node_names_with_enclaves() uses them. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * \pre Given `node_names` must be a valid string array, zero-initialized + * as returned by rcutils_get_zero_initialized_string_array(). + * \pre Given `node_namespaces` must be a valid string array, zero-initialized + * as returned by rcutils_get_zero_initialized_string_array(). + * \pre Given `enclaves` must be a zero-initialized string array, + * as returned by rcutils_get_zero_initialized_string_array(). + * \post Given `node_names`, `node_namespaces`, and `enclaves` will remain valid arrays. + * These will be left unchanged if this function fails early due to a logical error, + * such as an invalid argument, or in an unknown yet valid state if it fails due to + * a runtime error. + * + * \param[in] node Node to query the ROS graph. + * \param[out] node_names Array of discovered node names, populated on success. + * It is up to the caller to finalize this array later on, using rcutils_string_array_fini(). + * \param[out] node_namespaces Array of discovered node namespaces, populated on success. + * It is up to the caller to finalize this array later on, using rcutils_string_array_fini(). + * \param[out] enclaves Array of discovered node enclave names, populated on success. + * It is up to the caller to finalize this array later on, using rcutils_string_array_fini(). + * \return `RMW_RET_OK` if the query was successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_names` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_names` is not a zero-initialized array, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespaces` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node_namespaces` is not a zero-initialized array, or + * \return `RMW_RET_INVALID_ARGUMENT` if `enclaves` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `enclaves` is not a zero-initialized array, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or + * \return `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \return `RMW_RET_ERROR` if an unspecified error occurs. */ RMW_PUBLIC @@ -2051,13 +2150,49 @@ rmw_get_node_names_with_enclaves( rcutils_string_array_t * node_namespaces, rcutils_string_array_t * enclaves); -/// Count the number of publishers matching a topic name +/// Count the number of known publishers matching a topic name. /** -* \param[in] node rmw node connected to the ROS graph -* \param[in] topic_name The name of the topic to match under possible prefixes -* \param[out] count The number of publishers matching the topic name -* \return RMW_RET_OK if successful, otherwise an appropriate error code -*/ + * This function returns the numbers of publishers of a given topic in the ROS graph, + * as discovered so far by the given node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is to query the ROS graph using the same node concurrently. + * However, access to primitive data-type arguments is not synchronized. + * It is not safe to read or write `topic_name` or `count` while rmw_count_publishers() + * uses them. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * + * \param[in] node Handle to node to use to query the ROS graph. + * \param[in] topic_name Fully qualified ROS topic name. + * \param[out] count Number of publishers matching the given topic name. + * \return `RMW_RET_OK` if the query was successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is not a fully qualified topic name, + * by rmw_validate_full_topic_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `count` is NULL, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or + * \return `RMW_RET_ERROR` if an unspecified error occurs. + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_ret_t @@ -2066,12 +2201,48 @@ rmw_count_publishers( const char * topic_name, size_t * count); -/// Count the number of subscribers matching a topic name +/// Count the number of known subscribers matching a topic name. /** - * \param[in] node rmw node connected to the ROS graph - * \param[in] topic_name The name of the topic to match under possible prefixes - * \param[out] count The number of subscribers matching the topic name - * \return RMW_RET_OK if successful, otherwise an appropriate error code + * This function returns the numbers of subscribers of a given topic in the ROS graph, + * as discovered so far by the given node. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] implementation defined, check the implementation documentation + * + * \par Runtime behavior + * To query the ROS graph is a synchronous operation. + * It is also non-blocking, but it is not guaranteed to be lock-free. + * Generally speaking, implementations may synchronize access to internal resources using + * locks but are not allowed to wait for events with no guaranteed time bound (barring + * the effects of starvation due to OS scheduling). + * + * \par Thread-safety + * Nodes are thread-safe objects, and so are all operations on them except for finalization. + * Therefore, it is to query the ROS graph using the same node concurrently. + * However, access to primitive data-type arguments is not synchronized. + * It is not safe to read or write `topic_name` or `count` while rmw_count_subscribers() + * uses them. + * + * \pre Given `node` must be a valid node handle, as returned by rmw_create_node(). + * + * \param[in] node Handle to node to use to query the ROS graph. + * \param[in] topic_name Fully qualified ROS topic name. + * \param[out] count Number of subscribers matching the given topic name. + * \return `RMW_RET_OK` if the query was successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if `node` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is NULL, or + * \return `RMW_RET_INVALID_ARGUMENT` if `topic_name` is not a fully qualified topic name, + * by rmw_validate_full_topic_name() definition, or + * \return `RMW_RET_INVALID_ARGUMENT` if `count` is NULL, or + * \return `RMW_RET_INCORRECT_RMW_IMPLEMENTATION` if the `node` implementation + * identifier does not match this implementation, or + * \return `RMW_RET_ERROR` if an unspecified error occurs. */ RMW_PUBLIC RMW_WARN_UNUSED diff --git a/rmw/include/rmw/topic_endpoint_info.h b/rmw/include/rmw/topic_endpoint_info.h index 1e4ac690..dee89178 100644 --- a/rmw/include/rmw/topic_endpoint_info.h +++ b/rmw/include/rmw/topic_endpoint_info.h @@ -24,8 +24,9 @@ extern "C" #include "rmw/types.h" #include "rmw/visibility_control.h" -/// A structure that encapsulates the name, namespace, topic_type, gid and qos_profile -/// of publishers and subscriptions for a topic. +/// A data structure that encapsulates the node name, node namespace, +/// topic_type, gid, and qos_profile of publishers and subscriptions +/// for a topic. typedef struct RMW_PUBLIC_TYPE rmw_topic_endpoint_info_t { /// Name of the node @@ -42,26 +43,47 @@ typedef struct RMW_PUBLIC_TYPE rmw_topic_endpoint_info_t rmw_qos_profile_t qos_profile; } rmw_topic_endpoint_info_t; -/// Return a rmw_topic_endpoint_info_t struct with members initialized to `NULL`. +/// Return zero initialized topic endpoint info data structure. +/** + * Endpoint type will be invalid. + * Endpoint QoS profile will be the system default. + */ RMW_PUBLIC RMW_WARN_UNUSED rmw_topic_endpoint_info_t rmw_get_zero_initialized_topic_endpoint_info(void); -/// Finalize a rmw_topic_endpoint_info_t object. +/// Finalize a topic endpoint info data structure. /** - * The rmw_topic_endpoint_info_t struct has members which require memory to be allocated to them before - * setting values. - * This function reclaims any allocated resources within the object and zeroes out all other - * members. + * This function deallocates all allocated members of the given data structure, + * and then zero initializes it. + * If a logical error, such as `RMW_RET_INVALID_ARGUMENT`, ensues, this function + * will return early, leaving the given data structure unchanged. + * Otherwise, it will proceed despite errors. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Finalization is a reentrant procedure, but: + * - Access to the topic endpoint info data structure is not synchronized. + * It is not safe to read or write `topic_endpoint` during finalization. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * \param[inout] topic_endpoint_info object to be finalized - * \param[in] allocator the allocator used to allocate memory to the object - * \returns `RMW_RET_OK` on successfully reclaiming memory, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or + * \param[inout] topic_endpoint_info Data structure to be finalized. + * \param[in] allocator Allocator used to populate the given `topic_endpoint_info`. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `allocator` is invalid, + * by rcutils_allocator_is_valid() definition, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -70,20 +92,40 @@ rmw_topic_endpoint_info_fini( rmw_topic_endpoint_info_t * topic_endpoint_info, rcutils_allocator_t * allocator); -/// Set the topic_type in rmw_topic_endpoint_info_t. +/// Set the topic type in the given topic endpoint info data structure. /** - * rmw_topic_endpoint_info_t has a member topic_type of type const char *; - * this function allocates memory and copies the value of param passed to it. + * This functions allocates memory and copies the value of the `topic_type` + * argument to set the data structure `topic_type` member. * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] topic_type the topic_type value to set in rmw_topic_endpoint_info_t - * \param[in] allocator the allocator that will be used to allocate memory - * \returns `RMW_RET_OK` on successfully setting the topic_type, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or - * \returns `RMW_RET_BAD_ALLOC` if allocation for string duplication fails, or + * \par Thread-safety + * Setting a member is a reentrant procedure, but: + * - Access to the topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `topic_type` member of the given `topic_endpoint` + * while setting it. + * - Access to C-style string arguments is read-only but it is not synchronized. + * Concurrent `topic_type` reads are safe, but concurrent reads and writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \pre Given `topic_type` is a valid C-style string i.e. NULL terminated. + * + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] topic_type Type name to be set. + * \param[in] allocator Allocator to be used. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_type` is NULL, or + * \returns `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -93,20 +135,40 @@ rmw_topic_endpoint_info_set_topic_type( const char * topic_type, rcutils_allocator_t * allocator); -/// Set the node_name in rmw_topic_endpoint_info_t. +/// Set the node name in the given topic endpoint info data structure. /** - * rmw_topic_endpoint_info_t has a member node_name of type const char *; - * this function allocates memory and copies the value of param passed to it. + * This functions allocates memory and copies the value of the `node_name` + * argument to set the data structure `node_name` member. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Setting a member is a reentrant procedure, but: + * - Access to the topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `node_name` member of the given `topic_endpoint` + * while setting it. + * - Access to C-style string arguments is read-only but it is not synchronized. + * Concurrent `node_name` reads are safe, but concurrent reads and writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] node_name the node_name value to set in rmw_topic_endpoint_info_t - * \param[in] allocator the allocator that will be used to allocate memory - * \returns `RMW_RET_OK` on successfully setting the node_name, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or - * \returns `RMW_RET_BAD_ALLOC` if allocation for string duplication fails, or + * \pre Given `node_name` is a valid C-style string i.e. NULL terminated. + * + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] node_name Node name to be set. + * \param[in] allocator Allocator to be used. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `node_name` is NULL, or + * \returns `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -116,20 +178,40 @@ rmw_topic_endpoint_info_set_node_name( const char * node_name, rcutils_allocator_t * allocator); -/// Set the node_namespace in rmw_topic_endpoint_info_t. +/// Set the node namespace in the given topic endpoint info data structure. /** - * rmw_topic_endpoint_info_t has a member node_namespace of type const char *; - * this function allocates memory and copies the value of param passed to it. + * This functions allocates memory and copies the value of the `node_namespace` + * argument to set the data structure `node_namespace` member. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \par Thread-safety + * Setting a member is a reentrant procedure, but: + * - Access to the topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `node_namespace` member of the given `topic_endpoint` + * while setting it. + * - Access to C-style string arguments is read-only but it is not synchronized. + * Concurrent `node_namespace` reads are safe, but concurrent reads and writes are not. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \pre Given `node_namespace` is a valid C-style string i.e. NULL terminated. * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] node_namespace the node_namespace value to set in rmw_topic_endpoint_info_t - * \param[in] allocator the allocator that will be used to allocate memory - * \returns `RMW_RET_OK` on successfully setting the node_namespace, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or - * \returns `RMW_RET_BAD_ALLOC` if allocation for string duplication fails, or + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] node_namespace Node namespace to be set. + * \param[in] allocator Allocator to be used. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `node_namespace` is NULL, or + * \returns `RMW_RET_BAD_ALLOC` if memory allocation fails, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -139,20 +221,31 @@ rmw_topic_endpoint_info_set_node_namespace( const char * node_namespace, rcutils_allocator_t * allocator); -/// Set the gid in rmw_topic_endpoint_info_t. +/// Set the endpoint type in the given topic endpoint info data structure. /** - * Copies the values from gid into the gid member inside topic_endpoint_info. + * This functions assigns the value of the `type` argument to the data structure + * `endpoint_type` member. * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] gid the gid value to set in rmw_topic_endpoint_info_t - * \param[in] size the size of the gid param - * \returns `RMW_RET_OK` on successfully setting the gid, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or - * \returns `RMW_RET_INVALID_ARGUMENT` size is greater than RMW_GID_STORAGE_SIZE, or - * \returns `RMW_RET_BAD_ALLOC` if allocation for string duplication fails, or + * \par Thread-safety + * Setting a member is a reentrant procedure, but access to the + * topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `endpoint_type` member of the + * given `topic_endpoint` while setting it. + * + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] type Endpoint type to be set. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -161,19 +254,34 @@ rmw_topic_endpoint_info_set_endpoint_type( rmw_topic_endpoint_info_t * topic_endpoint_info, rmw_endpoint_type_t type); -/// Set the gid in rmw_topic_endpoint_info_t. +/// Set the endpoint gid in the given topic endpoint info data structure. /** - * Copies the values from gid into the gid member inside topic_endpoint_info. + * This functions copies the value of the `gid` argument to the data structure + * `endpoint_gid` member. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Setting a member is a reentrant procedure, but access to the + * topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `gid` member of the + * given `topic_endpoint` while setting it. * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] gid the gid value to set in rmw_topic_endpoint_info_t - * \param[in] size the size of the gid param - * \returns `RMW_RET_OK` on successfully setting the gid, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or - * \returns `RMW_RET_INVALID_ARGUMENT` size is greater than RMW_GID_STORAGE_SIZE, or + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] gid Endpoint gid to be set. + * \param[in] size Size of the given `gid`. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `gid` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `size` is greater than RMW_GID_STORAGE_SIZE, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -183,18 +291,32 @@ rmw_topic_endpoint_info_set_gid( const uint8_t gid[], size_t size); -/// Set the qos_profile in rmw_topic_endpoint_info_t. +/// Set the endpoint QoS profile in the given topic endpoint info data structure. /** - * rmw_topic_endpoint_info_t has a member qos_profile of type const rmw_qos_profile_t *. - * This function assigns the passed qos_profile pointer to the member. + * This functions assigns the value of the `qos_profile` argument to the data structure + * `qos_profile` member. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Setting a member is a reentrant procedure, but access to the + * topic endpoint info data structure is not synchronized. + * It is not safe to read or write the `qos_profile` member of the + * given `topic_endpoint` while setting it. * - * \param[inout] topic_endpoint_info pointer to an initialized instance of rmw_topic_endpoint_info_t - * \param[in] qos_profile the qos_profile to set in rmw_topic_endpoint_info_t - * \returns `RMW_RET_OK` on successfully setting the qos_profile, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or + * \param[inout] topic_endpoint_info Data structure to be populated. + * \param[in] qos_profile QoS profile to be set. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `qos_profile` is NULL, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED diff --git a/rmw/include/rmw/topic_endpoint_info_array.h b/rmw/include/rmw/topic_endpoint_info_array.h index c85f2b00..a8cf0986 100644 --- a/rmw/include/rmw/topic_endpoint_info_array.h +++ b/rmw/include/rmw/topic_endpoint_info_array.h @@ -24,31 +24,41 @@ extern "C" #include "rmw/topic_endpoint_info.h" #include "rmw/visibility_control.h" -/// Array of rmw_topic_endpoint_info_t +/// Array of topic endpoint information typedef struct RMW_PUBLIC_TYPE rmw_topic_endpoint_info_array_t { /// Size of the array. size_t size; - /// Pointer representing an array of rmw_topic_endpoint_info_t + /// Contiguous storage for topic endpoint information elements. rmw_topic_endpoint_info_t * info_array; } rmw_topic_endpoint_info_array_t; -/// Return a rmw_topic_endpoint_info_array_t struct with members initialized to `NULL`. +/// Return a zero initialized array of topic endpoint information. RMW_PUBLIC RMW_WARN_UNUSED rmw_topic_endpoint_info_array_t rmw_get_zero_initialized_topic_endpoint_info_array(void); -/// Check that a rmw_topic_endpoint_info_array_t struct is zero initialized. +/// Check that the given `topic_endpoint_info_array` is zero initialized. /** - * This function checks if the provided rmw_topic_endpoint_info_array_t is zero initialized or not. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Access to the array of topic endpoint information is read-only, but it is not synchronized. + * Concurrent `topic_endpoint_info_array` reads are safe, but concurrent reads + * and writes are not. * - * \param[in] topic_endpoint_info_array the data structure to be checked - * \returns `RMW_RET_OK` if topic_endpoint_info_array is zero initialized - * \returns `RMW_RET_INVALID_ARGUMENT` if the parameter is NULL, or - * \returns `RMW_RET_ERROR` if topic_endpoint_info_array is not zero initialized + * \param[in] topic_endpoint_info_array Array to be checked. + * \returns `RMW_RET_OK` if array is zero initialized, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info_array` is NULL, or + * \returns `RMW_RET_ERROR` if `topic_endpoint_info_array` is not zero initialized. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -56,26 +66,39 @@ rmw_ret_t rmw_topic_endpoint_info_array_check_zero( rmw_topic_endpoint_info_array_t * topic_endpoint_info_array); -/// Initialize the info_array member inside rmw_topic_endpoint_info_array_t with the given size +/// Initialize an array of topic endpoint information. /** - * The rmw_topic_endpoint_info_array_t has a member variable info_array which is an array of - * type rmw_topic_endpoint_info_t. - * This function allocates memory to this array to hold n elements, - * where n is the value of the size param to this function. - * The member `size` is updated accordingly. + * This function allocates space to hold `size` topic endpoint information elements. + * Both `info_array` and `size` members are updated accordingly. * - * topic_endpoint_info_array must be zero initialized before being passed into this function. + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + * \par Thread-safety + * Initialization is a reentrant procedure, but: + * - Access to the array of topic endpoint information is not synchronized. + * It is not safe to read or write `topic_endpoint_info_array` during initialization. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. * - * \param[inout] topic_endpoint_info_array the data structure to initialise - * \param[in] size the size of the array - * \param[in] allocator the allocator to be used to allocate space - * \returns `RMW_RET_OK` on successful init, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any of the parameters are NULL, or - * \returns `RMW_RET_INVALID_ARGUMENT` if topic_endpoint_info_array is not zero initialized, or + * \param[inout] topic_endpoint_info_array Array to be initialized on success, + * but left unchanged on failure. + * \param[in] size Size of the array. + * \param[in] allocator Allocator to be used to populate `names_and_types`. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info_array` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info_array` is not + * a zero initialized array, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `allocator` is invalid, + * by rcutils_allocator_is_valid() definition, or * \returns `RMW_BAD_ALLOC` if memory allocation fails, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED @@ -85,21 +108,38 @@ rmw_topic_endpoint_info_array_init_with_size( size_t size, rcutils_allocator_t * allocator); -/// Finalize a rmw_topic_endpoint_info_array_t object. +/// Finalize an array of topic endpoint information. /** - * The info_array member variable inside of rmw_topic_endpoint_info_array represents an array of - * rmw_topic_endpoint_info_t. - * When initializing this array, memory is allocated for it using the allocator. - * This function reclaims any allocated resources within the object and also sets the value of size - * to 0. + * This function deallocates the given array storage, and then zero initializes it. + * If a logical error, such as `RMW_RET_INVALID_ARGUMENT`, ensues, this function will + * return early, leaving the given array unchanged. + * Otherwise, it will proceed despite errors. * - * If a non RMW_RET_OK return value is returned, the RMW error message will be set + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes * - * \param[inout] topic_endpoint_info_array object to be finalized - * \param[in] allocator the allocator used to allocate memory to the object - * \returns `RMW_RET_OK` on successfully reclaiming memory, or - * \returns `RMW_RET_INVALID_ARGUMENT` if any parameters are NULL, or + * \par Thread-safety + * Finalization is a reentrant procedure, but: + * - Access to the array of topic endpoint information is not synchronized. + * It is not safe to read or write `topic_endpoint_info_array` during finalization. + * - The default allocators are thread-safe objects, but any custom `allocator` may not be. + * Check your allocator documentation for further reference. + * + * \pre Given `allocator` must be the same used to initialize the given `topic_endpoint_info_array`. + * + * \param[inout] topic_endpoint_info_array object to be finalized. + * \param[in] allocator Allocator used to populate the given `topic_endpoint_info_array`. + * \returns `RMW_RET_OK` if successful, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `topic_endpoint_info_array` is NULL, or + * \returns `RMW_RET_INVALID_ARGUMENT` if `allocator` is invalid, + * by rcutils_allocator_is_valid() definition, or * \returns `RMW_RET_ERROR` when an unspecified error occurs. + * \remark This function sets the RMW error state on failure. */ RMW_PUBLIC RMW_WARN_UNUSED