HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
system_status.hpp
1// Copyright Take Vos 2019-2020.
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_mutex.hpp"
9#include <atomic>
10#include <vector>
11#include <functional>
12#include <bit>
13
14namespace tt {
15
16enum class system_status_type : uint32_t {
17 log_level_debug = 0x01,
18 log_level_info = 0x02,
19 log_level_statistics = 0x04,
20 log_level_trace = 0x08,
21 log_level_warning = 0x10,
22 log_level_audit = 0x20,
23 log_level_error = 0x40,
24 log_level_fatal = 0x80,
25
26 shutdown = 0x1'00,
27 logger = 0x2'00,
28 statistics = 0x4'00,
29};
30
31[[nodiscard]] constexpr system_status_type operator&(system_status_type const &lhs, system_status_type const &rhs) noexcept
32{
33 return static_cast<system_status_type>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
34}
35
36[[nodiscard]] constexpr system_status_type operator|(system_status_type const &lhs, system_status_type const &rhs) noexcept
37{
38 return static_cast<system_status_type>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
39}
40
41[[nodiscard]] constexpr system_status_type operator~(system_status_type const &rhs) noexcept
42{
43 return static_cast<system_status_type>(~static_cast<uint32_t>(rhs));
44}
45
46[[nodiscard]] constexpr uint8_t to_log_level(system_status_type const &rhs) noexcept
47{
48 return static_cast<uint8_t>(rhs);
49}
50
57inline std::atomic<system_status_type> system_status = system_status_type{0};
58
59namespace detail {
60
63inline std::vector<std::function<void()>> system_status_deinit_list;
64
69inline unfair_mutex system_status_mutex;
70static_assert(decltype(system_status)::is_always_lock_free);
71
72template<typename InitFunc, typename DeinitFunc>
73tt_no_inline bool system_status_start_subsystem(system_status_type subsystem, InitFunc init_function, DeinitFunc deinit_function)
74{
75 tt_axiom(std::popcount(static_cast<uint32_t>(subsystem)) == 1);
76 ttlet lock = std::scoped_lock(system_status_mutex);
77
78 ttlet current_state = system_status.load();
79
80 if (static_cast<bool>(current_state & system_status_type::shutdown)) {
81 return false;
82 }
83
84 if (static_cast<bool>(current_state & subsystem)) {
85 return true;
86 }
87
88 system_status_deinit_list.emplace_back(std::forward<DeinitFunc>(deinit_function));
89
90 std::forward<InitFunc>(init_function)();
91
92 system_status.store(current_state | subsystem);
93 return true;
94}
95
96} // namespace detail
97
101inline void system_status_set_log_level(uint8_t log_level) noexcept
102{
103 ttlet lock = std::scoped_lock(detail::system_status_mutex);
104
105 auto current_status = static_cast<uint32_t>(system_status.load());
106 current_status >>= 8;
107 current_status <<= 8;
108 current_status |= log_level;
109 system_status.store(static_cast<system_status_type>(current_status));
110}
111
124template<typename InitFunc, typename DeinitFunc>
125bool system_status_start_subsystem(system_status_type subsystem, InitFunc init_function, DeinitFunc deinit_function)
126{
127 tt_axiom(std::popcount(static_cast<uint32_t>(subsystem)) == 1);
128
129 if (!static_cast<bool>(system_status.load(std::memory_order::relaxed) & subsystem)) {
130 [[unlikely]] return detail::system_status_start_subsystem(subsystem, init_function, deinit_function);
131 } else {
132 // Subsystem is already running.
133 return true;
134 }
135}
136
143inline void system_status_shutdown() noexcept
144{
145 detail::system_status_mutex.lock();
146 system_status = system_status | system_status_type::shutdown;
147
148 while (!detail::system_status_deinit_list.empty()) {
149 auto deinit = std::move(detail::system_status_deinit_list.back());
150 detail::system_status_deinit_list.pop_back();
151
152 detail::system_status_mutex.unlock();
153 deinit();
154 detail::system_status_mutex.lock();
155 }
156 detail::system_status_mutex.unlock();
157}
158
159} // namespace tt
T lock(T... args)
T move(T... args)