diff --git a/rcl/include/rcl/event.h b/rcl/include/rcl/event.h index 6da7f8093..7ad27e333 100644 --- a/rcl/include/rcl/event.h +++ b/rcl/include/rcl/event.h @@ -170,6 +170,28 @@ RCL_WARN_UNUSED rmw_event_t * rcl_event_get_rmw_handle(const rcl_event_t * event); +/// Check that the event is valid. +/** + * The bool returned is `false` if `event` is invalid. + * The bool returned is `true` otherwise. + * In the case where `false` is to be returned, an error message is set. + * This function cannot fail. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] event pointer to the rcl event + * \return `true` if `event` is valid, otherwise `false` + */ +RCL_PUBLIC +bool +rcl_event_is_valid(const rcl_event_t * event); + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/event.c b/rcl/src/rcl/event.c index 81ccf7c50..016274682 100644 --- a/rcl/src/rcl/event.c +++ b/rcl/src/rcl/event.c @@ -24,21 +24,17 @@ extern "C" #include "rcl/error_handling.h" #include "rcl/expand_topic_name.h" #include "rcl/remap.h" +#include "rcutils/allocator.h" #include "rcutils/logging_macros.h" #include "rmw/error_handling.h" #include "rmw/validate_full_topic_name.h" #include "rmw/event.h" #include "./common.h" +#include "./event_impl.h" #include "./publisher_impl.h" #include "./subscription_impl.h" -typedef struct rcl_event_impl_t -{ - rmw_event_t rmw_handle; - rcl_allocator_t allocator; -} rcl_event_impl_t; - rcl_event_t rcl_get_zero_initialized_event() { @@ -187,6 +183,20 @@ rcl_event_get_rmw_handle(const rcl_event_t * event) } } +bool +rcl_event_is_valid(const rcl_event_t * event) +{ + RCL_CHECK_FOR_NULL_WITH_MSG(event, "event pointer is invalid", return false); + RCL_CHECK_FOR_NULL_WITH_MSG(event->impl, "event's implementation is invalid", return false); + if (event->impl->rmw_handle.event_type == RMW_EVENT_INVALID) { + RCUTILS_SET_ERROR_MSG("event's implementation not init"); + return false; + } + RCUTILS_CHECK_ALLOCATOR_WITH_MSG( + &event->impl->allocator, "not valid allocator", return false); + return true; +} + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/event_impl.h b/rcl/src/rcl/event_impl.h new file mode 100644 index 000000000..1c6b8422b --- /dev/null +++ b/rcl/src/rcl/event_impl.h @@ -0,0 +1,28 @@ +// Copyright 2020 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 RCL__EVENT_IMPL_H_ +#define RCL__EVENT_IMPL_H_ + +#include "rmw/rmw.h" + +#include "rcl/event.h" + +typedef struct rcl_event_impl_t +{ + rmw_event_t rmw_handle; + rcl_allocator_t allocator; +} rcl_event_impl_t; + +#endif // RCL__EVENT_IMPL_H_ diff --git a/rcl/test/CMakeLists.txt b/rcl/test/CMakeLists.txt index ae1e42af1..ed94a0304 100644 --- a/rcl/test/CMakeLists.txt +++ b/rcl/test/CMakeLists.txt @@ -255,6 +255,7 @@ function(test_target_function) SRCS rcl/test_events.cpp ENV ${rmw_implementation_env_var} APPEND_LIBRARY_DIRS ${extra_lib_dirs} + INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../src/rcl/ LIBRARIES ${PROJECT_NAME} AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs" ) diff --git a/rcl/test/rcl/test_events.cpp b/rcl/test/rcl/test_events.cpp index d645b4bbb..351356c2b 100644 --- a/rcl/test/rcl/test_events.cpp +++ b/rcl/test/rcl/test_events.cpp @@ -25,12 +25,15 @@ #include "rcl/subscription.h" #include "rcl/error_handling.h" #include "rmw/incompatible_qos_events_statuses.h" +#include "rmw/event.h" #include "test_msgs/msg/strings.h" #include "rosidl_runtime_c/string_functions.h" #include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "./event_impl.h" + using namespace std::chrono_literals; using std::chrono::seconds; using std::chrono::duration_cast; @@ -730,6 +733,46 @@ TEST_F(TestEventFixture, test_bad_get_handle) EXPECT_EQ(NULL, rcl_event_get_rmw_handle(NULL)); } +/* + * Test cases for the event_is_valid function + */ +TEST_F(TestEventFixture, test_event_is_valid) +{ + EXPECT_FALSE(rcl_event_is_valid(nullptr)); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + setup_publisher_subscriber(default_qos_profile, default_qos_profile); + rcl_event_t publisher_event_test = rcl_get_zero_initialized_event(); + EXPECT_FALSE(rcl_event_is_valid(&publisher_event_test)); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + rcl_ret_t ret = rcl_publisher_event_init( + &publisher_event_test, &publisher, RCL_PUBLISHER_OFFERED_DEADLINE_MISSED); + ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + EXPECT_TRUE(rcl_event_is_valid(&publisher_event_test)); + + rmw_event_type_t saved_event_type = publisher_event_test.impl->rmw_handle.event_type; + publisher_event_test.impl->rmw_handle.event_type = RMW_EVENT_INVALID; + EXPECT_FALSE(rcl_event_is_valid(&publisher_event_test)); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + publisher_event_test.impl->rmw_handle.event_type = saved_event_type; + + rcl_allocator_t saved_alloc = publisher_event_test.impl->allocator; + rcl_allocator_t bad_alloc = rcutils_get_zero_initialized_allocator(); + publisher_event_test.impl->allocator = bad_alloc; + EXPECT_FALSE(rcl_event_is_valid(&publisher_event_test)); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + publisher_event_test.impl->allocator = saved_alloc; + + ret = rcl_event_fini(&publisher_event_test); + EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str; + tear_down_publisher_subscriber(); +} + static std::array get_test_pubsub_incompatible_qos_inputs()