From 37d0a05438f3dcfd272e45f161993827a1e60c4f Mon Sep 17 00:00:00 2001 From: Patrick Haecker Date: Fri, 5 Apr 2024 09:40:09 +0200 Subject: [PATCH 1/4] Support usage without explicit stack allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful if no header files can or should be used, e.g. if you want to use the library from a language which cannot directly use header files. Signed-off-by: Patrick Häcker --- rclc/include/rclc/executor.h | 41 +++++++++++ rclc/include/rclc/executor_handle.h | 3 + rclc/include/rclc/init.h | 106 +++++++++++++++++++++++++++ rclc/include/rclc/node.h | 39 ++++++++++ rclc/include/rclc/publisher.h | 38 ++++++++++ rclc/include/rclc/subscription.h | 40 ++++++++++ rclc/include/rclc/timer.h | 40 ++++++++++ rclc/src/rclc/executor.c | 21 ++++++ rclc/src/rclc/executor_handle.c | 2 + rclc/src/rclc/init.c | 58 +++++++++++++++ rclc/src/rclc/node.c | 23 ++++++ rclc/src/rclc/publisher.c | 23 ++++++ rclc/src/rclc/subscription.c | 23 ++++++ rclc/src/rclc/timer.c | 21 ++++++ rclc/test/rclc/test_executor.cpp | 8 ++ rclc/test/rclc/test_init.cpp | 31 ++++++++ rclc/test/rclc/test_node.cpp | 8 ++ rclc/test/rclc/test_publisher.cpp | 8 ++ rclc/test/rclc/test_subscription.cpp | 8 ++ rclc/test/rclc/test_timer.cpp | 8 ++ 20 files changed, 549 insertions(+) diff --git a/rclc/include/rclc/executor.h b/rclc/include/rclc/executor.h index 1f685e81..74e2fd9c 100644 --- a/rclc/include/rclc/executor.h +++ b/rclc/include/rclc/executor.h @@ -981,6 +981,47 @@ rclc_executor_trigger_one( unsigned int size, void * obj); +/** + * Allocates an rclc_executor_t object on the heap and sets its values to + * zero. Can be used as an alternative to + * rclc_executor_get_zero_initialized_executor() if no stack allocation can + * or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the executor (rclc_executor_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rclc_executor_t * +rclc_alloc_zero_initialized_executor(); + +/** + * De-allocates an rclc_executor_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] executor a heap-allocated rclc_executor_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +RCLC_PUBLIC +rcl_ret_t +rclc_executor_free( + rclc_executor_t * executor); + #if __cplusplus } #endif diff --git a/rclc/include/rclc/executor_handle.h b/rclc/include/rclc/executor_handle.h index 444a4ffd..bd2f826b 100644 --- a/rclc/include/rclc/executor_handle.h +++ b/rclc/include/rclc/executor_handle.h @@ -57,6 +57,9 @@ typedef enum ON_NEW_DATA, ALWAYS } rclc_executor_handle_invocation_t; +/** Can be used if the node cannot access defines.*/ +RCLC_PUBLIC extern const int32_t rclc_on_new_data; +RCLC_PUBLIC extern const int32_t rclc_always; /// Type definition for subscription callback function /// - incoming message diff --git a/rclc/include/rclc/init.h b/rclc/include/rclc/init.h index 832c9aab..d939d0d9 100644 --- a/rclc/include/rclc/init.h +++ b/rclc/include/rclc/init.h @@ -104,6 +104,112 @@ rcl_ret_t rclc_support_fini( rclc_support_t * support); +/** + * Allocates the rclc_support_t object on the heap. + * Can be used as if no stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the support (rclc_support_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rclc_support_t * +rclc_support_alloc(); + +/** + * Return the pointer to the context member of struct support. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[inout] support a heap-allocated rclc_support_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +rcl_context_t * +rclc_get_context( + rclc_support_t * support); + +/** + * De-allocates the rclc_support_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] support a heap-allocated rclc_support_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +rcl_ret_t +rclc_support_free( + rclc_support_t * support); + + +/** + * Allocates the rcl_allocator_t object on the heap and sets it with default + * values. + * Can be used as an alternative to rcl_get_default_allocator() if no + * stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the allocator (rcl_allocator_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rcl_allocator_t * +rclc_allocator_alloc_default(); + +/** + * De-allocates the rcl_allocator_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] allocator a heap-allocated rcl_allocator_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +RCLC_PUBLIC +rcl_ret_t +rclc_allocator_free( + rcl_allocator_t * allocator); + + +/** Can be used if the node cannot access defines.*/ +RCLC_PUBLIC extern const int32_t rcl_ret_ok; +RCLC_PUBLIC extern const int32_t rcl_ret_error; +RCLC_PUBLIC extern const int32_t rcl_ret_timeout; +RCLC_PUBLIC extern const int32_t rcl_ret_unsupported; + #if __cplusplus } #endif diff --git a/rclc/include/rclc/node.h b/rclc/include/rclc/node.h index 9149a932..835aab29 100644 --- a/rclc/include/rclc/node.h +++ b/rclc/include/rclc/node.h @@ -78,6 +78,45 @@ rclc_node_init_with_options( rclc_support_t * support, rcl_node_options_t * node_ops); +/** + * Allocates an rcl_node_t object on the heap and sets its values to zero. + * Can be used as an alternative to rcl_get_zero_initialized_node() if no + * stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the node (rcl_node_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rcl_node_t * +rclc_alloc_zero_initialized_node(); + +/** + * De-allocates an rcl_node_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] node a heap-allocated rcl_node_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +RCLC_PUBLIC +rcl_ret_t +rclc_node_free( + rcl_node_t * node); #if __cplusplus } diff --git a/rclc/include/rclc/publisher.h b/rclc/include/rclc/publisher.h index 35815a21..653aa400 100644 --- a/rclc/include/rclc/publisher.h +++ b/rclc/include/rclc/publisher.h @@ -108,6 +108,44 @@ rclc_publisher_init( const char * topic_name, const rmw_qos_profile_t * qos_profile); +/** + * Allocates an rcl_publisher_t object on the heap. + * Can be used as if no stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to a publisher (rcl_publisher_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rcl_publisher_t * +rclc_publisher_alloc(); + +/** + * De-allocates an rcl_publisher_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] publisher a heap-allocated rcl_publisher_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +rcl_ret_t +rclc_publisher_free( + rcl_publisher_t * publisher); + #if __cplusplus } #endif diff --git a/rclc/include/rclc/subscription.h b/rclc/include/rclc/subscription.h index cfa5ab48..9d238a85 100644 --- a/rclc/include/rclc/subscription.h +++ b/rclc/include/rclc/subscription.h @@ -107,6 +107,46 @@ rclc_subscription_init( const char * topic_name, const rmw_qos_profile_t * qos_profile); +/** + * Allocates an rcl_subscription_t object on the heap and sets its values to zero. + * Can be used as an alternative to rcl_get_zero_initialized_subscription() if no + * stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the subscription (rcl_subscription_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rcl_subscription_t * +rclc_alloc_zero_initialized_subscription(); + +/** + * De-allocates an rcl_subscription_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] subscription a heap-allocated rcl_subscription_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +RCLC_PUBLIC +rcl_ret_t +rclc_subscription_free( + rcl_subscription_t * subscription); + #if __cplusplus } #endif diff --git a/rclc/include/rclc/timer.h b/rclc/include/rclc/timer.h index 60441529..a7e47ecf 100644 --- a/rclc/include/rclc/timer.h +++ b/rclc/include/rclc/timer.h @@ -51,6 +51,46 @@ rclc_timer_init_default( const uint64_t timeout_ns, const rcl_timer_callback_t callback); +/** + * Allocates an rcl_timer_t object on the heap and sets its values to zero. + * Can be used as an alternative to rclc_timer_init_default() if no + * stack allocation can or should be used. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \return pointer to the timer (rcl_timer_t) + * \return NULL, if no memory could be allocated. + */ +RCLC_PUBLIC +rcl_timer_t * +rclc_alloc_zero_initialized_timer(); + +/** + * De-allocates an rcl_timer_t object and sets the pointer to NULL. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[inout] timer a heap-allocated rcl_timer_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +RCLC_PUBLIC +rcl_ret_t +rclc_timer_free( + rcl_timer_t * timer); + #if __cplusplus } #endif diff --git a/rclc/src/rclc/executor.c b/rclc/src/rclc/executor.c index b91aa783..39ea9e14 100644 --- a/rclc/src/rclc/executor.c +++ b/rclc/src/rclc/executor.c @@ -2119,3 +2119,24 @@ bool rclc_executor_trigger_always(rclc_executor_handle_t * handles, unsigned int RCLC_UNUSED(obj); return true; } + +rclc_executor_t * +rclc_alloc_zero_initialized_executor() +{ + rclc_executor_t * executor = (rclc_executor_t *) malloc(sizeof(rclc_executor_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + executor, "executor is a null pointer", return executor); + rclc_executor_t executor_stack = rclc_executor_get_zero_initialized_executor(); + memcpy(executor, &executor_stack, sizeof(rclc_executor_t)); + return executor; +} + +rcl_ret_t +rclc_executor_free(rclc_executor_t * executor) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + executor, "executor is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(executor); + executor = NULL; + return RCL_RET_OK; +} diff --git a/rclc/src/rclc/executor_handle.c b/rclc/src/rclc/executor_handle.c index dad84006..0af7bdee 100644 --- a/rclc/src/rclc/executor_handle.c +++ b/rclc/src/rclc/executor_handle.c @@ -19,6 +19,8 @@ #include #include +const int32_t rclc_on_new_data = ON_NEW_DATA; +const int32_t rclc_always = ALWAYS; // initialization of handle_counters object rcl_ret_t diff --git a/rclc/src/rclc/init.c b/rclc/src/rclc/init.c index 2c0174b9..bdac0def 100644 --- a/rclc/src/rclc/init.c +++ b/rclc/src/rclc/init.c @@ -22,6 +22,8 @@ #include #include +#include + rcl_ret_t rclc_support_init( rclc_support_t * support, @@ -105,3 +107,59 @@ rclc_support_fini(rclc_support_t * support) } return result; } + +rclc_support_t * +rclc_support_alloc() +{ + rclc_support_t * support = (rclc_support_t *) malloc(sizeof(rclc_support_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + support, "support is a null pointer", return support); + return support; +} + +rcl_ret_t +rclc_support_free(rclc_support_t * support) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + support, "support is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(support); + support = NULL; + return RCL_RET_OK; +} + + +rcl_context_t * +rclc_get_context(rclc_support_t * support) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + support, "support is a null pointer", return (rcl_context_t *) NULL); + return &(support->context); +} + + +rcl_allocator_t * +rclc_allocator_alloc_default() +{ + rcl_allocator_t * allocator = (rcl_allocator_t *) malloc(sizeof(rcutils_allocator_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + allocator, "allocator is a null pointer", return allocator); + rcl_allocator_t allocator_stack = rcl_get_default_allocator(); + memcpy(allocator, &allocator_stack, sizeof(rcl_allocator_t)); + return allocator; +} + +rcl_ret_t +rclc_allocator_free(rcl_allocator_t * allocator) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + allocator, "allocator is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(allocator); + allocator = NULL; + return RCL_RET_OK; +} + + +const int32_t rcl_ret_ok = RCL_RET_OK; +const int32_t rcl_ret_error = RCL_RET_ERROR; +const int32_t rcl_ret_timeout = RCL_RET_TIMEOUT; +const int32_t rcl_ret_unsupported = RCL_RET_UNSUPPORTED; diff --git a/rclc/src/rclc/node.c b/rclc/src/rclc/node.c index 283777ef..17f56246 100644 --- a/rclc/src/rclc/node.c +++ b/rclc/src/rclc/node.c @@ -19,6 +19,8 @@ #include #include +#include + rcl_ret_t rclc_node_init_default( rcl_node_t * node, @@ -82,3 +84,24 @@ rclc_node_init_with_options( } return rc; } + +rcl_node_t * +rclc_alloc_zero_initialized_node() +{ + rcl_node_t * node = (rcl_node_t *) malloc(sizeof(rcl_node_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + node, "node is a null pointer", return node); + rcl_node_t node_stack = rcl_get_zero_initialized_node(); + memcpy(node, &node_stack, sizeof(rcl_node_t)); + return node; +} + +rcl_ret_t +rclc_node_free(rcl_node_t * node) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + node, "node is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(node); + node = NULL; + return RCL_RET_OK; +} diff --git a/rclc/src/rclc/publisher.c b/rclc/src/rclc/publisher.c index d53f5a27..420a20e9 100644 --- a/rclc/src/rclc/publisher.c +++ b/rclc/src/rclc/publisher.c @@ -20,6 +20,8 @@ #include #include +#include + rcl_ret_t rclc_publisher_init_default( rcl_publisher_t * publisher, @@ -77,3 +79,24 @@ rclc_publisher_init( } return rc; } + +RCLC_PUBLIC +rcl_publisher_t * +rclc_publisher_alloc() +{ + rcl_publisher_t * publisher = (rcl_publisher_t *) malloc(sizeof(rcl_publisher_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + publisher, "publisher is a null pointer", return publisher); + return publisher; +} + +rcl_ret_t +rclc_publisher_free( + rcl_publisher_t * publisher) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + publisher, "publisher is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(publisher); + publisher = NULL; + return RCL_RET_OK; +} diff --git a/rclc/src/rclc/subscription.c b/rclc/src/rclc/subscription.c index af592543..ca3028cb 100644 --- a/rclc/src/rclc/subscription.c +++ b/rclc/src/rclc/subscription.c @@ -20,6 +20,8 @@ #include #include +#include + rcl_ret_t rclc_subscription_init_default( rcl_subscription_t * subscription, @@ -77,3 +79,24 @@ rclc_subscription_init( } return rc; } + +rcl_subscription_t * +rclc_alloc_zero_initialized_subscription() +{ + rcl_subscription_t * subscription = (rcl_subscription_t *) malloc(sizeof(rcl_subscription_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + subscription, "subscription is a null pointer", return subscription); + rcl_subscription_t subscription_stack = rcl_get_zero_initialized_subscription(); + memcpy(subscription, &subscription_stack, sizeof(rcl_subscription_t)); + return subscription; +} + +rcl_ret_t +rclc_subscription_free(rcl_subscription_t * subscription) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + subscription, "subscription is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(subscription); + subscription = NULL; + return RCL_RET_OK; +} diff --git a/rclc/src/rclc/timer.c b/rclc/src/rclc/timer.c index f480f9e6..86f3c381 100644 --- a/rclc/src/rclc/timer.c +++ b/rclc/src/rclc/timer.c @@ -46,3 +46,24 @@ rclc_timer_init_default( } return rc; } + +rcl_timer_t * +rclc_alloc_zero_initialized_timer() +{ + rcl_timer_t * timer = (rcl_timer_t *) malloc(sizeof(rcl_timer_t)); + RCL_CHECK_FOR_NULL_WITH_MSG( + timer, "timer is a null pointer", return timer); + rcl_timer_t timer_stack = rcl_get_zero_initialized_timer(); + memcpy(timer, &timer_stack, sizeof(rcl_timer_t)); + return timer; +} + +rcl_ret_t +rclc_timer_free(rcl_timer_t * timer) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + timer, "timer is a null pointer", return RCL_RET_INVALID_ARGUMENT); + free(timer); + timer = NULL; + return RCL_RET_OK; +} diff --git a/rclc/test/rclc/test_executor.cpp b/rclc/test/rclc/test_executor.cpp index 86346f49..5749d8c8 100644 --- a/rclc/test/rclc/test_executor.cpp +++ b/rclc/test/rclc/test_executor.cpp @@ -2804,3 +2804,11 @@ TEST_F(TestDefaultExecutor, executor_test_remove_guard_condition) { rc = rclc_executor_fini(&executor); EXPECT_EQ(RCL_RET_OK, rc) << rcl_get_error_string().str; } + +TEST(TestDefaultExecutor, rclc_alloc_zero_initialized_executor) { + // test heap allocation and freeing + rclc_executor_t * executor_heap = rclc_alloc_zero_initialized_executor(); + EXPECT_NE(nullptr, executor_heap); + rcl_ret_t rc = rclc_executor_fini(executor_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} \ No newline at end of file diff --git a/rclc/test/rclc/test_init.cpp b/rclc/test/rclc/test_init.cpp index db8cac6d..19359a8d 100644 --- a/rclc/test/rclc/test_init.cpp +++ b/rclc/test/rclc/test_init.cpp @@ -84,3 +84,34 @@ TEST(Test, rclc_support_fini) { EXPECT_EQ(RCL_RET_ERROR, rc); rcutils_reset_error(); } + +TEST(Test, rclc_support_alloc) { + // test heap allocation and freeing + rclc_support_t * support_heap = rclc_support_alloc(); + EXPECT_NE(nullptr, support_heap); + rcl_ret_t rc = rclc_support_free(support_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} + +TEST(Test, rclc_get_context) { + rclc_support_t support; + rcl_ret_t rc; + rcl_allocator_t allocator = rcl_get_default_allocator(); + rc = rclc_support_init(&support, 0, nullptr, &allocator); + EXPECT_EQ(RCL_RET_OK, rc); + + rcl_context_t *context = rclc_get_context(&support); + EXPECT_NE(nullptr, context); + EXPECT_TRUE(rcl_context_is_valid(context)); + + rc = rclc_support_fini(&support); + EXPECT_EQ(RCL_RET_OK, rc); +} + +TEST(Test, rclc_allocator_alloc_default) { + // test heap allocation and freeing + rcl_allocator_t * allocator_heap = rclc_allocator_alloc_default(); + EXPECT_NE(nullptr, allocator_heap); + rcl_ret_t rc = rclc_allocator_free(allocator_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} diff --git a/rclc/test/rclc/test_node.cpp b/rclc/test/rclc/test_node.cpp index 7dfcd01d..1a638231 100644 --- a/rclc/test/rclc/test_node.cpp +++ b/rclc/test/rclc/test_node.cpp @@ -113,3 +113,11 @@ TEST(Test, rclc_node_init_with_options) { rc = rclc_support_fini(&support); EXPECT_EQ(RCL_RET_OK, rc); } + +TEST(Test, rclc_alloc_zero_initialized_node) { + // test heap allocation and freeing + rcl_node_t * node_heap = rclc_alloc_zero_initialized_node(); + EXPECT_NE(nullptr, node_heap); + rcl_ret_t rc = rclc_node_free(node_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} \ No newline at end of file diff --git a/rclc/test/rclc/test_publisher.cpp b/rclc/test/rclc/test_publisher.cpp index c9faabb5..3f87b8aa 100644 --- a/rclc/test/rclc/test_publisher.cpp +++ b/rclc/test/rclc/test_publisher.cpp @@ -154,3 +154,11 @@ TEST(Test, rclc_publisher_init_qos) { rc = rclc_support_fini(&support); EXPECT_EQ(RCL_RET_OK, rc); } + +TEST(Test, rclc_publisher_alloc) { + // test heap allocation and freeing + rcl_publisher_t * publisher_heap = rclc_publisher_alloc(); + EXPECT_NE(nullptr, publisher_heap); + rcl_ret_t rc = rclc_publisher_free(publisher_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} \ No newline at end of file diff --git a/rclc/test/rclc/test_subscription.cpp b/rclc/test/rclc/test_subscription.cpp index 45723752..1236b24d 100644 --- a/rclc/test/rclc/test_subscription.cpp +++ b/rclc/test/rclc/test_subscription.cpp @@ -151,3 +151,11 @@ TEST(Test, rclc_subscription_init_qos) { rc = rclc_support_fini(&support); EXPECT_EQ(RCL_RET_OK, rc); } + +TEST(Test, rclc_alloc_zero_initialized_subscription) { + // test heap allocation and freeing + rcl_subscription_t * subscription_heap = rclc_alloc_zero_initialized_subscription(); + EXPECT_NE(nullptr, subscription_heap); + rcl_ret_t rc = rclc_subscription_free(subscription_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} \ No newline at end of file diff --git a/rclc/test/rclc/test_timer.cpp b/rclc/test/rclc/test_timer.cpp index ce5c8671..fae5da13 100644 --- a/rclc/test/rclc/test_timer.cpp +++ b/rclc/test/rclc/test_timer.cpp @@ -56,3 +56,11 @@ TEST(Test, rclc_timer_init_default) { rc = rclc_support_fini(&support); EXPECT_EQ(RCL_RET_OK, rc); } + +TEST(Test, rclc_alloc_zero_initialized_timer) { + // test heap allocation and freeing + rcl_timer_t * timer_heap = rclc_alloc_zero_initialized_timer(); + EXPECT_NE(nullptr, timer_heap); + rcl_ret_t rc = rclc_timer_free(timer_heap); + EXPECT_EQ(RCL_RET_OK, rc); +} From 7209d04aaf5c24038ba05e45819648746090a41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Tue, 25 Jun 2024 17:47:47 +0200 Subject: [PATCH 2/4] Use user provided allocator for explicit allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick Häcker --- rclc/include/rclc/executor.h | 10 +++++----- rclc/include/rclc/init.h | 11 +++++++---- rclc/include/rclc/node.h | 9 ++++++--- rclc/include/rclc/publisher.h | 10 +++++++--- rclc/include/rclc/subscription.h | 11 ++++++++--- rclc/include/rclc/timer.h | 9 +++++++-- rclc/src/rclc/executor.c | 10 +++++----- rclc/src/rclc/init.c | 16 +++++++++------- rclc/src/rclc/node.c | 12 ++++++------ rclc/src/rclc/publisher.c | 9 +++++---- rclc/src/rclc/subscription.c | 13 +++++++------ rclc/src/rclc/timer.c | 12 ++++++------ rclc/test/rclc/test_executor.cpp | 7 ++++--- rclc/test/rclc/test_init.cpp | 10 +++++----- rclc/test/rclc/test_node.cpp | 7 ++++--- rclc/test/rclc/test_publisher.cpp | 7 ++++--- rclc/test/rclc/test_subscription.cpp | 7 ++++--- rclc/test/rclc/test_timer.cpp | 7 ++++--- 18 files changed, 103 insertions(+), 74 deletions(-) diff --git a/rclc/include/rclc/executor.h b/rclc/include/rclc/executor.h index 74e2fd9c..f0bc5697 100644 --- a/rclc/include/rclc/executor.h +++ b/rclc/include/rclc/executor.h @@ -982,10 +982,9 @@ rclc_executor_trigger_one( void * obj); /** - * Allocates an rclc_executor_t object on the heap and sets its values to - * zero. Can be used as an alternative to - * rclc_executor_get_zero_initialized_executor() if no stack allocation can - * or should be used. + * Allocates an rclc_executor_t object and sets its values to zero. Can be + * used as an alternative to rclc_executor_get_zero_initialized_executor() if + * no stack allocation can or should be used. * * *
* Attribute | Adherence @@ -995,12 +994,13 @@ rclc_executor_trigger_one( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator the rcl_allocator_t to be used * \return pointer to the executor (rclc_executor_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rclc_executor_t * -rclc_alloc_zero_initialized_executor(); +rclc_alloc_zero_initialized_executor(const rcl_allocator_t * const allocator); /** * De-allocates an rclc_executor_t object and sets the pointer to NULL. diff --git a/rclc/include/rclc/init.h b/rclc/include/rclc/init.h index d939d0d9..e3a51d5a 100644 --- a/rclc/include/rclc/init.h +++ b/rclc/include/rclc/init.h @@ -105,8 +105,8 @@ rclc_support_fini( rclc_support_t * support); /** - * Allocates the rclc_support_t object on the heap. - * Can be used as if no stack allocation can or should be used. + * Allocates memory for an rclc_support_t object. + * Can be used if no stack allocation can or should be used. * * *
* Attribute | Adherence @@ -116,12 +116,13 @@ rclc_support_fini( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator the rcl_allocator_t to be used * \return pointer to the support (rclc_support_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rclc_support_t * -rclc_support_alloc(); +rclc_support_alloc(const rcl_allocator_t * const allocator); /** * Return the pointer to the context member of struct support. @@ -154,12 +155,14 @@ rclc_get_context( * Lock-Free | No * * \param[inout] support a heap-allocated rclc_support_t + * \param[in] allocator the rcl_allocator_t to be used * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ rcl_ret_t rclc_support_free( - rclc_support_t * support); + rclc_support_t * support, + const rcl_allocator_t * const allocator); /** diff --git a/rclc/include/rclc/node.h b/rclc/include/rclc/node.h index 835aab29..26829493 100644 --- a/rclc/include/rclc/node.h +++ b/rclc/include/rclc/node.h @@ -79,7 +79,7 @@ rclc_node_init_with_options( rcl_node_options_t * node_ops); /** - * Allocates an rcl_node_t object on the heap and sets its values to zero. + * Allocates an rcl_node_t object and sets its values to zero. * Can be used as an alternative to rcl_get_zero_initialized_node() if no * stack allocation can or should be used. * @@ -91,12 +91,13 @@ rclc_node_init_with_options( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator the rcl_allocator_t to be used * \return pointer to the node (rcl_node_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rcl_node_t * -rclc_alloc_zero_initialized_node(); +rclc_alloc_zero_initialized_node(const rcl_allocator_t * const allocator); /** * De-allocates an rcl_node_t object and sets the pointer to NULL. @@ -110,13 +111,15 @@ rclc_alloc_zero_initialized_node(); * Lock-Free | No * * \param[inout] node a heap-allocated rcl_node_t + * \param[in] allocator the rcl_allocator_t to be used * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ RCLC_PUBLIC rcl_ret_t rclc_node_free( - rcl_node_t * node); + rcl_node_t * node, + const rcl_allocator_t * const allocator); #if __cplusplus } diff --git a/rclc/include/rclc/publisher.h b/rclc/include/rclc/publisher.h index 653aa400..34cac163 100644 --- a/rclc/include/rclc/publisher.h +++ b/rclc/include/rclc/publisher.h @@ -109,7 +109,7 @@ rclc_publisher_init( const rmw_qos_profile_t * qos_profile); /** - * Allocates an rcl_publisher_t object on the heap. + * Allocates memory for an rcl_publisher_t object. * Can be used as if no stack allocation can or should be used. * * *
@@ -120,12 +120,14 @@ rclc_publisher_init( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator the rcl_allocator_t to be used * \return pointer to a publisher (rcl_publisher_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rcl_publisher_t * -rclc_publisher_alloc(); +rclc_publisher_alloc( + const rcl_allocator_t * const allocator); /** * De-allocates an rcl_publisher_t object and sets the pointer to NULL. @@ -139,12 +141,14 @@ rclc_publisher_alloc(); * Lock-Free | No * * \param[inout] publisher a heap-allocated rcl_publisher_t + * \param[in] allocator the rcl_allocator_t to be used * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ rcl_ret_t rclc_publisher_free( - rcl_publisher_t * publisher); + rcl_publisher_t * publisher, + const rcl_allocator_t * const allocator); #if __cplusplus } diff --git a/rclc/include/rclc/subscription.h b/rclc/include/rclc/subscription.h index 9d238a85..39f224ba 100644 --- a/rclc/include/rclc/subscription.h +++ b/rclc/include/rclc/subscription.h @@ -108,7 +108,7 @@ rclc_subscription_init( const rmw_qos_profile_t * qos_profile); /** - * Allocates an rcl_subscription_t object on the heap and sets its values to zero. + * Allocates an rcl_subscription_t object and sets its values to zero. * Can be used as an alternative to rcl_get_zero_initialized_subscription() if no * stack allocation can or should be used. * @@ -120,12 +120,15 @@ rclc_subscription_init( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator the rcl_allocator_t to be used * \return pointer to the subscription (rcl_subscription_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rcl_subscription_t * -rclc_alloc_zero_initialized_subscription(); +rclc_alloc_zero_initialized_subscription( + const rcl_allocator_t * const allocator +); /** * De-allocates an rcl_subscription_t object and sets the pointer to NULL. @@ -139,13 +142,15 @@ rclc_alloc_zero_initialized_subscription(); * Lock-Free | No * * \param[inout] subscription a heap-allocated rcl_subscription_t + * \param[in] allocator the rcl_allocator_t to be used * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ RCLC_PUBLIC rcl_ret_t rclc_subscription_free( - rcl_subscription_t * subscription); + rcl_subscription_t * subscription, + const rcl_allocator_t * const allocator); #if __cplusplus } diff --git a/rclc/include/rclc/timer.h b/rclc/include/rclc/timer.h index a7e47ecf..a397402e 100644 --- a/rclc/include/rclc/timer.h +++ b/rclc/include/rclc/timer.h @@ -64,12 +64,15 @@ rclc_timer_init_default( * Uses Atomics | No * Lock-Free | No * + * \param[in] allocator allocator for allocating memory * \return pointer to the timer (rcl_timer_t) * \return NULL, if no memory could be allocated. */ RCLC_PUBLIC rcl_timer_t * -rclc_alloc_zero_initialized_timer(); +rclc_alloc_zero_initialized_timer( + const rcl_allocator_t * const allocator +); /** * De-allocates an rcl_timer_t object and sets the pointer to NULL. @@ -83,13 +86,15 @@ rclc_alloc_zero_initialized_timer(); * Lock-Free | No * * \param[inout] timer a heap-allocated rcl_timer_t + * \param[in] allocator the rcl_allocator_t to be used * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ RCLC_PUBLIC rcl_ret_t rclc_timer_free( - rcl_timer_t * timer); + rcl_timer_t * timer, + const rcl_allocator_t * const allocator); #if __cplusplus } diff --git a/rclc/src/rclc/executor.c b/rclc/src/rclc/executor.c index 39ea9e14..3e522c8c 100644 --- a/rclc/src/rclc/executor.c +++ b/rclc/src/rclc/executor.c @@ -2121,13 +2121,13 @@ bool rclc_executor_trigger_always(rclc_executor_handle_t * handles, unsigned int } rclc_executor_t * -rclc_alloc_zero_initialized_executor() +rclc_alloc_zero_initialized_executor(const rcl_allocator_t * const allocator) { - rclc_executor_t * executor = (rclc_executor_t *) malloc(sizeof(rclc_executor_t)); + rclc_executor_t * executor = (rclc_executor_t *) + allocator->allocate(sizeof(rclc_executor_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( executor, "executor is a null pointer", return executor); - rclc_executor_t executor_stack = rclc_executor_get_zero_initialized_executor(); - memcpy(executor, &executor_stack, sizeof(rclc_executor_t)); + *executor = rclc_executor_get_zero_initialized_executor(); return executor; } @@ -2136,7 +2136,7 @@ rclc_executor_free(rclc_executor_t * executor) { RCL_CHECK_FOR_NULL_WITH_MSG( executor, "executor is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(executor); + executor->allocator->deallocate(executor, executor->allocator->state); executor = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/init.c b/rclc/src/rclc/init.c index bdac0def..eaace013 100644 --- a/rclc/src/rclc/init.c +++ b/rclc/src/rclc/init.c @@ -109,20 +109,21 @@ rclc_support_fini(rclc_support_t * support) } rclc_support_t * -rclc_support_alloc() +rclc_support_alloc(const rcl_allocator_t * const allocator) { - rclc_support_t * support = (rclc_support_t *) malloc(sizeof(rclc_support_t)); + rclc_support_t * support = (rclc_support_t *) + allocator->allocate(sizeof(rclc_support_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( support, "support is a null pointer", return support); return support; } rcl_ret_t -rclc_support_free(rclc_support_t * support) +rclc_support_free(rclc_support_t * support, const rcl_allocator_t * const allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( support, "support is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(support); + allocator->deallocate(support, allocator->state); support = NULL; return RCL_RET_OK; } @@ -140,10 +141,11 @@ rclc_get_context(rclc_support_t * support) rcl_allocator_t * rclc_allocator_alloc_default() { - rcl_allocator_t * allocator = (rcl_allocator_t *) malloc(sizeof(rcutils_allocator_t)); + rcl_allocator_t allocator_stack = rcl_get_default_allocator(); + rcl_allocator_t * allocator = (rcl_allocator_t *) + allocator_stack.allocate(sizeof(rcutils_allocator_t), allocator_stack.state); RCL_CHECK_FOR_NULL_WITH_MSG( allocator, "allocator is a null pointer", return allocator); - rcl_allocator_t allocator_stack = rcl_get_default_allocator(); memcpy(allocator, &allocator_stack, sizeof(rcl_allocator_t)); return allocator; } @@ -153,7 +155,7 @@ rclc_allocator_free(rcl_allocator_t * allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( allocator, "allocator is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(allocator); + allocator->deallocate(allocator, allocator->state); allocator = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/node.c b/rclc/src/rclc/node.c index 17f56246..f57f39e7 100644 --- a/rclc/src/rclc/node.c +++ b/rclc/src/rclc/node.c @@ -86,22 +86,22 @@ rclc_node_init_with_options( } rcl_node_t * -rclc_alloc_zero_initialized_node() +rclc_alloc_zero_initialized_node(const rcl_allocator_t * const allocator) { - rcl_node_t * node = (rcl_node_t *) malloc(sizeof(rcl_node_t)); + rcl_node_t * node = (rcl_node_t *) + allocator->allocate(sizeof(rcl_node_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( node, "node is a null pointer", return node); - rcl_node_t node_stack = rcl_get_zero_initialized_node(); - memcpy(node, &node_stack, sizeof(rcl_node_t)); + *node = rcl_get_zero_initialized_node(); return node; } rcl_ret_t -rclc_node_free(rcl_node_t * node) +rclc_node_free(rcl_node_t * node, const rcl_allocator_t * const allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( node, "node is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(node); + allocator->deallocate(node, allocator->state); node = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/publisher.c b/rclc/src/rclc/publisher.c index 420a20e9..33f61ef7 100644 --- a/rclc/src/rclc/publisher.c +++ b/rclc/src/rclc/publisher.c @@ -82,9 +82,10 @@ rclc_publisher_init( RCLC_PUBLIC rcl_publisher_t * -rclc_publisher_alloc() +rclc_publisher_alloc(const rcl_allocator_t * const allocator) { - rcl_publisher_t * publisher = (rcl_publisher_t *) malloc(sizeof(rcl_publisher_t)); + rcl_publisher_t * publisher = (rcl_publisher_t *) + allocator->allocate(sizeof(rcl_publisher_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( publisher, "publisher is a null pointer", return publisher); return publisher; @@ -92,11 +93,11 @@ rclc_publisher_alloc() rcl_ret_t rclc_publisher_free( - rcl_publisher_t * publisher) + rcl_publisher_t * publisher, const rcl_allocator_t * const allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( publisher, "publisher is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(publisher); + allocator->deallocate(publisher, allocator->state); publisher = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/subscription.c b/rclc/src/rclc/subscription.c index ca3028cb..a9512bc5 100644 --- a/rclc/src/rclc/subscription.c +++ b/rclc/src/rclc/subscription.c @@ -81,22 +81,23 @@ rclc_subscription_init( } rcl_subscription_t * -rclc_alloc_zero_initialized_subscription() +rclc_alloc_zero_initialized_subscription(const rcl_allocator_t * const allocator) { - rcl_subscription_t * subscription = (rcl_subscription_t *) malloc(sizeof(rcl_subscription_t)); + rcl_subscription_t * subscription = (rcl_subscription_t *) + allocator->allocate(sizeof(rcl_subscription_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( subscription, "subscription is a null pointer", return subscription); - rcl_subscription_t subscription_stack = rcl_get_zero_initialized_subscription(); - memcpy(subscription, &subscription_stack, sizeof(rcl_subscription_t)); + *subscription = rcl_get_zero_initialized_subscription(); return subscription; } rcl_ret_t -rclc_subscription_free(rcl_subscription_t * subscription) +rclc_subscription_free( + rcl_subscription_t * subscription, const rcl_allocator_t * const allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( subscription, "subscription is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(subscription); + allocator->deallocate(subscription, allocator->state); subscription = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/timer.c b/rclc/src/rclc/timer.c index 86f3c381..9667f4c3 100644 --- a/rclc/src/rclc/timer.c +++ b/rclc/src/rclc/timer.c @@ -48,22 +48,22 @@ rclc_timer_init_default( } rcl_timer_t * -rclc_alloc_zero_initialized_timer() +rclc_alloc_zero_initialized_timer(const rcl_allocator_t * const allocator) { - rcl_timer_t * timer = (rcl_timer_t *) malloc(sizeof(rcl_timer_t)); + rcl_timer_t * timer = (rcl_timer_t *) + allocator->allocate(sizeof(rcl_timer_t), allocator->state); RCL_CHECK_FOR_NULL_WITH_MSG( timer, "timer is a null pointer", return timer); - rcl_timer_t timer_stack = rcl_get_zero_initialized_timer(); - memcpy(timer, &timer_stack, sizeof(rcl_timer_t)); + *timer = rcl_get_zero_initialized_timer(); return timer; } rcl_ret_t -rclc_timer_free(rcl_timer_t * timer) +rclc_timer_free(rcl_timer_t * timer, const rcl_allocator_t * const allocator) { RCL_CHECK_FOR_NULL_WITH_MSG( timer, "timer is a null pointer", return RCL_RET_INVALID_ARGUMENT); - free(timer); + allocator->deallocate(timer, allocator->state); timer = NULL; return RCL_RET_OK; } diff --git a/rclc/test/rclc/test_executor.cpp b/rclc/test/rclc/test_executor.cpp index 5749d8c8..64dd42f5 100644 --- a/rclc/test/rclc/test_executor.cpp +++ b/rclc/test/rclc/test_executor.cpp @@ -2807,8 +2807,9 @@ TEST_F(TestDefaultExecutor, executor_test_remove_guard_condition) { TEST(TestDefaultExecutor, rclc_alloc_zero_initialized_executor) { // test heap allocation and freeing - rclc_executor_t * executor_heap = rclc_alloc_zero_initialized_executor(); - EXPECT_NE(nullptr, executor_heap); - rcl_ret_t rc = rclc_executor_fini(executor_heap); + const rcl_allocator_t allocator = rcl_get_default_allocator(); + rclc_executor_t * executor = rclc_alloc_zero_initialized_executor(&allocator); + EXPECT_NE(nullptr, executor); + rcl_ret_t rc = rclc_executor_fini(executor); EXPECT_EQ(RCL_RET_OK, rc); } \ No newline at end of file diff --git a/rclc/test/rclc/test_init.cpp b/rclc/test/rclc/test_init.cpp index 19359a8d..a21907ca 100644 --- a/rclc/test/rclc/test_init.cpp +++ b/rclc/test/rclc/test_init.cpp @@ -87,17 +87,17 @@ TEST(Test, rclc_support_fini) { TEST(Test, rclc_support_alloc) { // test heap allocation and freeing - rclc_support_t * support_heap = rclc_support_alloc(); - EXPECT_NE(nullptr, support_heap); - rcl_ret_t rc = rclc_support_free(support_heap); + rcl_allocator_t allocator = rcl_get_default_allocator(); + rclc_support_t * support = rclc_support_alloc(&allocator); + EXPECT_NE(nullptr, support); + rcl_ret_t rc = rclc_support_free(support, &allocator); EXPECT_EQ(RCL_RET_OK, rc); } TEST(Test, rclc_get_context) { rclc_support_t support; - rcl_ret_t rc; rcl_allocator_t allocator = rcl_get_default_allocator(); - rc = rclc_support_init(&support, 0, nullptr, &allocator); + rcl_ret_t rc = rclc_support_init(&support, 0, nullptr, &allocator); EXPECT_EQ(RCL_RET_OK, rc); rcl_context_t *context = rclc_get_context(&support); diff --git a/rclc/test/rclc/test_node.cpp b/rclc/test/rclc/test_node.cpp index 1a638231..40af2986 100644 --- a/rclc/test/rclc/test_node.cpp +++ b/rclc/test/rclc/test_node.cpp @@ -116,8 +116,9 @@ TEST(Test, rclc_node_init_with_options) { TEST(Test, rclc_alloc_zero_initialized_node) { // test heap allocation and freeing - rcl_node_t * node_heap = rclc_alloc_zero_initialized_node(); - EXPECT_NE(nullptr, node_heap); - rcl_ret_t rc = rclc_node_free(node_heap); + const rcl_allocator_t allocator = rcl_get_default_allocator(); + rcl_node_t * node = rclc_alloc_zero_initialized_node(&allocator); + EXPECT_NE(nullptr, node); + rcl_ret_t rc = rclc_node_free(node, &allocator); EXPECT_EQ(RCL_RET_OK, rc); } \ No newline at end of file diff --git a/rclc/test/rclc/test_publisher.cpp b/rclc/test/rclc/test_publisher.cpp index 3f87b8aa..41e8c21d 100644 --- a/rclc/test/rclc/test_publisher.cpp +++ b/rclc/test/rclc/test_publisher.cpp @@ -157,8 +157,9 @@ TEST(Test, rclc_publisher_init_qos) { TEST(Test, rclc_publisher_alloc) { // test heap allocation and freeing - rcl_publisher_t * publisher_heap = rclc_publisher_alloc(); - EXPECT_NE(nullptr, publisher_heap); - rcl_ret_t rc = rclc_publisher_free(publisher_heap); + const rcl_allocator_t allocator = rcl_get_default_allocator(); + rcl_publisher_t * publisher = rclc_publisher_alloc(&allocator); + EXPECT_NE(nullptr, publisher); + rcl_ret_t rc = rclc_publisher_free(publisher, &allocator); EXPECT_EQ(RCL_RET_OK, rc); } \ No newline at end of file diff --git a/rclc/test/rclc/test_subscription.cpp b/rclc/test/rclc/test_subscription.cpp index 1236b24d..1df00116 100644 --- a/rclc/test/rclc/test_subscription.cpp +++ b/rclc/test/rclc/test_subscription.cpp @@ -154,8 +154,9 @@ TEST(Test, rclc_subscription_init_qos) { TEST(Test, rclc_alloc_zero_initialized_subscription) { // test heap allocation and freeing - rcl_subscription_t * subscription_heap = rclc_alloc_zero_initialized_subscription(); - EXPECT_NE(nullptr, subscription_heap); - rcl_ret_t rc = rclc_subscription_free(subscription_heap); + const rcl_allocator_t allocator = rcl_get_default_allocator(); + rcl_subscription_t * subscription = rclc_alloc_zero_initialized_subscription(&allocator); + EXPECT_NE(nullptr, subscription); + rcl_ret_t rc = rclc_subscription_free(subscription, &allocator); EXPECT_EQ(RCL_RET_OK, rc); } \ No newline at end of file diff --git a/rclc/test/rclc/test_timer.cpp b/rclc/test/rclc/test_timer.cpp index fae5da13..648d2adb 100644 --- a/rclc/test/rclc/test_timer.cpp +++ b/rclc/test/rclc/test_timer.cpp @@ -59,8 +59,9 @@ TEST(Test, rclc_timer_init_default) { TEST(Test, rclc_alloc_zero_initialized_timer) { // test heap allocation and freeing - rcl_timer_t * timer_heap = rclc_alloc_zero_initialized_timer(); - EXPECT_NE(nullptr, timer_heap); - rcl_ret_t rc = rclc_timer_free(timer_heap); + const rcl_allocator_t allocator = rcl_get_default_allocator(); + rcl_timer_t * timer = rclc_alloc_zero_initialized_timer(&allocator); + EXPECT_NE(nullptr, timer); + rcl_ret_t rc = rclc_timer_free(timer, &allocator); EXPECT_EQ(RCL_RET_OK, rc); } From e79f906a4a60af4a6dd5093b662f938bc53cc4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Wed, 26 Jun 2024 07:12:52 +0200 Subject: [PATCH 3/4] Move the responsibility of pointer zeroing to the caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick Häcker --- rclc/include/rclc/executor.h | 2 +- rclc/include/rclc/init.h | 7 +++---- rclc/include/rclc/node.h | 2 +- rclc/include/rclc/publisher.h | 2 +- rclc/include/rclc/subscription.h | 2 +- rclc/include/rclc/timer.h | 2 +- rclc/src/rclc/executor.c | 1 - rclc/src/rclc/init.c | 2 -- rclc/src/rclc/node.c | 1 - rclc/src/rclc/publisher.c | 1 - rclc/src/rclc/subscription.c | 1 - rclc/src/rclc/timer.c | 1 - rclc/test/rclc/test_executor.cpp | 2 ++ rclc/test/rclc/test_init.cpp | 8 +++++--- rclc/test/rclc/test_node.cpp | 1 + rclc/test/rclc/test_publisher.cpp | 1 + rclc/test/rclc/test_subscription.cpp | 1 + rclc/test/rclc/test_timer.cpp | 1 + 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/rclc/include/rclc/executor.h b/rclc/include/rclc/executor.h index f0bc5697..c51b738c 100644 --- a/rclc/include/rclc/executor.h +++ b/rclc/include/rclc/executor.h @@ -1003,7 +1003,7 @@ rclc_executor_t * rclc_alloc_zero_initialized_executor(const rcl_allocator_t * const allocator); /** - * De-allocates an rclc_executor_t object and sets the pointer to NULL. + * De-allocates an rclc_executor_t object. * * *
* Attribute | Adherence diff --git a/rclc/include/rclc/init.h b/rclc/include/rclc/init.h index e3a51d5a..d5e90b3e 100644 --- a/rclc/include/rclc/init.h +++ b/rclc/include/rclc/init.h @@ -144,7 +144,7 @@ rclc_get_context( rclc_support_t * support); /** - * De-allocates the rclc_support_t object and sets the pointer to NULL. + * De-allocates an rclc_support_t object. * * *
* Attribute | Adherence @@ -166,8 +166,7 @@ rclc_support_free( /** - * Allocates the rcl_allocator_t object on the heap and sets it with default - * values. + * Allocates the rcl_allocator_t object and sets it to default values. * Can be used as an alternative to rcl_get_default_allocator() if no * stack allocation can or should be used. * @@ -187,7 +186,7 @@ rcl_allocator_t * rclc_allocator_alloc_default(); /** - * De-allocates the rcl_allocator_t object and sets the pointer to NULL. + * De-allocates an rcl_allocator_t object. * * *
* Attribute | Adherence diff --git a/rclc/include/rclc/node.h b/rclc/include/rclc/node.h index 26829493..2bcce763 100644 --- a/rclc/include/rclc/node.h +++ b/rclc/include/rclc/node.h @@ -100,7 +100,7 @@ rcl_node_t * rclc_alloc_zero_initialized_node(const rcl_allocator_t * const allocator); /** - * De-allocates an rcl_node_t object and sets the pointer to NULL. + * De-allocates an rcl_node_t object. * * *
* Attribute | Adherence diff --git a/rclc/include/rclc/publisher.h b/rclc/include/rclc/publisher.h index 34cac163..bce9ad1d 100644 --- a/rclc/include/rclc/publisher.h +++ b/rclc/include/rclc/publisher.h @@ -130,7 +130,7 @@ rclc_publisher_alloc( const rcl_allocator_t * const allocator); /** - * De-allocates an rcl_publisher_t object and sets the pointer to NULL. + * De-allocates an rcl_publisher_t object. * * *
* Attribute | Adherence diff --git a/rclc/include/rclc/subscription.h b/rclc/include/rclc/subscription.h index 39f224ba..24c330bd 100644 --- a/rclc/include/rclc/subscription.h +++ b/rclc/include/rclc/subscription.h @@ -131,7 +131,7 @@ rclc_alloc_zero_initialized_subscription( ); /** - * De-allocates an rcl_subscription_t object and sets the pointer to NULL. + * De-allocates an rcl_subscription_t object. * * *
* Attribute | Adherence diff --git a/rclc/include/rclc/timer.h b/rclc/include/rclc/timer.h index a397402e..0dd4c573 100644 --- a/rclc/include/rclc/timer.h +++ b/rclc/include/rclc/timer.h @@ -75,7 +75,7 @@ rclc_alloc_zero_initialized_timer( ); /** - * De-allocates an rcl_timer_t object and sets the pointer to NULL. + * De-allocates an rcl_timer_t object. * * *
* Attribute | Adherence diff --git a/rclc/src/rclc/executor.c b/rclc/src/rclc/executor.c index 3e522c8c..b5324a34 100644 --- a/rclc/src/rclc/executor.c +++ b/rclc/src/rclc/executor.c @@ -2137,6 +2137,5 @@ rclc_executor_free(rclc_executor_t * executor) RCL_CHECK_FOR_NULL_WITH_MSG( executor, "executor is a null pointer", return RCL_RET_INVALID_ARGUMENT); executor->allocator->deallocate(executor, executor->allocator->state); - executor = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/init.c b/rclc/src/rclc/init.c index eaace013..d7ca08e4 100644 --- a/rclc/src/rclc/init.c +++ b/rclc/src/rclc/init.c @@ -124,7 +124,6 @@ rclc_support_free(rclc_support_t * support, const rcl_allocator_t * const alloca RCL_CHECK_FOR_NULL_WITH_MSG( support, "support is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(support, allocator->state); - support = NULL; return RCL_RET_OK; } @@ -156,7 +155,6 @@ rclc_allocator_free(rcl_allocator_t * allocator) RCL_CHECK_FOR_NULL_WITH_MSG( allocator, "allocator is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(allocator, allocator->state); - allocator = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/node.c b/rclc/src/rclc/node.c index f57f39e7..bd64453f 100644 --- a/rclc/src/rclc/node.c +++ b/rclc/src/rclc/node.c @@ -102,6 +102,5 @@ rclc_node_free(rcl_node_t * node, const rcl_allocator_t * const allocator) RCL_CHECK_FOR_NULL_WITH_MSG( node, "node is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(node, allocator->state); - node = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/publisher.c b/rclc/src/rclc/publisher.c index 33f61ef7..d186461d 100644 --- a/rclc/src/rclc/publisher.c +++ b/rclc/src/rclc/publisher.c @@ -98,6 +98,5 @@ rclc_publisher_free( RCL_CHECK_FOR_NULL_WITH_MSG( publisher, "publisher is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(publisher, allocator->state); - publisher = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/subscription.c b/rclc/src/rclc/subscription.c index a9512bc5..e000e550 100644 --- a/rclc/src/rclc/subscription.c +++ b/rclc/src/rclc/subscription.c @@ -98,6 +98,5 @@ rclc_subscription_free( RCL_CHECK_FOR_NULL_WITH_MSG( subscription, "subscription is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(subscription, allocator->state); - subscription = NULL; return RCL_RET_OK; } diff --git a/rclc/src/rclc/timer.c b/rclc/src/rclc/timer.c index 9667f4c3..cfbfd8fa 100644 --- a/rclc/src/rclc/timer.c +++ b/rclc/src/rclc/timer.c @@ -64,6 +64,5 @@ rclc_timer_free(rcl_timer_t * timer, const rcl_allocator_t * const allocator) RCL_CHECK_FOR_NULL_WITH_MSG( timer, "timer is a null pointer", return RCL_RET_INVALID_ARGUMENT); allocator->deallocate(timer, allocator->state); - timer = NULL; return RCL_RET_OK; } diff --git a/rclc/test/rclc/test_executor.cpp b/rclc/test/rclc/test_executor.cpp index 64dd42f5..fdf0b8e1 100644 --- a/rclc/test/rclc/test_executor.cpp +++ b/rclc/test/rclc/test_executor.cpp @@ -2812,4 +2812,6 @@ TEST(TestDefaultExecutor, rclc_alloc_zero_initialized_executor) { EXPECT_NE(nullptr, executor); rcl_ret_t rc = rclc_executor_fini(executor); EXPECT_EQ(RCL_RET_OK, rc); + rclc_executor_free(executor); + executor = nullptr; } \ No newline at end of file diff --git a/rclc/test/rclc/test_init.cpp b/rclc/test/rclc/test_init.cpp index a21907ca..6e344fd5 100644 --- a/rclc/test/rclc/test_init.cpp +++ b/rclc/test/rclc/test_init.cpp @@ -92,6 +92,7 @@ TEST(Test, rclc_support_alloc) { EXPECT_NE(nullptr, support); rcl_ret_t rc = rclc_support_free(support, &allocator); EXPECT_EQ(RCL_RET_OK, rc); + support = nullptr; } TEST(Test, rclc_get_context) { @@ -110,8 +111,9 @@ TEST(Test, rclc_get_context) { TEST(Test, rclc_allocator_alloc_default) { // test heap allocation and freeing - rcl_allocator_t * allocator_heap = rclc_allocator_alloc_default(); - EXPECT_NE(nullptr, allocator_heap); - rcl_ret_t rc = rclc_allocator_free(allocator_heap); + rcl_allocator_t * allocator = rclc_allocator_alloc_default(); + EXPECT_NE(nullptr, allocator); + rcl_ret_t rc = rclc_allocator_free(allocator); EXPECT_EQ(RCL_RET_OK, rc); + allocator = nullptr; } diff --git a/rclc/test/rclc/test_node.cpp b/rclc/test/rclc/test_node.cpp index 40af2986..92d7881d 100644 --- a/rclc/test/rclc/test_node.cpp +++ b/rclc/test/rclc/test_node.cpp @@ -121,4 +121,5 @@ TEST(Test, rclc_alloc_zero_initialized_node) { EXPECT_NE(nullptr, node); rcl_ret_t rc = rclc_node_free(node, &allocator); EXPECT_EQ(RCL_RET_OK, rc); + node = nullptr; } \ No newline at end of file diff --git a/rclc/test/rclc/test_publisher.cpp b/rclc/test/rclc/test_publisher.cpp index 41e8c21d..4697f624 100644 --- a/rclc/test/rclc/test_publisher.cpp +++ b/rclc/test/rclc/test_publisher.cpp @@ -162,4 +162,5 @@ TEST(Test, rclc_publisher_alloc) { EXPECT_NE(nullptr, publisher); rcl_ret_t rc = rclc_publisher_free(publisher, &allocator); EXPECT_EQ(RCL_RET_OK, rc); + publisher = nullptr; } \ No newline at end of file diff --git a/rclc/test/rclc/test_subscription.cpp b/rclc/test/rclc/test_subscription.cpp index 1df00116..a1ffa33e 100644 --- a/rclc/test/rclc/test_subscription.cpp +++ b/rclc/test/rclc/test_subscription.cpp @@ -159,4 +159,5 @@ TEST(Test, rclc_alloc_zero_initialized_subscription) { EXPECT_NE(nullptr, subscription); rcl_ret_t rc = rclc_subscription_free(subscription, &allocator); EXPECT_EQ(RCL_RET_OK, rc); + subscription = nullptr; } \ No newline at end of file diff --git a/rclc/test/rclc/test_timer.cpp b/rclc/test/rclc/test_timer.cpp index 648d2adb..d51c3f5e 100644 --- a/rclc/test/rclc/test_timer.cpp +++ b/rclc/test/rclc/test_timer.cpp @@ -64,4 +64,5 @@ TEST(Test, rclc_alloc_zero_initialized_timer) { EXPECT_NE(nullptr, timer); rcl_ret_t rc = rclc_timer_free(timer, &allocator); EXPECT_EQ(RCL_RET_OK, rc); + timer = nullptr; } From 4c26ba6361e97a6c07433ed677cdf2f6f4e4d629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20H=C3=A4cker?= Date: Fri, 5 Jul 2024 09:36:24 +0200 Subject: [PATCH 4/4] Add getter for all support fields for completeness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick Häcker --- rclc/include/rclc/init.h | 40 +++++++++++++++++++++++++++++++++++++++- rclc/src/rclc/init.c | 15 +++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/rclc/include/rclc/init.h b/rclc/include/rclc/init.h index d5e90b3e..16dab806 100644 --- a/rclc/include/rclc/init.h +++ b/rclc/include/rclc/init.h @@ -135,7 +135,7 @@ rclc_support_alloc(const rcl_allocator_t * const allocator); * Uses Atomics | No * Lock-Free | Yes * - * \param[inout] support a heap-allocated rclc_support_t + * \param[inout] support an instance of type rclc_support_t * \return `RCL_RET_OK` if operation was successful * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument */ @@ -143,6 +143,44 @@ rcl_context_t * rclc_get_context( rclc_support_t * support); +/** + * Return the pointer to the allocator member of struct support. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[inout] support an instance of type rclc_support_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +rcl_allocator_t * +rclc_get_allocator( + rclc_support_t * support); + +/** + * Return the pointer to the clock member of struct support. + * + * *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[inout] support an instance of type rclc_support_t + * \return `RCL_RET_OK` if operation was successful + * \return `RCL_RET_INVALID_ARGUMENT` if any null pointer as argument + */ +rcl_clock_t * +rclc_get_clock( + rclc_support_t * support); + /** * De-allocates an rclc_support_t object. * diff --git a/rclc/src/rclc/init.c b/rclc/src/rclc/init.c index d7ca08e4..095c1d29 100644 --- a/rclc/src/rclc/init.c +++ b/rclc/src/rclc/init.c @@ -136,6 +136,21 @@ rclc_get_context(rclc_support_t * support) return &(support->context); } +rcl_allocator_t * +rclc_get_allocator(rclc_support_t * support) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + support, "support is a null pointer", return (rcl_allocator_t *) NULL); + return support->allocator; +} + +rcl_clock_t * +rclc_get_clock(rclc_support_t * support) +{ + RCL_CHECK_FOR_NULL_WITH_MSG( + support, "support is a null pointer", return (rcl_clock_t *) NULL); + return &(support->clock); +} rcl_allocator_t * rclc_allocator_alloc_default()