diff --git a/rcl/include/rcl/wait.h b/rcl/include/rcl/wait.h index fd6278862..10b615c12 100644 --- a/rcl/include/rcl/wait.h +++ b/rcl/include/rcl/wait.h @@ -459,6 +459,29 @@ RCL_WARN_UNUSED rcl_ret_t rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout); +/// Return `true` if the wait set is valid, else `false`. +/** + * A wait set is invalid if: + * - the implementation is `NULL` (rcl_wait_set_init not called or failed) + * - the wait set has been finalized with rcl_wait_set_fini + * + * Also return `false` if the wait set pointer is `NULL`. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] wait_set the rcl_wait_set_t to be validated + * \return `true` if the wait_set is valid, otherwise `false`. + */ +RCL_PUBLIC +bool +rcl_wait_set_is_valid(const rcl_wait_set_t * wait_set); + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/wait.c b/rcl/src/rcl/wait.c index a4694365f..d3e5fde9a 100644 --- a/rcl/src/rcl/wait.c +++ b/rcl/src/rcl/wait.c @@ -79,8 +79,8 @@ rcl_get_zero_initialized_wait_set() return null_wait_set; } -static bool -__wait_set_is_valid(const rcl_wait_set_t * wait_set) +bool +rcl_wait_set_is_valid(const rcl_wait_set_t * wait_set) { return wait_set && wait_set->impl; } @@ -118,7 +118,7 @@ rcl_wait_set_init( RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT); RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); - if (__wait_set_is_valid(wait_set)) { + if (rcl_wait_set_is_valid(wait_set)) { RCL_SET_ERROR_MSG("wait_set already initialized, or memory was uninitialized."); return RCL_RET_ALREADY_INIT; } @@ -173,7 +173,7 @@ rcl_wait_set_init( } return RCL_RET_OK; fail: - if (__wait_set_is_valid(wait_set)) { + if (rcl_wait_set_is_valid(wait_set)) { rmw_ret_t ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set); if (ret != RMW_RET_OK) { fail_ret = RCL_RET_WAIT_SET_INVALID; @@ -189,7 +189,7 @@ rcl_wait_set_fini(rcl_wait_set_t * wait_set) rcl_ret_t result = RCL_RET_OK; RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); - if (__wait_set_is_valid(wait_set)) { + if (rcl_wait_set_is_valid(wait_set)) { rmw_ret_t ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set); if (ret != RMW_RET_OK) { RCL_SET_ERROR_MSG(rmw_get_error_string().str); @@ -204,7 +204,7 @@ rcl_ret_t rcl_wait_set_get_allocator(const rcl_wait_set_t * wait_set, rcl_allocator_t * allocator) { RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); - if (!__wait_set_is_valid(wait_set)) { + if (!rcl_wait_set_is_valid(wait_set)) { RCL_SET_ERROR_MSG("wait set is invalid"); return RCL_RET_WAIT_SET_INVALID; } @@ -215,7 +215,7 @@ rcl_wait_set_get_allocator(const rcl_wait_set_t * wait_set, rcl_allocator_t * al #define SET_ADD(Type) \ RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); \ - if (!__wait_set_is_valid(wait_set)) { \ + if (!rcl_wait_set_is_valid(wait_set)) { \ RCL_SET_ERROR_MSG("wait set is invalid"); \ return RCL_RET_WAIT_SET_INVALID; \ } \ @@ -515,7 +515,7 @@ rcl_ret_t rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout) { RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); - if (!__wait_set_is_valid(wait_set)) { + if (!rcl_wait_set_is_valid(wait_set)) { RCL_SET_ERROR_MSG("wait set is invalid"); return RCL_RET_WAIT_SET_INVALID; } diff --git a/rcl/test/rcl/test_wait.cpp b/rcl/test/rcl/test_wait.cpp index a5399e91b..612082499 100644 --- a/rcl/test/rcl/test_wait.cpp +++ b/rcl/test/rcl/test_wait.cpp @@ -65,6 +65,26 @@ class CLASSNAME (WaitSetTestFixture, RMW_IMPLEMENTATION) : public ::testing::Tes } }; +TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), wait_set_is_valid) { + // null pointers are invalid + EXPECT_FALSE(rcl_wait_set_is_valid(nullptr)); + + // uninitialized wait set is invalid + rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set(); + EXPECT_FALSE(rcl_wait_set_is_valid(&wait_set)); + + // initialized wait set is valid + rcl_ret_t ret = + rcl_wait_set_init(&wait_set, 1, 1, 1, 1, 1, 0, context_ptr, rcl_get_default_allocator()); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + EXPECT_TRUE(rcl_wait_set_is_valid(&wait_set)); + + // finalized wait set is invalid + ret = rcl_wait_set_fini(&wait_set); + EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; + EXPECT_FALSE(rcl_wait_set_is_valid(&wait_set)); +} + TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), test_resize_to_zero) { // Initialize a wait set with a subscription and then resize it to zero. rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();