src/internal/hook_emission.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP | ||
| 2 | #define DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP | ||
| 3 | |||
| 4 | /** | ||
| 5 | * @file internal/hook_emission.hpp | ||
| 6 | * @brief The shared hook lifecycle snapshot and emission sequence for the hook sibling TUs. | ||
| 7 | * @details src/hook.cpp and src/hook_toggle.cpp publish lifecycle events through this one sequence, so the | ||
| 8 | * population-then-emit order and the owned-name lifetime rule are stated exactly once. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include "DetourModKit/diagnostics.hpp" | ||
| 12 | |||
| 13 | #include "internal/diagnostics_population.hpp" | ||
| 14 | |||
| 15 | #include <cstdint> | ||
| 16 | #include <string> | ||
| 17 | #include <string_view> | ||
| 18 | |||
| 19 | namespace DetourModKit::detail | ||
| 20 | { | ||
| 21 | struct RemovalPopulationState | ||
| 22 | { | ||
| 23 | bool was_active{false}; | ||
| 24 | bool remains_live{false}; | ||
| 25 | }; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * @brief Owns the identity for one enable or disable lifecycle event. | ||
| 29 | * @details The owned name stays valid if a subscriber destroys the hook before synchronous emission ends. A | ||
| 30 | * failed name copy preserves the transition and publishes an empty name (HookLifecycleName.*). | ||
| 31 | */ | ||
| 32 | struct LifecycleSnapshot | ||
| 33 | { | ||
| 34 | std::string name; | ||
| 35 | std::uint64_t ledger_id{0}; | ||
| 36 | diagnostics::HookKind kind{diagnostics::HookKind::Inline}; | ||
| 37 | }; | ||
| 38 | |||
| 39 | [[nodiscard]] inline LifecycleSnapshot | ||
| 40 | 7347 | snapshot_lifecycle(const std::string &name, std::uint64_t ledger_id, bool is_inline) noexcept | |
| 41 | { | ||
| 42 | 7347 | LifecycleSnapshot snapshot; | |
| 43 | 7347 | snapshot.ledger_id = ledger_id; | |
| 44 |
2/2✓ Branch 3 → 4 taken 7278 times.
✓ Branch 3 → 5 taken 69 times.
|
7347 | snapshot.kind = is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid; |
| 45 | try | ||
| 46 | { | ||
| 47 |
2/2✓ Branch 6 → 7 taken 7346 times.
✓ Branch 6 → 9 taken 1 time.
|
7347 | snapshot.name = name; |
| 48 | } | ||
| 49 | 1 | catch (...) | |
| 50 | { | ||
| 51 | 1 | } | |
| 52 | 7347 | return snapshot; | |
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * @brief Updates the live population tally, then emits the associated hook lifecycle event. | ||
| 57 | * @param removal Population state for a Removed event. Teardown must capture @c was_active before it forces its | ||
| 58 | * status to Disabled. Set @c remains_live when the target stays conservatively tracked. | ||
| 59 | * @details The tally moves first so a subscriber that calls collect() observes the completed transition. | ||
| 60 | */ | ||
| 61 | 8544 | inline void emit_lifecycle( | |
| 62 | std::string_view name, | ||
| 63 | std::uint64_t ledger_id, | ||
| 64 | diagnostics::HookKind kind, | ||
| 65 | diagnostics::HookTransition transition, | ||
| 66 | RemovalPopulationState removal = {} | ||
| 67 | ) noexcept | ||
| 68 | { | ||
| 69 |
3/4✓ Branch 2 → 3 taken 608 times.
✓ Branch 2 → 5 taken 7347 times.
✓ Branch 2 → 6 taken 589 times.
✗ Branch 2 → 9 not taken.
|
8544 | switch (transition) |
| 70 | { | ||
| 71 | 608 | case diagnostics::HookTransition::Created: | |
| 72 | 608 | DetourModKit::detail::hook_population::record_created(kind == diagnostics::HookKind::Vmt); | |
| 73 | 608 | break; | |
| 74 | 7347 | case diagnostics::HookTransition::Enabled: | |
| 75 | case diagnostics::HookTransition::Disabled: | ||
| 76 | // The status store updates the count while it still holds the call gate. This code runs after unlock. | ||
| 77 | // Otherwise, two toggles can commit +1/-1 in an order opposite their serialized transitions. | ||
| 78 | 7347 | break; | |
| 79 | 589 | case diagnostics::HookTransition::Removed: | |
| 80 |
2/2✓ Branch 6 → 7 taken 570 times.
✓ Branch 6 → 8 taken 19 times.
|
589 | if (!removal.remains_live) |
| 81 | { | ||
| 82 | 570 | DetourModKit::detail::hook_population::record_removed(removal.was_active); | |
| 83 | } | ||
| 84 | 589 | break; | |
| 85 | } | ||
| 86 | try | ||
| 87 | { | ||
| 88 |
1/2✓ Branch 9 → 10 taken 8544 times.
✗ Branch 9 → 13 not taken.
|
8544 | diagnostics::hook_lifecycle().emit_safe( |
| 89 | 8544 | diagnostics::HookLifecycleEvent{ | |
| 90 | .name = name, | ||
| 91 | .ledger_id = ledger_id, | ||
| 92 | .kind = kind, | ||
| 93 | .transition = transition, | ||
| 94 | } | ||
| 95 | ); | ||
| 96 | } | ||
| 97 | ✗ | catch (...) | |
| 98 | { | ||
| 99 | ✗ | } | |
| 100 | 8544 | } | |
| 101 | } // namespace DetourModKit::detail | ||
| 102 | |||
| 103 | #endif // DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP | ||
| 104 |