-
Notifications
You must be signed in to change notification settings - Fork 181
Ensure no redundant rcl_logging initialization and finalization (alternative) #573
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,19 +19,24 @@ extern "C" | |
|
|
||
| #include "rcl/init.h" | ||
|
|
||
| #include "./arguments_impl.h" | ||
| #include "./common.h" | ||
| #include "./context_impl.h" | ||
| #include "./init_options_impl.h" | ||
| #include "rcl/arguments.h" | ||
| #include "rcl/error_handling.h" | ||
| #include "rcl/logging.h" | ||
ivanpauno marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| #include "rcutils/logging_macros.h" | ||
| #include "rcutils/stdatomic_helper.h" | ||
|
|
||
| #include "rmw/error_handling.h" | ||
|
|
||
| #include "tracetools/tracetools.h" | ||
|
|
||
| static atomic_uint_least64_t __rcl_next_unique_id = ATOMIC_VAR_INIT(1); | ||
| #include "./arguments_impl.h" | ||
| #include "./common.h" | ||
| #include "./context_impl.h" | ||
| #include "./init_options_impl.h" | ||
|
|
||
| static atomic_uint_least64_t g_rcl_next_unique_id = ATOMIC_VAR_INIT(1); | ||
| static atomic_uint_least64_t g_logging_ref_count = ATOMIC_VAR_INIT(0); | ||
|
|
||
| rcl_ret_t | ||
| rcl_init( | ||
|
|
@@ -122,23 +127,35 @@ rcl_init( | |
| goto fail; | ||
| } | ||
|
|
||
| ret = rcl_logging_configure(&context->global_arguments, &allocator); | ||
| if (RCL_RET_OK != ret) { | ||
| fail_ret = ret; | ||
| RCUTILS_LOG_ERROR_NAMED( | ||
| ROS_PACKAGE_NAME, | ||
| "Failed to configure logging: %s", | ||
| rcutils_get_error_string().str); | ||
| goto fail; | ||
| if (0u == rcutils_atomic_fetch_add_uint64_t(&g_logging_ref_count, 1)) { | ||
| ret = rcl_logging_configure(&context->global_arguments, &allocator); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚡️ context switch here, then:
My conclusion is that
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mmm, I see what you meant now. So, I always considered that the upper layer will ensure that each Under that situation, using an atomic count adds protection between My main reason for pushing this alternative, it's that it solves the problem in a more "minimalistic" way (only one PR, without adding functions like [*] If calls in each context between
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But what about this case: init1-shutdown1-init2-... Where shutdown1 is interrupted after adjusting the atomic count, but before it does log fini, and context switches to init2 which then increments it, finding that according to the count logging was not initialized, and tries to initialize logging when it already has been. Either the "initialize while already initialized" case will fail, or if that silently passes, when shutdown1 continues it will shutdown logging and leave init2 initialized but without logging. I remain unconvinced that this is thread-safe even when using separate context objects.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh 🤦♂️, I completed miss that case. Thanks William!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's ok, this stuff is tricky. I've only learned to be very suspicious of creating thread-safety with just atomics after messing it up many, many times. :) Maybe it's possible to salvage this approach with enough iteration, but honestly I think a global mutex provided by rclpy/rclcpp is the safest thing to do to protect the init/shutdown and therefore logging init.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I agree.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can go ahead to take them! thanks for your effort! |
||
| if (RCL_RET_OK != ret) { | ||
| fail_ret = ret; | ||
| RCUTILS_LOG_ERROR_NAMED( | ||
| ROS_PACKAGE_NAME, | ||
| "Failed to configure logging: %s", | ||
| rcutils_get_error_string().str); | ||
| goto fail; | ||
| } | ||
| } else { | ||
| // Check if logging configurations were specified again or not. | ||
| // It's not possible to check that in the already parsed `context->global_arguments` | ||
| // as many of the configurations have default values matching a possible argument. | ||
| if (rcl_contains_logging_arguments(argc, argv)) { | ||
| RCUTILS_LOG_WARN_NAMED( | ||
| ROS_PACKAGE_NAME, | ||
| "rcl_init was called more than once with logging arguments," | ||
| "ignoring the last logging configuration"); | ||
| } | ||
| } | ||
|
|
||
| // Set the instance id. | ||
| uint64_t next_instance_id = rcutils_atomic_fetch_add_uint64_t(&__rcl_next_unique_id, 1); | ||
| uint64_t next_instance_id = rcutils_atomic_fetch_add_uint64_t(&g_rcl_next_unique_id, 1); | ||
| if (0 == next_instance_id) { | ||
| // Roll over occurred, this is an extremely unlikely occurrence. | ||
| RCL_SET_ERROR_MSG("unique rcl instance ids exhausted"); | ||
| // Roll back to try to avoid the next call succeeding, but there's a data race here. | ||
| rcutils_atomic_store(&__rcl_next_unique_id, -1); | ||
| rcutils_atomic_store(&g_rcl_next_unique_id, -1); | ||
| goto fail; | ||
| } | ||
| rcutils_atomic_store((atomic_uint_least64_t *)(&context->instance_id_storage), next_instance_id); | ||
|
|
@@ -184,13 +201,22 @@ rcl_shutdown(rcl_context_t * context) | |
| RCL_SET_ERROR_MSG(rmw_get_error_string().str); | ||
| return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret); | ||
| } | ||
|
|
||
| rcl_ret_t rcl_ret = rcl_logging_fini(); | ||
| RCUTILS_LOG_ERROR_EXPRESSION_NAMED( | ||
| RCL_RET_OK != rcl_ret, ROS_PACKAGE_NAME, | ||
| "Failed to fini logging, rcl_ret_t: %i, rcl_error_str: %s", rcl_ret, | ||
| rcl_get_error_string().str); | ||
| rcl_reset_error(); | ||
| size_t previous_logging_ref_count = | ||
| rcutils_atomic_fetch_add_uint64_t(&g_logging_ref_count, -1); | ||
|
|
||
| if (1u == previous_logging_ref_count) { | ||
ivanpauno marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| rcl_ret_t rcl_ret = rcl_logging_fini(); | ||
| RCUTILS_LOG_ERROR_EXPRESSION_NAMED( | ||
| RCL_RET_OK != rcl_ret, ROS_PACKAGE_NAME, | ||
| "Failed to fini logging, rcl_ret_t: %i, rcl_error_str: %s", rcl_ret, | ||
| rcl_get_error_string().str); | ||
| rcl_reset_error(); | ||
| } else if (0u >= previous_logging_ref_count) { | ||
| rcutils_atomic_fetch_add_uint64_t(&g_logging_ref_count, 1); | ||
| RCUTILS_LOG_ERROR_NAMED( | ||
| ROS_PACKAGE_NAME, | ||
| "logging was already finished"); | ||
| } | ||
|
|
||
| return RCL_RET_OK; | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.