Commit: 7032dfdcd331e6b7085350708868558b60e230b9
Parent: 5c644e1497edea66e809f1d327031c72910d9d06
Author: Randy Palamar
Date: Mon, 30 Mar 2026 08:17:24 -0600
debug: fix hot reloading on glibc linux systems
while glibc is successful at loading the same library multiple
times at once it seems to maintain some kind of weird global
state. So despite loading the new library and closing the old
library it seems the code would not be replaced. Apparently it
needs to have the old code unloaded first.
Diffstat:
4 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -23,7 +23,7 @@ BEAMFORMER_DEBUG_ENTRY_POINTS
#undef X
BEAMFORMER_EXPORT void
-beamformer_debug_hot_reload(OSLibrary library, BeamformerInput *input)
+beamformer_debug_hot_release(BeamformerInput *input)
{
BeamformerCtx *ctx = BeamformerContextMemory(input->memory);
@@ -32,7 +32,11 @@ beamformer_debug_hot_reload(OSLibrary library, BeamformerInput *input)
* never reload while compute is in progress but just incase). */
spin_wait(atomic_load_u32(&ctx->upload_worker.awake));
spin_wait(atomic_load_u32(&ctx->compute_worker.awake));
+}
+BEAMFORMER_EXPORT void
+beamformer_debug_hot_reload(OSLibrary library, BeamformerInput *input)
+{
#define X(name) name = os_lookup_symbol(library, #name);
BEAMFORMER_DEBUG_ENTRY_POINTS
#undef X
diff --git a/beamformer.h b/beamformer.h
@@ -24,8 +24,9 @@
* IMPORTANT: When the platform wants to reload the library at runtime it
* MUST NOT unload the old library immediately; the beamformer may still
* be executing code in old library. Instead the platform must first call
- * `beamformer_debug_hot_reload` with the program's memory and the new library
- * handle. Once that function has returned it is safe to close the old handle.
+ * `beamformer_debug_hot_release` with the program's memory, then it may close the
+ * old handle. Then `beamformer_debug_hot_reload` should be called with the new handle
+ * so that the beamformer may resume operation.
*
* BEAMFORMER_RENDERDOC_HOOKS
* Add RenderDoc API calls to capture complete compute frames. As compute is performed
@@ -198,6 +199,7 @@ BEAMFORMER_EXPORT void beamformer_frame_step(BeamformerInput *);
#endif
#if BEAMFORMER_DEBUG
+BEAMFORMER_EXPORT void beamformer_debug_hot_release(BeamformerInput *);
BEAMFORMER_EXPORT void beamformer_debug_hot_reload(OSLibrary new_library, BeamformerInput *);
#endif
diff --git a/main_linux.c b/main_linux.c
@@ -204,16 +204,19 @@ function void
debug_library_reload(BeamformerInput *input)
{
local_persist OSLibrary beamformer_library_handle = {OSInvalidHandleValue};
- OSLibrary new_handle = load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, RTLD_NOW|RTLD_LOCAL);
+ if ValidHandle(beamformer_library_handle) {
+ beamformer_debug_hot_release(input);
+ dlclose((void *)beamformer_library_handle.value[0]);
+ beamformer_library_handle = (OSLibrary){OSInvalidHandleValue};
+ }
+
+ OSLibrary new_handle = load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME, RTLD_NOW|RTLD_LOCAL);
if (InvalidHandle(beamformer_library_handle) && InvalidHandle(new_handle))
fatal(s8("[os] failed to load: " OS_DEBUG_LIB_NAME "\n"));
if ValidHandle(new_handle) {
beamformer_debug_hot_reload(new_handle, input);
-
- if ValidHandle(beamformer_library_handle)
- dlclose((void *)beamformer_library_handle.value[0]);
beamformer_library_handle = new_handle;
}
}
diff --git a/main_w32.c b/main_w32.c
@@ -254,16 +254,19 @@ function void
debug_library_reload(BeamformerInput *input)
{
local_persist OSLibrary beamformer_library_handle = {OSInvalidHandleValue};
- OSLibrary new_handle = load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME);
+ if ValidHandle(beamformer_library_handle) {
+ beamformer_debug_hot_release(input);
+ FreeLibrary(beamformer_library_handle.value[0]);
+ beamformer_library_handle = (OSLibrary){OSInvalidHandleValue};
+ }
+
+ OSLibrary new_handle = load_library(OS_DEBUG_LIB_NAME, OS_DEBUG_LIB_TEMP_NAME);
if (InvalidHandle(beamformer_library_handle) && InvalidHandle(new_handle))
fatal(s8("[os] failed to load: " OS_DEBUG_LIB_NAME "\n"));
if ValidHandle(new_handle) {
beamformer_debug_hot_reload(new_handle, input);
-
- if ValidHandle(beamformer_library_handle)
- FreeLibrary(beamformer_library_handle.value[0]);
beamformer_library_handle = new_handle;
}
}