GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 2 / 0 / 2
Functions: 100.0% 2 / 0 / 2
Branches: -% 0 / 0 / 0

src/internal/config_reload_lifecycle.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_INTERNAL_CONFIG_RELOAD_LIFECYCLE_HPP
2 #define DETOURMODKIT_INTERNAL_CONFIG_RELOAD_LIFECYCLE_HPP
3
4 /**
5 * @file internal/config_reload_lifecycle.hpp
6 * @brief Reload-pass and lifecycle-gate vocabulary owned by src/internal/config_reload.cpp.
7 * @details The data-plane pass (config.cpp) and the watcher control plane (config_watch.cpp) reach the pass lock and
8 * the background-reload lifecycle gate through this seam. The state itself lives in one TU.
9 */
10
11 #include <cstdint>
12 #include <mutex>
13
14 namespace DetourModKit::config::detail
15 {
16 /**
17 * @class ReloadApplyLock
18 * @brief Guards a reload pass and fails fast on same-thread re-entry.
19 * @details Serializes an entire load()/reload() pass: read, content-hash decision, and deferred-setter
20 * application. Setters run after the config mutex is released, so this separate lock prevents stale pass
21 * reorder. Acquire this lock FIRST, then the config mutex. Lock order against the watcher control mutex
22 * (config_watch.cpp): a pass-lock holder can take the watcher mutex (load()'s re-point does), but a
23 * watcher-mutex holder must not acquire this lock. The drain predicate reads only the atomic in-flight
24 * count under the watcher mutex. A refused same-thread re-entry stays disengaged, which lets the caller
25 * report failure without a wait.
26 */
27 class ReloadApplyLock
28 {
29 public:
30 ReloadApplyLock();
31 ~ReloadApplyLock() noexcept;
32
33 ReloadApplyLock(const ReloadApplyLock &) = delete;
34 ReloadApplyLock &operator=(const ReloadApplyLock &) = delete;
35
36 /// Reports true for an acquired pass lock and false for a refused same-thread re-entry.
37 257 [[nodiscard]] bool engaged() const noexcept { return m_engaged; }
38
39 /// Releases the pass lock before load() performs a stale-watcher join. The operation is idempotent.
40 void unlock() noexcept;
41
42 private:
43 std::unique_lock<std::mutex> m_lock;
44 bool m_engaged{false};
45 };
46
47 /// Reports whether the current thread owns the reload pass lock (it runs inside a bound setter).
48 [[nodiscard]] bool reload_apply_lock_held_by_current_thread() noexcept;
49
50 /**
51 * @class BackgroundReloadGuard
52 * @brief Controls entry to a background reload pass from a watcher callback or hotkey servicer.
53 * @details The captured lifecycle epoch must match an enabled lifecycle state before and after admission.
54 * Otherwise, the pass stops before it can call consumer code. While engaged, it holds the in-flight
55 * count for the whole pass. The check, increment, and recheck pair with the drain latch store and count
56 * load. A pass that unload misses also fails to engage.
57 */
58 class BackgroundReloadGuard
59 {
60 public:
61 explicit BackgroundReloadGuard(std::uint64_t expected_epoch) noexcept;
62 ~BackgroundReloadGuard() noexcept;
63
64 BackgroundReloadGuard(const BackgroundReloadGuard &) = delete;
65 BackgroundReloadGuard &operator=(const BackgroundReloadGuard &) = delete;
66
67 /// Returns true when reloads are armed for this lifecycle and this pass can run consumer code.
68 29 [[nodiscard]] bool engaged() const noexcept { return m_engaged; }
69
70 /// Reports whether an admitted pass still belongs to its enabled lifecycle.
71 [[nodiscard]] bool current() const noexcept;
72
73 private:
74 [[nodiscard]] bool lifecycle_current() const noexcept;
75
76 std::uint64_t m_expected_epoch{0};
77 bool m_engaged{false};
78 };
79
80 /// Returns the current reload lifecycle epoch with the unload latch masked off.
81 [[nodiscard]] std::uint64_t current_reload_lifecycle_epoch() noexcept;
82
83 /// Reports whether the background-reload unload latch is set.
84 [[nodiscard]] bool background_reloads_disabled() noexcept;
85 } // namespace DetourModKit::config::detail
86
87 #endif // DETOURMODKIT_INTERNAL_CONFIG_RELOAD_LIFECYCLE_HPP
88