11#include "unfair_mutex_intf.hpp"
13#include "../utility/utility.hpp"
14#include "../macros.hpp"
22hi_export_module(hikogui.concurrency.unfair_mutex : impl);
24hi_export
namespace hi {
inline namespace v1 {
27hi_inline unfair_mutex_impl<false> unfair_mutex_deadlock_mutex;
38[[
nodiscard]] hi_inline
void *unfair_mutex_deadlock_check_graph(
void *
object)
noexcept
40 hi_assert_not_null(
object);
42 auto const lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
44 for (
auto const before : unfair_mutex_deadlock_stack) {
49 unfair_mutex_deadlock_lock_graph.cbegin(), unfair_mutex_deadlock_lock_graph.cend(),
correct_order)) {
55 unfair_mutex_deadlock_lock_graph.cbegin(), unfair_mutex_deadlock_lock_graph.cend(),
reverse_order)) {
82 hi_assert_not_null(
object);
84 if (
std::count(detail::unfair_mutex_deadlock_stack.
begin(), detail::unfair_mutex_deadlock_stack.
end(),
object) != 0) {
89 if (
auto before = detail::unfair_mutex_deadlock_check_graph(
object)) {
94 detail::unfair_mutex_deadlock_stack.push_back(
object);
109 hi_assert_not_null(
object);
112 if (detail::unfair_mutex_deadlock_stack.empty()) {
117 if (detail::unfair_mutex_deadlock_stack.back() !=
object) {
121 detail::unfair_mutex_deadlock_stack.pop_back();
133 hi_assert_not_null(
object);
140 auto const lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
141 std::erase_if(detail::unfair_mutex_deadlock_lock_graph, [
object](
auto const&
item) {
156 detail::unfair_mutex_deadlock_stack.clear();
169 auto const lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
170 detail::unfair_mutex_deadlock_lock_graph.clear();
173template<
bool UseDeadLockDetector>
174hi_inline unfair_mutex_impl<UseDeadLockDetector>::~unfair_mutex_impl()
176 hi_axiom(
not is_locked());
182template<
bool UseDeadLockDetector>
183hi_inline
bool unfair_mutex_impl<UseDeadLockDetector>::is_locked()
const noexcept
185 return semaphore.load(std::memory_order::relaxed) != 0;
188template<
bool UseDeadLockDetector>
189hi_inline
void unfair_mutex_impl<UseDeadLockDetector>::lock()
noexcept
193 hi_assert(
other !=
this,
"This mutex is already locked.");
194 hi_assert(
other ==
nullptr,
"Potential dead-lock because of different lock ordering of mutexes.");
197 hi_axiom(holds_invariant());
201 if (
not semaphore.compare_exchange_strong(
expected, 1, std::memory_order::acquire)) {
205 hi_axiom(holds_invariant());
215template<
bool UseDeadLockDetector>
220 hi_assert(
other !=
this,
"This mutex is already locked.");
221 hi_assert(
other ==
nullptr,
"Potential dead-lock because of different lock ordering of mutexes.");
224 hi_axiom(holds_invariant());
228 if (
not semaphore.compare_exchange_strong(
expected, 1, std::memory_order::acquire)) {
229 hi_axiom(holds_invariant());
238 hi_axiom(holds_invariant());
242template<
bool UseDeadLockDetector>
249 hi_axiom(holds_invariant());
251 if (semaphore.fetch_sub(1, std::memory_order::relaxed) != 1) {
252 [[
unlikely]] semaphore.store(0, std::memory_order::release);
254 semaphore.notify_one();
256 atomic_thread_fence(std::memory_order::release);
259 hi_axiom(holds_invariant());
262template<
bool UseDeadLockDetector>
265 return semaphore.load(std::memory_order::relaxed) <= 2;
268template<
bool UseDeadLockDetector>
269hi_no_inline hi_inline
void unfair_mutex_impl<UseDeadLockDetector>::lock_contended(semaphore_value_type
expected)
noexcept
271 hi_axiom(holds_invariant());
279 hi_axiom(holds_invariant());
283 hi_axiom(holds_invariant());
286 }
while (!semaphore.compare_exchange_strong(
expected, 2));
An atomic access global variable for quick access to state of the system.
hi_inline bool is_system_shutting_down() noexcept
Check if the HikoGUI system is being shut down.
Definition global_state.hpp:222
@ end
Start from the end of the file.
@ begin
Start from the beginning of the file.
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
hi_export hi_inline void * unfair_mutex_deadlock_lock(void *object) noexcept
Lock an object on this thread.
Definition unfair_mutex_impl.hpp:75
hi_export hi_inline void unfair_mutex_deadlock_clear_stack() noexcept
Clear the stack.
Definition unfair_mutex_impl.hpp:149
hi_export hi_inline void unfair_mutex_deadlock_clear_graph() noexcept
Clear the graph.
Definition unfair_mutex_impl.hpp:162
hi_export hi_inline bool unfair_mutex_deadlock_unlock(void *object) noexcept
Unlock an object on this thread.
Definition unfair_mutex_impl.hpp:102
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
hi_export hi_inline void unfair_mutex_deadlock_remove_object(void *object) noexcept
Remove the object from the detection.
Definition unfair_mutex_impl.hpp:131
An unfair mutex This is a fast implementation of a mutex which does not fairly arbitrate between mult...
Definition unfair_mutex_intf.hpp:38
bool try_lock() noexcept
When try_lock() is called from a thread that already owns the lock it will return false.
Definition unfair_mutex_impl.hpp:216
T binary_search(T... args)