Skip to content

[rcl_action] Implement init/fini functions for types#312

Merged
jacobperron merged 9 commits intomasterfrom
jacob/action_types
Oct 31, 2018
Merged

[rcl_action] Implement init/fini functions for types#312
jacobperron merged 9 commits intomasterfrom
jacob/action_types

Conversation

@jacobperron
Copy link
Copy Markdown
Member

Connects to #306.

Refactored API. Removed init/fini functions for types that do not necessarily need allocation on the heap.
Added unit tests for implementation.

@jacobperron jacobperron added in progress Actively being worked on (Kanban column) in review Waiting for review (Kanban column) and removed in progress Actively being worked on (Kanban column) labels Oct 30, 2018
@jacobperron jacobperron mentioned this pull request Oct 30, 2018
10 tasks
@jacobperron
Copy link
Copy Markdown
Member Author

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

rcl_action_goal_info_t
rcl_action_get_zero_initialized_goal_info(void)
{
static rcl_action_goal_info_t goal_info = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron I wonder if just goal_info = {0} would do for all compilers (as it does for gcc).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that will work. For some reason I thought the internal uuid array wasn't initializing with the proper size.

rcl_action_get_zero_initialized_cancel_request(void)
{
static rcl_action_cancel_request_t request;
request.goal_info = rcl_action_get_zero_initialized_goal_info();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron this one's tricky, we rely on the compiler to be smart enough to not call rcl_action_get_zero_initialized_goal_info() every single time. How wrong would it be to go with request = {0}; only?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

rcl_action_cancel_response_t
rcl_action_get_zero_initialized_cancel_response(void)
{
static rcl_action_cancel_response_t response;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron missing zero initialization?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

TEST(TestActionTypes, test_get_zero_inititalized_goal_info)
{
rcl_action_goal_info_t goal_info = rcl_action_get_zero_initialized_goal_info();
ASSERT_EQ(sizeof(goal_info.uuid) / sizeof(uint8_t), 16lu);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron that long literal qualifier is painfully similar to a 1, I wonder which compiler complains if missing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to 16u seems okay.

goal_info.stamp.nanosec = 4567u;
rcl_action_goal_info_t another_goal_info = rcl_action_get_zero_initialized_goal_info();
for (int i = 0; i < 16; ++i) {
EXPECT_EQ(goal_info.uuid[i], i);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron what's the rationale for this test? A comment explaining it would be super helpful.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a sanity check for myself that creating a second object with the function did not interfere with the first. I'm okay to remove the second goal test if you think it's too pedantic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good test, but I would add a comment explaining it for the unaware reader.

TEST(TestActionTypes, test_get_zero_initialized_cancel_response)
{
rcl_action_cancel_response_t cancel_response = rcl_action_get_zero_initialized_cancel_response();
ASSERT_EQ(cancel_response.goals_canceling.size, 0lu);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron shouldn't we check for the pointer to be NULL too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added check.

// Initialize with invalid status array
rcl_ret_t ret = rcl_action_goal_status_array_init(
nullptr,
(size_t) 3,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron consider making these two above constants for better readability and deduplication.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Copy Markdown
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two extra tiny bits.

rcl_action_goal_status_array_t
rcl_action_get_zero_initialized_goal_status_array(void)
{
static rcl_action_goal_status_array_t status_array;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron missing zero initialization?

{
rcl_action_goal_status_array_t status_array =
rcl_action_get_zero_initialized_goal_status_array();
ASSERT_EQ(sizeof(status_array.status_list) / sizeof(rcl_action_goal_status_t), 0u);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron what's this intent of this test? Won't sizeof(status_array.status_list) be always the same?

@hidmic
Copy link
Copy Markdown
Contributor

hidmic commented Oct 30, 2018

Also, it looks like MSVC is complaining about linkage again -.-

@jacobperron
Copy link
Copy Markdown
Member Author

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@jacobperron jacobperron reopened this Oct 30, 2018
@jacobperron jacobperron added in progress Actively being worked on (Kanban column) and removed in review Waiting for review (Kanban column) labels Oct 30, 2018
@jacobperron
Copy link
Copy Markdown
Member Author

Also, it looks like MSVC is complaining about linkage again -.-

Forgot to uncomment the cmake line that should resolve this

@jacobperron
Copy link
Copy Markdown
Member Author

Also, it looks like Clang wants braces around initialization of sub-objects in the zero init functions.

@jacobperron
Copy link
Copy Markdown
Member Author

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@hidmic
Copy link
Copy Markdown
Contributor

hidmic commented Oct 30, 2018

Looks like Clang is a bit picky.

@jacobperron jacobperron self-assigned this Oct 30, 2018
@jacobperron
Copy link
Copy Markdown
Member Author

Up to rcl_action:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

🎉

Refactored API. Removed init/fini functions for types that do not necessarily need allocation on the heap.
Added unit tests for implementation.
- Simplify and add missing zero initializers
- Replace `lu` qualifier with `u`
- Add null ptr check in cancel response zero init test
- Make size arguments constants
This is to satisfy Clang warnings.
@jacobperron
Copy link
Copy Markdown
Member Author

Rebased on master (resolving conflicts in CMakeLists.txt).

CI (up to rcl_action):

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@jacobperron jacobperron added in review Waiting for review (Kanban column) and removed in progress Actively being worked on (Kanban column) labels Oct 31, 2018
Copy link
Copy Markdown
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

{
rcl_action_goal_status_array_t status_array =
rcl_action_get_zero_initialized_goal_status_array();
// ASSERT_EQ(sizeof(status_array.status_list.data) / sizeof(rcl_action_goal_status_t), 0u);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacobperron nit: remove the comment.

@jacobperron jacobperron merged commit f9dfc5d into master Oct 31, 2018
@jacobperron jacobperron deleted the jacob/action_types branch October 31, 2018 20:36
@jacobperron jacobperron removed the in review Waiting for review (Kanban column) label Oct 31, 2018
Copy link
Copy Markdown
Contributor

@sloretz sloretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit late with the review, just some minor comments

${rcl_action_sources}
)
target_link_libraries(${PROJECT_NAME}
${rcl_LIBRARIES}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rcl_action_get_zero_initialized_cancel_response(void);
rcl_action_goal_status_array_fini(
rcl_action_goal_status_array_t * status_array,
const rcl_allocator_t allocator);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend storing allocator in rcl_action_goal_status_array_t to avoid accidentally deallocating with the wrong allocator.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, it is defined as:

typedef action_msgs__msg__GoalStatusArray rcl_action_goal_status_array_t;

If we want to include space for the allocator, then I suppose we should do something like:

typedef struct rcl_action_goal_status_array_t
{
  action_msgs__msg__GoalStatusArray msg;
  rcl_allocator_t allocator;
} rcl_action_goal_status_array_t;

I can make a follow-up PR to address this and your other comments.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 came here to say this, I noticed it in the API when rebasing my pr (#314).

rcl_action_cancel_response_fini(
rcl_action_cancel_response_t * cancel_response,
rcl_action_server_t * action_server);
const rcl_allocator_t allocator);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about storing allocator rather than passing it to fini

RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(status_array, RCL_RET_INVALID_ARGUMENT, allocator);
// Ensure status array is zero initialized
if (status_array->status_list.size > 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should this function do if it is called with num_status = 0?

RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(cancel_response, RCL_RET_INVALID_ARGUMENT, allocator);
// Ensure cancel response is zero initialized
if (cancel_response->goals_canceling.size > 0) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should this function do if num_goals_canceling = 0?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default allocator uses calloc, which has undefined behavior if the size is zero

If size is zero, the return value depends on the particular library implementation (it may or may not be a null pointer), but the returned pointer shall not be dereferenced.

http://www.cplusplus.com/reference/cstdlib/calloc/

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Perhaps it should return RCL_RET_INVALID_ARGUMENT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants