#include "hook_registry.hpp" #include #include #include namespace coop::hook { namespace { struct Slot { char name[40] = {}; std::atomic subsystem{0}; std::atomic installed{0}; std::atomic calls{0}; std::atomic used{0}; }; Slot g_slots[kMaxHookEntries]; std::atomic g_count{0}; // high-water mark of allocated slots std::mutex g_register_mutex; // registration only (rare); calls are lock-free } // namespace int hook_register(const char* name, std::uint32_t subsystem) { std::scoped_lock lock(g_register_mutex); const std::uint32_t count = g_count.load(std::memory_order_relaxed); for (std::uint32_t i = 0; i < count; ++i) { if (g_slots[i].used.load(std::memory_order_relaxed) && std::strcmp(g_slots[i].name, name) == 0) { return static_cast(i); // already registered } } if (count >= kMaxHookEntries) { return -1; // table full } Slot& s = g_slots[count]; std::strncpy(s.name, name, sizeof(s.name) - 1); s.name[sizeof(s.name) - 1] = '\0'; s.subsystem.store(subsystem, std::memory_order_relaxed); s.installed.store(0, std::memory_order_relaxed); s.calls.store(0, std::memory_order_relaxed); s.used.store(1, std::memory_order_release); g_count.store(count + 1, std::memory_order_release); return static_cast(count); } void hook_set_installed(int id, bool installed) { if (id >= 0 && id < static_cast(kMaxHookEntries)) { g_slots[id].installed.store(installed ? 1u : 0u, std::memory_order_relaxed); } } void hook_note_call(int id) { if (id >= 0 && id < static_cast(kMaxHookEntries)) { g_slots[id].calls.fetch_add(1, std::memory_order_relaxed); } } void hook_publish(IpcClient& ipc) { const std::uint32_t count = g_count.load(std::memory_order_acquire); HookEntry entries[kMaxHookEntries]; std::uint32_t n = 0; for (std::uint32_t i = 0; i < count && i < kMaxHookEntries; ++i) { if (!g_slots[i].used.load(std::memory_order_acquire)) { continue; } HookEntry& e = entries[n]; std::memcpy(e.name, g_slots[i].name, sizeof(e.name)); e.subsystem = g_slots[i].subsystem.load(std::memory_order_relaxed); e.installed = g_slots[i].installed.load(std::memory_order_relaxed); e.calls = g_slots[i].calls.load(std::memory_order_relaxed); ++n; } ipc.publish_hook_entries(entries, n); } void hook_registry_reset() { std::scoped_lock lock(g_register_mutex); for (auto& s : g_slots) { s.used.store(0, std::memory_order_relaxed); s.installed.store(0, std::memory_order_relaxed); s.calls.store(0, std::memory_order_relaxed); } g_count.store(0, std::memory_order_release); } } // namespace coop::hook