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()