summaryrefslogtreecommitdiffstats
path: root/src/modules.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/modules.cpp47
1 files changed, 38 insertions, 9 deletions
diff --git a/src/modules.cpp b/src/modules.cpp
index 7a82028..a671d82 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -1,10 +1,27 @@
1// modules.cpp — /proc/self/maps parsing and module discovery 1// modules.cpp — /proc/self/maps parsing and module discovery
2#include "hl2h.h" 2#include "hl2h.h"
3#include <atomic>
3#include <elf.h> 4#include <elf.h>
4#include <mutex>
5#include <vector> 5#include <vector>
6 6
7static std::mutex g_modules_mutex; 7// Immutable snapshots. Readers load a pointer with acquire semantics and get a
8// module that never changes underneath them. find_modules() publishes a fresh
9// copy instead of mutating the current one; retired snapshots are deliberately
10// leaked so a reference already handed to another thread stays valid.
11static const Module g_no_module;
12static std::atomic<const Module *> g_client_snap{&g_no_module};
13static std::atomic<const Module *> g_engine_snap{&g_no_module};
14static std::atomic<const Module *> g_server_snap{&g_no_module};
15
16const Module &mod_client() {
17 return *g_client_snap.load(std::memory_order_acquire);
18}
19const Module &mod_engine() {
20 return *g_engine_snap.load(std::memory_order_acquire);
21}
22const Module &mod_server() {
23 return *g_server_snap.load(std::memory_order_acquire);
24}
8 25
9static bool basename_is(const char *path, const char *base) { 26static bool basename_is(const char *path, const char *base) {
10 size_t pl = strlen(path), bl = strlen(base); 27 size_t pl = strlen(path), bl = strlen(base);
@@ -55,6 +72,9 @@ void find_modules() {
55 else if (engine.valid() && engine.ranges.back().file && 72 else if (engine.valid() && engine.ranges.back().file &&
56 lo == engine.ranges.back().hi && hi - lo <= 0x1000000) 73 lo == engine.ranges.back().hi && hi - lo <= 0x1000000)
57 m = &engine; 74 m = &engine;
75 else if (server.valid() && server.ranges.back().file &&
76 lo == server.ranges.back().hi && hi - lo <= 0x1000000)
77 m = &server;
58 } 78 }
59 if (!m) 79 if (!m)
60 continue; 80 continue;
@@ -72,16 +92,25 @@ void find_modules() {
72 } 92 }
73 } 93 }
74 fclose(f); 94 fclose(f);
75 // setup_thread and resolve_server_netvars can both call this; the old code 95 // setup_thread and resolve_server_netvars can both call this. Publish whole
76 // reset the shared Module globals and reallocated their vectors live, which 96 // snapshots atomically so a reader never iterates a vector being reallocated.
77 // crashed under the startup thread. Publish complete snapshots instead.
78 std::lock_guard<std::mutex> lock(g_modules_mutex);
79 if (client.valid()) 97 if (client.valid())
80 g_client = std::move(client); 98 g_client_snap.store(new Module(std::move(client)), std::memory_order_release);
81 if (engine.valid()) 99 if (engine.valid())
82 g_engine = std::move(engine); 100 g_engine_snap.store(new Module(std::move(engine)), std::memory_order_release);
83 if (server.valid()) 101 if (server.valid())
84 g_server = std::move(server); 102 g_server_snap.store(new Module(std::move(server)), std::memory_order_release);
103}
104
105bool module_range(uintptr_t p, size_t n) {
106 if (n == 0)
107 return true;
108 uintptr_t last = p + (n - 1);
109 if (last < p)
110 return false; // address-space wrap
111 return (mod_client().contains(p) && mod_client().contains(last)) ||
112 (mod_engine().contains(p) && mod_engine().contains(last)) ||
113 (mod_server().contains(p) && mod_server().contains(last));
85} 114}
86 115
87// --------------------------------------------------------------------------- 116// ---------------------------------------------------------------------------