HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
subsystem.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "../utility/utility.hpp"
13#include "global_state.hpp"
14#include "../macros.hpp"
15#include <atomic>
16#include <vector>
17#include <functional>
18#include <bit>
19#include <type_traits>
20#include <mutex>
21
22
23
24namespace hi { inline namespace v1 {
25namespace detail {
26
29inline std::vector<void (*)()> subsystem_deinit_list;
30
36
37template<typename T>
38hi_no_inline typename T::value_type start_subsystem(
40 typename T::value_type off_value,
41 typename T::value_type (*init_function)(),
42 void (*deinit_function)())
43 requires(is_atomic_v<T>)
44{
45 hi_assert_not_null(init_function);
46 hi_assert_not_null(deinit_function);
47 hilet lock = std::scoped_lock(subsystem_mutex);
48
49 hilet old_value = check_variable.load(std::memory_order::acquire);
50 if (old_value != off_value) {
51 // In the short time before the lock the subsystem became available.
52 return old_value;
53 }
54
55 if (not is_system_running()) {
56 // Only when the system is running can subsystems be started.
57 // otherwise they have to run in degraded mode.
58 return off_value;
59 }
60
61 auto new_value = init_function();
62
63 if (new_value != off_value) {
65 check_variable.store(new_value, std::memory_order::release);
66 }
67
68 return new_value;
69}
70
71hi_no_inline inline bool start_subsystem(global_state_type state_bit, bool (*init_function)(), void (*deinit_function)())
72{
73 hi_assert(std::popcount(std::to_underlying(state_bit)) == 1);
74 hi_assert_not_null(init_function);
75 hi_assert_not_null(deinit_function);
76
77 hilet lock = std::scoped_lock(subsystem_mutex);
78
79 hilet old_state = global_state.load(std::memory_order::acquire);
81 // Only when the system is running can subsystems be started.
82 // otherwise they have to run in degraded mode.
83 return false;
84
85 } else if (to_bool(old_state & state_bit)) {
86 // In the short time before the lock the subsystem became available.
87 return true;
88 }
89
90 if (init_function()) {
91 subsystem_deinit_list.emplace_back(deinit_function);
92 global_state_enable(state_bit, std::memory_order::release);
93 return true;
94 }
95
96 return false;
97}
98
99} // namespace detail
100
115template<typename T>
116typename T::value_type start_subsystem(
118 typename T::value_type off_value,
119 typename T::value_type (*init_function)(),
120 void (*deinit_function)())
121 requires(is_atomic_v<T>)
122{
123 // We can do a relaxed load, if:
124 // - off_value, then we will lock before writing check_variable and memory order will be guaranteed
125 // - not off_value, The system is started. If the subsystem is turning off we can't deal with that anyway.
126 hilet old_value = check_variable.load(std::memory_order::relaxed);
127 if (old_value == off_value) {
128 return detail::start_subsystem(check_variable, off_value, init_function, deinit_function);
129 } else {
130 [[likely]] return old_value;
131 }
132}
133
148{
149 // We can do a relaxed load, if:
150 // - off_value, then we will lock before writing check_variable and memory order will be guaranteed
151 // - not off_value, The system is started. If the subsystem is turning off we can't deal with that anyway.
152 if (not to_bool(global_state.load(std::memory_order::relaxed) & state_bit)) {
153 return detail::start_subsystem(state_bit, init_function, deinit_function);
154 } else {
155 [[likely]] return true;
156 }
157}
158
176template<typename T>
177 requires(is_atomic_v<T>)
178typename T::value_type start_subsystem_or_terminate(
180 typename T::value_type off_value,
181 typename T::value_type (*init_function)(),
182 void (*deinit_function)())
183{
184 auto old_value = check_variable.load(std::memory_order::acquire);
185 if (old_value == off_value) {
186 auto tmp = detail::start_subsystem(check_variable, off_value, init_function, deinit_function);
187 hi_assert(tmp != off_value);
188 return tmp;
189 } else {
190 [[likely]] return old_value;
191 }
192}
193
202inline void stop_subsystem(void (*deinit_function)())
203{
204 hi_assert_not_null(deinit_function);
205
206 hilet lock = std::scoped_lock(detail::subsystem_mutex);
207
208 std::erase(detail::subsystem_deinit_list, deinit_function);
209 return deinit_function();
210}
211
218{
219 global_state |= global_state_type::system_is_running;
220}
221
231{
232 detail::subsystem_mutex.lock();
233 global_state |= global_state_type::system_is_shutting_down;
234
235 while (!detail::subsystem_deinit_list.empty()) {
236 auto deinit = std::move(detail::subsystem_deinit_list.back());
237 hi_assert_not_null(deinit);
238 detail::subsystem_deinit_list.pop_back();
239
240 detail::subsystem_mutex.unlock();
241 deinit();
242 detail::subsystem_mutex.lock();
243 }
244 detail::subsystem_mutex.unlock();
245}
246
247}} // namespace hi::v1
An atomic access global variable for quick access to state of the system.
unfair_recursive_mutex subsystem_mutex
Mutex to be held when writing to system_status or accessing system_status_deinit_list.
Definition subsystem.hpp:35
std::vector< void(*)()> subsystem_deinit_list
A list of deinit function to be called on shutdown.
Definition subsystem.hpp:29
Definition of the unfair_recursive_mutex.
bool global_state_enable(global_state_type subsystem, std::memory_order order=std::memory_order::seq_cst) noexcept
Enable a subsystem.
Definition global_state.hpp:260
bool is_system_running() noexcept
Check if the HikoGUI system is running.
Definition global_state.hpp:209
T::value_type start_subsystem_or_terminate(T &check_variable, typename T::value_type off_value, typename T::value_type(*init_function)(), void(*deinit_function)())
Start a sub-system.
Definition subsystem.hpp:178
void shutdown_system() noexcept
Shutdown the system.
Definition subsystem.hpp:230
T::value_type start_subsystem(T &check_variable, typename T::value_type off_value, typename T::value_type(*init_function)(), void(*deinit_function)())
Start a sub-system.
Definition subsystem.hpp:116
std::atomic< global_state_type > global_state
The global state of the hikogui framework.
Definition global_state.hpp:201
global_state_type
The flag-type used for global state.
Definition global_state.hpp:30
void stop_subsystem(void(*deinit_function)())
Stop a sub-system.
Definition subsystem.hpp:202
void start_system() noexcept
Start the system.
Definition subsystem.hpp:217
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
An unfair recursive-mutex This is a fast implementation of a recursive-mutex which does not fairly ar...
Definition unfair_recursive_mutex.hpp:38
T move(T... args)