11#include "unfair_mutex_intf.hpp"
13#include "../utility/utility.hpp"
14#include "../macros.hpp"
19hi_export_module(hikogui.concurrency.unfair_mutex : impl);
21namespace hi {
inline namespace v1 {
24inline unfair_mutex_impl<false> unfair_mutex_deadlock_mutex;
35[[
nodiscard]]
inline void *unfair_mutex_deadlock_check_graph(
void *
object)
noexcept
37 hi_assert_not_null(
object);
39 hilet
lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
41 for (hilet before : unfair_mutex_deadlock_stack) {
46 unfair_mutex_deadlock_lock_graph.cbegin(), unfair_mutex_deadlock_lock_graph.cend(),
correct_order)) {
52 unfair_mutex_deadlock_lock_graph.cbegin(), unfair_mutex_deadlock_lock_graph.cend(),
reverse_order)) {
79 hi_assert_not_null(
object);
81 if (
std::count(detail::unfair_mutex_deadlock_stack.
begin(), detail::unfair_mutex_deadlock_stack.
end(),
object) != 0) {
86 if (
auto before = detail::unfair_mutex_deadlock_check_graph(
object)) {
91 detail::unfair_mutex_deadlock_stack.push_back(
object);
106 hi_assert_not_null(
object);
109 if (detail::unfair_mutex_deadlock_stack.empty()) {
114 if (detail::unfair_mutex_deadlock_stack.back() !=
object) {
118 detail::unfair_mutex_deadlock_stack.pop_back();
130 hi_assert_not_null(
object);
137 hilet lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
138 std::erase_if(detail::unfair_mutex_deadlock_lock_graph, [
object](hilet& item) {
139 return item.first ==
object or item.second ==
object;
153 detail::unfair_mutex_deadlock_stack.clear();
166 hilet lock = std::scoped_lock(detail::unfair_mutex_deadlock_mutex);
167 detail::unfair_mutex_deadlock_lock_graph.clear();
170template<
bool UseDeadLockDetector>
171inline unfair_mutex_impl<UseDeadLockDetector>::~unfair_mutex_impl()
173 hi_axiom(
not is_locked());
179template<
bool UseDeadLockDetector>
180inline bool unfair_mutex_impl<UseDeadLockDetector>::is_locked()
const noexcept
182 return semaphore.load(std::memory_order::relaxed) != 0;
185template<
bool UseDeadLockDetector>
186inline void unfair_mutex_impl<UseDeadLockDetector>::lock()
noexcept
190 hi_assert(
other !=
this,
"This mutex is already locked.");
191 hi_assert(
other ==
nullptr,
"Potential dead-lock because of different lock ordering of mutexes.");
194 hi_axiom(holds_invariant());
198 if (
not semaphore.compare_exchange_strong(
expected, 1, std::memory_order::acquire)) {
202 hi_axiom(holds_invariant());
212template<
bool UseDeadLockDetector>
217 hi_assert(
other !=
this,
"This mutex is already locked.");
218 hi_assert(
other ==
nullptr,
"Potential dead-lock because of different lock ordering of mutexes.");
221 hi_axiom(holds_invariant());
225 if (
not semaphore.compare_exchange_strong(
expected, 1, std::memory_order::acquire)) {
226 hi_axiom(holds_invariant());
235 hi_axiom(holds_invariant());
239template<
bool UseDeadLockDetector>
246 hi_axiom(holds_invariant());
248 if (semaphore.fetch_sub(1, std::memory_order::relaxed) != 1) {
249 [[
unlikely]] semaphore.store(0, std::memory_order::release);
251 semaphore.notify_one();
253 atomic_thread_fence(std::memory_order::release);
256 hi_axiom(holds_invariant());
259template<
bool UseDeadLockDetector>
262 return semaphore.load(std::memory_order::relaxed) <= 2;
265template<
bool UseDeadLockDetector>
266hi_no_inline
inline void unfair_mutex_impl<UseDeadLockDetector>::lock_contended(semaphore_value_type
expected)
noexcept
268 hi_axiom(holds_invariant());
276 hi_axiom(holds_invariant());
280 hi_axiom(holds_invariant());
283 }
while (!semaphore.compare_exchange_strong(
expected, 2));
An atomic access global variable for quick access to state of the system.
bool is_system_shutting_down() noexcept
Check if the HikoGUI system is being shut down.
Definition global_state.hpp:220
@ 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.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
hi_export void unfair_mutex_deadlock_remove_object(void *object) noexcept
Remove the object from the detection.
Definition unfair_mutex_impl.hpp:128
hi_export void unfair_mutex_deadlock_clear_stack() noexcept
Clear the stack.
Definition unfair_mutex_impl.hpp:146
hi_export void * unfair_mutex_deadlock_lock(void *object) noexcept
Lock an object on this thread.
Definition unfair_mutex_impl.hpp:72
hi_export void unfair_mutex_deadlock_clear_graph() noexcept
Clear the graph.
Definition unfair_mutex_impl.hpp:159
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
hi_export bool unfair_mutex_deadlock_unlock(void *object) noexcept
Unlock an object on this thread.
Definition unfair_mutex_impl.hpp:99
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:213
T binary_search(T... args)