Skip to content
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

Add realtime priority inheritance mutexes #197

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

saikishor
Copy link
Member

Add realtime priority inheritance mutexes for using within the realtime loops

@codecov-commenter
Copy link

codecov-commenter commented Nov 20, 2024

Codecov Report

Attention: Patch coverage is 46.42857% with 30 lines in your changes missing coverage. Please review.

Project coverage is 69.82%. Comparing base (97f9f41) to head (c5250a1).

Files with missing lines Patch % Lines
include/realtime_tools/mutex.hpp 46.42% 19 Missing and 11 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #197      +/-   ##
==========================================
- Coverage   73.11%   69.82%   -3.30%     
==========================================
  Files           8        9       +1     
  Lines         398      454      +56     
  Branches       65       77      +12     
==========================================
+ Hits          291      317      +26     
- Misses         68       87      +19     
- Partials       39       50      +11     
Flag Coverage Δ
unittests 69.82% <46.42%> (-3.30%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
include/realtime_tools/mutex.hpp 46.42% <46.42%> (ø)
---- 🚨 Try these New Features:

test/realtime_mutex_tests.cpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
* @tparam MutexCeiling The priority ceiling of the mutex. It can be any integer value valid for the scheduling policy of the thread. It is only used if MutexProtocol is PTHREAD_PRIO_PROTECT
* @tparam MutexRobustness The robustness of the mutex. It can be one of the following: PTHREAD_MUTEX_STALLED, PTHREAD_MUTEX_ROBUST
*/
template <int MutexType, int MutexProtocol, int MutexCeiling, int MutexRobustness>
Copy link

Choose a reason for hiding this comment

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

I would replace plain ints for class enums where apply.
These enums should be located inside the sub namespace detail

* @tparam MutexCeiling The priority ceiling of the mutex. It can be any integer value valid for the scheduling policy of the thread. It is only used if MutexProtocol is PTHREAD_PRIO_PROTECT
* @tparam MutexRobustness The robustness of the mutex. It can be one of the following: PTHREAD_MUTEX_STALLED, PTHREAD_MUTEX_ROBUST
*/
template <int MutexType, int MutexProtocol, int MutexCeiling, int MutexRobustness>
Copy link

Choose a reason for hiding this comment

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

I would expose the template parameters in the class itself because it is quite handy to check for them in generic code.
I mean something like:

namespace ... {
class enum mutex_type_t { ... };
namespace detail {
  class mutex<mutex_type_t MutexType, ...> { constexpr auto type = MutexType; ... }
} // detail
} // ...

include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
{
const auto res = pthread_mutex_destroy(&mutex_);
if (res != 0) {
std::cerr << "Failed to destroy mutex : " << std::strerror(res) << std::endl;
Copy link

Choose a reason for hiding this comment

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

No logging through cerr, I would use any logging mechanism in the framework or do nothing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you please explain why std::cerr cannot be used here?

Copy link

Choose a reason for hiding this comment

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

Because, as a system integrator using your stuff, I would like to configure, redirect and filter the logs of my system as it is documented in the framework.

Maybe using something like RCLCPP_FATAL(rclcpp::get_logger("ros_control_logger"), msg); ?

Copy link

Choose a reason for hiding this comment

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

as explained aside, if your concern is to be more ROS-agnostic then rely on weak symbols, in C parlance, extern declarations.

extern "C" {
extern int logAsError(int line, const char* file, const char* msg);
extern int logAsInfo(int line, const char* file, const char* msg);
}

// in ros-control
#define LOG_ERROR(msg) do { (void)logAsError(__LINE__, __FILE__, (msg)); } while(0);
...

and then the one generating the executable must implement them to prevent a linker error, for instance:

// in a ROS node project linking with ros-control...
// my_log_as_handlers.cpp
extern "C" {
int logAsError(int line, const char* file, const char* msg) {
  ROS_LOG_ERROR(...);
}
int logAsInfo(int line, const char* file, const char* msg);
  ROS_LOG_INFO(...);
}
}

include/realtime_tools/mutex.hpp Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Show resolved Hide resolved
/**
* @brief A class template that provides a pthread mutex with the priority inheritance protocol
*
* @tparam MutexType The type of the mutex. It can be one of the following: PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_DEFAULT
Copy link

Choose a reason for hiding this comment

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

If your intention is to implement a general wrapper for POSIX mutexes, this review is going to take time...

I would suggest to decrease the scope of the endeavor and just implement the PTHREAD_PRIO_INHERIT.

That means:

  • rephrase the documentation
  • prevent users to instantiate non-PRIO_INHERIT mutexes (easy if you use class enums as suggested below)

Additionally I think it is not good idea to support some combinations ever (i.e. PTHREAD_MUTEX_NORMAL + PTHREAD_PRIO_NONE) because they are already implemented in the STL [1]

[1] I am a bit nervous here when trying to understand which c++ mutexes conform to the POSIX standard:

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree with you, I will reduce the scope. Thanks for pointing out

Regarding to the PTHREAD_MUTEX_DEFAULT, I choose it because of the explanation given here : https://linux.die.net/man/3/pthread_mutexattr_settype

include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
{
const auto res = pthread_mutex_destroy(&mutex_);
if (res != 0) {
std::cerr << "Failed to destroy mutex : " << std::strerror(res) << std::endl;
Copy link

Choose a reason for hiding this comment

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

as explained aside, if your concern is to be more ROS-agnostic then rely on weak symbols, in C parlance, extern declarations.

extern "C" {
extern int logAsError(int line, const char* file, const char* msg);
extern int logAsInfo(int line, const char* file, const char* msg);
}

// in ros-control
#define LOG_ERROR(msg) do { (void)logAsError(__LINE__, __FILE__, (msg)); } while(0);
...

and then the one generating the executable must implement them to prevent a linker error, for instance:

// in a ROS node project linking with ros-control...
// my_log_as_handlers.cpp
extern "C" {
int logAsError(int line, const char* file, const char* msg) {
  ROS_LOG_ERROR(...);
}
int logAsInfo(int line, const char* file, const char* msg);
  ROS_LOG_INFO(...);
}
}

include/realtime_tools/mutex.hpp Outdated Show resolved Hide resolved
* @tparam MutexRobustness The robustness of the mutex. It can be one of the following: PTHREAD_MUTEX_STALLED, PTHREAD_MUTEX_ROBUST
*/
template <int MutexType, int MutexProtocol, int MutexCeiling, int MutexRobustness>
class MutexBase
template <int MutexType, int MutexRobustness>
Copy link

Choose a reason for hiding this comment

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

build vs run-time errors:

static_assert to prevent unsupported instantiations like detail::mutex<83, 29>

Copy link
Member Author

Choose a reason for hiding this comment

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

ok

include/realtime_tools/mutex.hpp Show resolved Hide resolved
include/realtime_tools/mutex.hpp Show resolved Hide resolved
}
}

TEST(PriorityInheritanceMutexTests, test_error_mutex)
Copy link

Choose a reason for hiding this comment

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

testing a dead-lock would be great!

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