-
Notifications
You must be signed in to change notification settings - Fork 90
Add realtime priority inheritance mutexes #197
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
Merged
christophfroehlich
merged 33 commits into
ros-controls:master
from
pal-robotics-forks:add/realtime/mutexes
Dec 21, 2024
Merged
Changes from 22 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
c2e1c10
add first version of the mutex with priority inheritance
saikishor 05ce6bc
added documentation and remove the copy constructor and assignment op…
saikishor 1921f21
change the name of the mutex to priority_inheritance_mutex
saikishor 1a18c6e
Remove pthread_mutexattr_setprioceiling as the protocol is set to PTH…
saikishor 040a904
templatize the class and create different instance with using
saikishor 742177e
Add cerr to mention that the owner is died so user is aware of it
saikishor f392b21
Add tests to the priority inheritance mutex
saikishor bad11ed
add documentation and more template arguments
saikishor 9f33a30
Address MR comments
saikishor 0a8343f
remove the virtual instances from the methods
saikishor bb1f880
Change the exceptions to system_error
saikishor 1b371cc
Change to cerrno
saikishor 1d0f911
Add noexcept to some methods
saikishor 8ecf332
use attr_cleanup_t to cleanup properly without any memory_leaks
saikishor bbfb3ca
Remove the protocol and ceiling template arguments
saikishor 3e610d9
Add detail namespace as suggested
saikishor 0fab814
test with different lock constructors
saikishor cee4ee9
Change to system_categeory
saikishor 0611b82
add tests on deadlock detection
saikishor 07e4e3a
Just use the default mutex with PTHREAD_MUTEX_ERRORCHECK
saikishor 91cce17
Rename the mutexes prefixing `prio_inherit_`
saikishor 8c6e1e2
Merge branch 'master' into add/realtime/mutexes
saikishor 6f332bf
Exclude the windows using mutex.hpp
saikishor c16d73a
Merge branch 'master' into add/realtime/mutexes
saikishor 58452ff
create class enums for defining the template types
saikishor 5b3028c
Make the mutexes work with the std::is_same for conditioning in code
saikishor 7409bca
Merge branch 'master' into add/realtime/mutexes
saikishor 3a7edb2
indent the condition in CMakeLists.txt
saikishor 3dd885f
Merge branch 'master' into add/realtime/mutexes
saikishor ca86ba3
Merge branch 'master' into add/realtime/mutexes
saikishor f7198ee
Merge branch 'master' into add/realtime/mutexes
saikishor 8ee40da
Merge branch 'master' into add/realtime/mutexes
saikishor 8b0bded
Merge branch 'master' into add/realtime/mutexes
saikishor File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| // Copyright 2024 PAL Robotics S.L. | ||
| // | ||
| // 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. | ||
|
|
||
| /// \author Sai Kishor Kothakota | ||
|
|
||
| #ifndef REALTIME_TOOLS__MUTEX_HPP_ | ||
| #define REALTIME_TOOLS__MUTEX_HPP_ | ||
|
|
||
| #include <pthread.h> | ||
| #include <cerrno> | ||
| #include <cstring> | ||
| #include <iostream> | ||
| #include <memory> | ||
| #include <stdexcept> | ||
| #include <string> | ||
|
|
||
| /** | ||
| * @brief A pthread mutex wrapper that provides a mutex with the priority inheritance | ||
| * protocol and a priority ceiling of 99. | ||
| * The mutex is also error checked and robust. | ||
| * This mutex is intended to be used in real-time contexts. | ||
| * @note This mutex is not recursive. | ||
| */ | ||
| namespace realtime_tools | ||
| { | ||
| namespace detail | ||
| { | ||
| /** | ||
| * @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 | ||
saikishor marked this conversation as resolved.
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 MutexRobustness> | ||
saikishor marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
saikishor marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| class mutex | ||
| { | ||
| public: | ||
| using native_handle_type = pthread_mutex_t *; | ||
|
|
||
| mutex() | ||
| { | ||
| pthread_mutexattr_t attr; | ||
|
|
||
| const auto attr_destroy = [](pthread_mutexattr_t * mutex_attr) { | ||
| // Destroy the mutex attributes | ||
| const auto res_destroy = pthread_mutexattr_destroy(mutex_attr); | ||
| if (res_destroy != 0) { | ||
| throw std::system_error( | ||
| res_destroy, std::generic_category(), "Failed to destroy mutex attribute"); | ||
| } | ||
| }; | ||
| using attr_cleanup_t = std::unique_ptr<pthread_mutexattr_t, decltype(attr_destroy)>; | ||
| auto attr_cleanup = attr_cleanup_t(&attr, attr_destroy); | ||
|
|
||
| // Initialize the mutex attributes | ||
| const auto res_attr = pthread_mutexattr_init(&attr); | ||
| if (res_attr != 0) { | ||
| throw std::system_error( | ||
| res_attr, std::system_category(), "Failed to initialize mutex attribute"); | ||
| } | ||
|
|
||
| // Set the mutex type to MutexType | ||
saikishor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const auto res_type = pthread_mutexattr_settype(&attr, MutexType); | ||
|
|
||
| if (res_type != 0) { | ||
| throw std::system_error(res_type, std::system_category(), "Failed to set mutex type"); | ||
| } | ||
|
|
||
| // Set the mutex attribute to use the protocol PTHREAD_PRIO_INHERIT | ||
| const auto res_protocol = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); | ||
| if (res_protocol != 0) { | ||
| throw std::system_error(res_protocol, std::system_category(), "Failed to set mutex protocol"); | ||
| } | ||
|
|
||
| // Set the mutex attribute robustness to MutexRobustness | ||
| const auto res_robust = pthread_mutexattr_setrobust(&attr, MutexRobustness); | ||
| if (res_robust != 0) { | ||
| throw std::system_error(res_robust, std::system_category(), "Failed to set mutex robustness"); | ||
| } | ||
|
|
||
| // Initialize the mutex with the attributes | ||
| const auto res_init = pthread_mutex_init(&mutex_, &attr); | ||
| if (res_init != 0) { | ||
| throw std::system_error(res_init, std::system_category(), "Failed to initialize mutex"); | ||
| } | ||
| } | ||
|
|
||
| ~mutex() | ||
| { | ||
| const auto res = pthread_mutex_destroy(&mutex_); | ||
| if (res != 0) { | ||
| std::cerr << "Failed to destroy mutex : " << std::strerror(res) << std::endl; | ||
saikishor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| mutex(const mutex &) = delete; | ||
|
|
||
| mutex & operator=(const mutex &) = delete; | ||
|
|
||
| native_handle_type native_handle() noexcept { return &mutex_; } | ||
|
|
||
| void lock() | ||
| { | ||
| const auto res = pthread_mutex_lock(&mutex_); | ||
| if (res == 0) { | ||
| return; | ||
| } | ||
| if (res == EOWNERDEAD) { | ||
| const auto res_consistent = pthread_mutex_consistent(&mutex_); | ||
| if (res_consistent != 0) { | ||
| throw std::runtime_error( | ||
| std::string("Failed to make mutex consistent : ") + std::strerror(res_consistent)); | ||
| } | ||
| std::cerr << "Mutex owner died, but the mutex is consistent now. This shouldn't happen!" | ||
| << std::endl; | ||
| } else if (res == EDEADLK) { | ||
| throw std::system_error(res, std::system_category(), "Deadlock detected"); | ||
| } else { | ||
saikishor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| throw std::runtime_error(std::string("Failed to lock mutex : ") + std::strerror(res)); | ||
| } | ||
| } | ||
|
|
||
| void unlock() noexcept | ||
| { | ||
| // As per the requirements of BasicLockable concept, unlock should not throw | ||
| const auto res = pthread_mutex_unlock(&mutex_); | ||
| if (res != 0) { | ||
| std::cerr << "Failed to unlock mutex : " << std::strerror(res) << std::endl; | ||
| } | ||
| } | ||
|
|
||
| bool try_lock() | ||
| { | ||
| const auto res = pthread_mutex_trylock(&mutex_); | ||
| if (res == 0) { | ||
| return true; | ||
| } | ||
| if (res == EBUSY) { | ||
| return false; | ||
| } else if (res == EOWNERDEAD) { | ||
| const auto res_consistent = pthread_mutex_consistent(&mutex_); | ||
| if (res_consistent != 0) { | ||
| throw std::runtime_error( | ||
| std::string("Failed to make mutex consistent : ") + std::strerror(res_consistent)); | ||
| } | ||
| std::cerr << "Mutex owner died, but the mutex is consistent now. This shouldn't happen!" | ||
| << std::endl; | ||
| } else if (res == EDEADLK) { | ||
| throw std::system_error(res, std::system_category(), "Deadlock detected"); | ||
| } else { | ||
| throw std::runtime_error(std::string("Failed to try lock mutex : ") + std::strerror(res)); | ||
saikishor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| pthread_mutex_t mutex_; | ||
| }; | ||
| } // namespace detail | ||
| using prio_inherit_mutex = detail::mutex<PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_ROBUST>; | ||
| using prio_inherit_recursive_mutex = detail::mutex<PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ROBUST>; | ||
| } // namespace realtime_tools | ||
|
|
||
| #endif // REALTIME_TOOLS__MUTEX_HPP_ | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.