diff --git a/rmw/CMakeLists.txt b/rmw/CMakeLists.txt index cf643706..265b137f 100644 --- a/rmw/CMakeLists.txt +++ b/rmw/CMakeLists.txt @@ -27,6 +27,7 @@ include_directories(include) set(rmw_sources "src/allocators.c" "src/convert_rcutils_ret_to_rmw_ret.c" + "src/event.c" "src/init.c" "src/init_options.c" "src/names_and_types.c" diff --git a/rmw/include/rmw/event.h b/rmw/include/rmw/event.h new file mode 100644 index 00000000..e24cd5df --- /dev/null +++ b/rmw/include/rmw/event.h @@ -0,0 +1,128 @@ +// Copyright 2019 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__EVENT_H_ +#define RMW__EVENT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#include "rcutils/allocator.h" + +#include "rmw/macros.h" +#include "rmw/types.h" +#include "rmw/ret_types.h" +#include "rmw/visibility_control.h" + +/// Define QoS policy events +typedef enum rmw_event_type_t +{ + // subscription events + RMW_EVENT_LIVELINESS_CHANGED, + RMW_EVENT_REQUESTED_DEADLINE_MISSED, + + // publisher events + RMW_EVENT_LIVELINESS_LOST, + RMW_EVENT_OFFERED_DEADLINE_MISSED, + + // sentinel value + RMW_EVENT_INVALID +} rmw_event_type_t; + +/// Encapsulate the RMW event implementation, data, and type. +typedef struct RMW_PUBLIC_TYPE rmw_event_t +{ + /// Implementation identifier, used to ensure two different implementations are not being mixed. + const char * implementation_identifier; + /// Data specific to this event type from either the publisher or subscriber. + void * data; + /// The event type that occurred. + rmw_event_type_t event_type; +} rmw_event_t; + +/// Return a zero initialized event structure. +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_event_t +rmw_get_zero_initialized_event(void); + +/// Initialize a rmw publisher event. +/** + * \param[in|out] rmw_event to initialize + * \param publisher to initialize with + * \param event_type for the event to handle + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if invalid argument + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_publisher_event_init( + rmw_event_t * rmw_event, + const rmw_publisher_t * publisher, + rmw_event_type_t event_type); + +/// Initialize a rmw subscription event. +/** + * \param[in|out] rmw_event to initialize + * \param subscription to initialize with + * \param event_type for the event to handle + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if invalid argument + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_subscription_event_init( + rmw_event_t * rmw_event, + const rmw_subscription_t * subscription, + rmw_event_type_t event_type); + +/// Take an event from the event handle. +/** + * \param event_handle event object to take from + * \param event_info event info object to write taken data into + * \param taken boolean flag indicating if an event was taken or not + * \return `RMW_RET_OK` if successful, or + * \return `RMW_RET_BAD_ALLOC` if memory allocation failed, or + * \return `RMW_RET_ERROR` if an unexpected error occurs. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_take_event( + const rmw_event_t * event_handle, + void * event_info, + bool * taken); + +/// Finalize an rmw_event_t. +/** + * \param event to finalize + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_event_fini(rmw_event_t * event); + +#ifdef __cplusplus +} +#endif + +#endif // RMW__EVENT_H_ diff --git a/rmw/include/rmw/rmw.h b/rmw/include/rmw/rmw.h index 05347c37..22480511 100644 --- a/rmw/include/rmw/rmw.h +++ b/rmw/include/rmw/rmw.h @@ -183,6 +183,30 @@ RMW_WARN_UNUSED rmw_ret_t rmw_destroy_node(rmw_node_t * node); +/// Manually assert that this node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE) +/** + * If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE, the creator of + * this node may manually call `assert_liveliness` at some point in time to signal to the rest + * of the system that this Node is still alive. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] node handle to the node that needs liveliness to be asserted + * \return `RMW_RET_OK` if the liveliness assertion was completed successfully, or + * \return `RMW_RET_ERROR` if an unspecified error occurs, or + * \return `RMW_RET_UNSUPPORTED` if the rmw implementation does not support asserting liveliness. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +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. @@ -373,6 +397,30 @@ rmw_get_serialized_message_size( const rosidl_message_bounds_t * message_bounds, size_t * size); +/// Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC) +/** + * If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC, the creator of + * this publisher may manually call `assert_liveliness` at some point in time to signal to the rest + * of the system that this Node is still alive. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] publisher handle to the publisher that needs liveliness to be asserted + * \return `RMW_RET_OK` if the liveliness assertion was completed successfully, or + * \return `RMW_RET_ERROR` if an unspecified error occurs, or + * \return `RMW_RET_UNSUPPORTED` if the rmw implementation does not support asserting liveliness. + */ +RMW_PUBLIC +RMW_WARN_UNUSED +rmw_ret_t +rmw_publisher_assert_liveliness(const rmw_publisher_t * publisher); + /// Serialize a ROS message into a rmw_serialized_message_t. /** * The ROS message is serialized into a byte stream contained within the @@ -764,6 +812,7 @@ rmw_wait( rmw_guard_conditions_t * guard_conditions, rmw_services_t * services, rmw_clients_t * clients, + rmw_events_t * events, rmw_wait_set_t * wait_set, const rmw_time_t * wait_timeout); diff --git a/rmw/include/rmw/types.h b/rmw/include/rmw/types.h index 16203dd2..baf972f7 100644 --- a/rmw/include/rmw/types.h +++ b/rmw/include/rmw/types.h @@ -137,6 +137,14 @@ typedef struct RMW_PUBLIC_TYPE rmw_clients_t void ** clients; } rmw_clients_t; +typedef struct RMW_PUBLIC_TYPE rmw_events_t +{ + /// The number of events represented by the array. + size_t event_count; + /// Pointer to an array of void * pointers of events. + void ** events; +} rmw_events_t; + /// Array of guard condition handles. /** * An array of void * pointers representing type-erased middleware-specific guard conditions. diff --git a/rmw/src/event.c b/rmw/src/event.c new file mode 100644 index 00000000..c4b3dc0a --- /dev/null +++ b/rmw/src/event.c @@ -0,0 +1,91 @@ +// Copyright 2019 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/error_handling.h" +#include "rmw/event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +rmw_event_t +rmw_get_zero_initialized_event(void) +{ + const rmw_event_t event = { + .implementation_identifier = NULL, + .data = NULL, + .event_type = RMW_EVENT_INVALID + }; // NOLINT(readability/braces): false positive + return event; +} + +rmw_ret_t +__rmw_init_event( + rmw_event_t * rmw_event, + const char * implementation_identifier, + void * data, + const rmw_event_type_t event_type) +{ + RMW_CHECK_ARGUMENT_FOR_NULL(implementation_identifier, RMW_RET_INVALID_ARGUMENT); + RMW_CHECK_ARGUMENT_FOR_NULL(data, RMW_RET_INVALID_ARGUMENT); + RMW_CHECK_ARGUMENT_FOR_NULL(rmw_event, RMW_RET_INVALID_ARGUMENT); + if (NULL != rmw_event->implementation_identifier) { + RMW_SET_ERROR_MSG("expected zero-initialized rmw_event"); + return RMW_RET_INVALID_ARGUMENT; + } + rmw_event->implementation_identifier = implementation_identifier; + rmw_event->data = data; + rmw_event->event_type = event_type; + return RMW_RET_OK; +} + +rmw_ret_t +rmw_publisher_event_init( + rmw_event_t * rmw_event, + const rmw_publisher_t * publisher, + rmw_event_type_t event_type) +{ + return __rmw_init_event( + rmw_event, + publisher->implementation_identifier, + publisher->data, + event_type); +} + +rmw_ret_t +rmw_subscription_event_init( + rmw_event_t * rmw_event, + const rmw_subscription_t * subscription, + rmw_event_type_t event_type) +{ + return __rmw_init_event( + rmw_event, + subscription->implementation_identifier, + subscription->data, + event_type); +} + +rmw_ret_t +rmw_event_fini(rmw_event_t * rmw_event) +{ + RMW_CHECK_ARGUMENT_FOR_NULL(rmw_event, RMW_RET_INVALID_ARGUMENT); + *rmw_event = rmw_get_zero_initialized_event(); + return RMW_RET_OK; +} + +#ifdef __cplusplus +} +#endif