HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
subsystem.hpp
1// Copyright Take Vos 2019-2021.
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
5#pragma once
6
7#include "assert.hpp"
8#include "unfair_recursive_mutex.hpp"
9#include "type_traits.hpp"
10#include <atomic>
11#include <vector>
12#include <functional>
13#include <bit>
14#include <type_traits>
15#include <mutex>
16
17namespace tt {
18namespace detail {
19
26enum class system_status_type { not_started, running, shutdown };
27
28inline system_status_type system_status = system_status_type::not_started;
29
32inline std::vector<void (*)()> subsystem_deinit_list;
33
38inline unfair_recursive_mutex subsystem_mutex;
39
40template<typename T> requires(is_atomic_v<T>)
41tt_no_inline typename T::value_type start_subsystem(
42 T &check_variable,
43 typename T::value_type off_value,
44 typename T::value_type (*init_function)(),
45 void (*deinit_function)())
46{
47 ttlet lock = std::scoped_lock(subsystem_mutex);
48
49 auto 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 (system_status != system_status_type::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) {
64 subsystem_deinit_list.emplace_back(deinit_function);
65 check_variable.store(new_value, std::memory_order::release);
66 }
67
68 return new_value;
69}
70
71} // namespace detail
72
86template<typename T>
87requires(is_atomic_v<T>) typename T::value_type start_subsystem(
88 T &check_variable,
89 typename T::value_type off_value,
90 typename T::value_type (*init_function)(),
91 void (*deinit_function)())
92{
93 // We can do a relaxed load, if:
94 // - off_value, then we will lock before writing check_variable and memory order will be guaranteed
95 // - not off_value, The system is started. If the subsystem is turning off we can't deal with that anyway.
96 auto old_value = check_variable.load(std::memory_order::relaxed);
97 if (old_value == off_value) {
98 return detail::start_subsystem(check_variable, off_value, init_function, deinit_function);
99 } else {
100 [[likely]] return old_value;
101 }
102}
103
120template<typename T>
121requires(is_atomic_v<T>) typename T::value_type start_subsystem_or_terminate(
122 T &check_variable,
123 typename T::value_type off_value,
124 typename T::value_type (*init_function)(),
125 void (*deinit_function)())
126{
127 auto old_value = check_variable.load(std::memory_order::acquire);
128 if (old_value == off_value) {
129 auto tmp = detail::start_subsystem(check_variable, off_value, init_function, deinit_function);
130 tt_assert(tmp != off_value);
131 return tmp;
132 } else {
133 [[likely]] return old_value;
134 }
135}
136
144inline void stop_subsystem(void (*deinit_function)())
145{
146 ttlet lock = std::scoped_lock(detail::subsystem_mutex);
147
148 std::erase(detail::subsystem_deinit_list, deinit_function);
149 return deinit_function();
150}
151
155inline void start_system() noexcept
156{
157 ttlet lock = std::scoped_lock(detail::subsystem_mutex);
158 detail::system_status = detail::system_status_type::running;
159}
160
161[[nodiscard]] inline bool system_shutting_down() noexcept
162{
163 return detail::system_status == detail::system_status_type::shutdown;
164}
165
172inline void shutdown_system() noexcept
173{
174 detail::subsystem_mutex.lock();
175 detail::system_status = detail::system_status_type::shutdown;
176
177 while (!detail::subsystem_deinit_list.empty()) {
178 auto deinit = std::move(detail::subsystem_deinit_list.back());
179 detail::subsystem_deinit_list.pop_back();
180
181 detail::subsystem_mutex.unlock();
182 deinit();
183 detail::subsystem_mutex.lock();
184 }
185 detail::subsystem_mutex.unlock();
186}
187
188} // namespace tt
T lock(T... args)
T move(T... args)