From a6f97cad139c62dc23e24cc8e171afe08d73debb Mon Sep 17 00:00:00 2001 From: William Woodall Date: Wed, 9 Jan 2019 16:37:33 -0800 Subject: [PATCH] add method for accessing rmw_context from rcl_context Signed-off-by: William Woodall --- rcl/include/rcl/context.h | 22 +++++++ rcl/src/rcl/context.c | 8 +++ rcl/test/CMakeLists.txt | 8 +++ rcl/test/rcl/test_context.cpp | 114 ++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 rcl/test/rcl/test_context.cpp diff --git a/rcl/include/rcl/context.h b/rcl/include/rcl/context.h index 64610e0d8..633e3bd83 100644 --- a/rcl/include/rcl/context.h +++ b/rcl/include/rcl/context.h @@ -261,6 +261,28 @@ RCL_WARN_UNUSED bool rcl_context_is_valid(rcl_context_t * context); +/// Return pointer to the rmw context if the given context is currently valid, otherwise `NULL`. +/** + * If context is `NULL`, then `NULL` is returned. + * If context is zero-initialized, then `NULL` is returned. + * If context is uninitialized, then it is undefined behavior. + * + * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Yes + * Lock-Free | Yes [1] + * [1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t` + * + * \param[in] context object from which the rmw context should be retrieved. + * \return pointer to rmw context if valid, otherwise `NULL` + */ +RCL_PUBLIC +RCL_WARN_UNUSED +rmw_context_t * +rcl_context_get_rmw_context(rcl_context_t * context); + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/context.c b/rcl/src/rcl/context.c index 989286657..a56ca72a3 100644 --- a/rcl/src/rcl/context.c +++ b/rcl/src/rcl/context.c @@ -84,6 +84,14 @@ rcl_context_is_valid(rcl_context_t * context) return 0 != rcl_context_get_instance_id(context); } +rmw_context_t * +rcl_context_get_rmw_context(rcl_context_t * context) +{ + RCL_CHECK_ARGUMENT_FOR_NULL(context, NULL); + RCL_CHECK_FOR_NULL_WITH_MSG(context->impl, "context is zero-initialized", return NULL); + return &(context->impl->rmw_context); +} + void __cleanup_context(rcl_context_t * context) { diff --git a/rcl/test/CMakeLists.txt b/rcl/test/CMakeLists.txt index 8505c7363..5eed488d0 100644 --- a/rcl/test/CMakeLists.txt +++ b/rcl/test/CMakeLists.txt @@ -59,6 +59,14 @@ function(test_target_function) AMENT_DEPENDENCIES ${rmw_implementation} ) + rcl_add_custom_gtest(test_context${target_suffix} + SRCS rcl/test_context.cpp + ENV ${rmw_implementation_env_var} ${memory_tools_ld_preload_env_var} + APPEND_LIBRARY_DIRS ${extra_lib_dirs} + LIBRARIES ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools + AMENT_DEPENDENCIES ${rmw_implementation} + ) + rcl_add_custom_gtest(test_get_node_names${target_suffix} SRCS rcl/test_get_node_names.cpp INCLUDE_DIRS ${osrf_testing_tools_cpp_INCLUDE_DIRS} diff --git a/rcl/test/rcl/test_context.cpp b/rcl/test/rcl/test_context.cpp new file mode 100644 index 000000000..6cdc37128 --- /dev/null +++ b/rcl/test/rcl/test_context.cpp @@ -0,0 +1,114 @@ +// 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 "osrf_testing_tools_cpp/memory_tools/gtest_quickstart.hpp" +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcl/context.h" +#include "rcl/error_handling.h" +#include "rcl/init.h" + +#ifdef RMW_IMPLEMENTATION +# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX +# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX) +#else +# define CLASSNAME(NAME, SUFFIX) NAME +#endif + +class CLASSNAME (TestContextFixture, RMW_IMPLEMENTATION) : public ::testing::Test {}; + +// Test the rcl_context_t's normal function. +// Note: that init/fini are tested in test_init.cpp. +TEST_F(CLASSNAME(TestContextFixture, RMW_IMPLEMENTATION), nominal) { + osrf_testing_tools_cpp::memory_tools::ScopedQuickstartGtest scoped_quickstart_gtest; + + // This prevents memory allocations when setting error states in the future. + rcl_ret_t ret = rcl_initialize_error_handling_thread_local_storage(rcl_get_default_allocator()); + ASSERT_EQ(ret, RCL_RET_OK); + + // initialization with rcl_init + rcl_context_t context = rcl_get_zero_initialized_context(); + rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); + ret = rcl_init_options_init(&init_options, rcl_get_default_allocator()); + ASSERT_EQ(ret, RCL_RET_OK); + ret = rcl_init(0, nullptr, &init_options, &context); + ASSERT_EQ(ret, RCL_RET_OK); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ + ret = rcl_shutdown(&context); + EXPECT_EQ(ret, RCL_RET_OK); + ret = rcl_context_fini(&context); + EXPECT_EQ(ret, RCL_RET_OK); + }); + + // test rcl_context_get_init_options + const rcl_init_options_t * init_options_ptr; + EXPECT_NO_MEMORY_OPERATIONS({ + init_options_ptr = rcl_context_get_init_options(nullptr); + }); + EXPECT_EQ(init_options_ptr, nullptr); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + EXPECT_NO_MEMORY_OPERATIONS({ + init_options_ptr = rcl_context_get_init_options(&context); + }); + EXPECT_NE(init_options_ptr, nullptr) << rcl_get_error_string().str; + rcl_reset_error(); + + // test rcl_context_get_instance_id + rcl_context_instance_id_t instance_id; + EXPECT_NO_MEMORY_OPERATIONS({ + instance_id = rcl_context_get_instance_id(nullptr); + }); + EXPECT_EQ(instance_id, 0UL); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + EXPECT_NO_MEMORY_OPERATIONS({ + instance_id = rcl_context_get_instance_id(&context); + }); + EXPECT_NE(instance_id, 0UL) << rcl_get_error_string().str; + rcl_reset_error(); + + // test rcl_context_is_valid + bool is_valid; + EXPECT_NO_MEMORY_OPERATIONS({ + is_valid = rcl_context_is_valid(nullptr); + }); + EXPECT_FALSE(is_valid); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + EXPECT_NO_MEMORY_OPERATIONS({ + is_valid = rcl_context_is_valid(&context); + }); + EXPECT_TRUE(is_valid) << rcl_get_error_string().str; + rcl_reset_error(); + + // test rcl_context_get_rmw_context + rmw_context_t * rmw_context_ptr; + EXPECT_NO_MEMORY_OPERATIONS({ + rmw_context_ptr = rcl_context_get_rmw_context(nullptr); + }); + EXPECT_EQ(rmw_context_ptr, nullptr); + EXPECT_TRUE(rcl_error_is_set()); + rcl_reset_error(); + + EXPECT_NO_MEMORY_OPERATIONS({ + rmw_context_ptr = rcl_context_get_rmw_context(&context); + }); + EXPECT_NE(rmw_context_ptr, nullptr) << rcl_get_error_string().str; + rcl_reset_error(); +}