Commit: f24f6aa5a0d8c2378b76d9a0d5efd0c5f9f9bf86
Parent: 11b1ae5152036e9c03936d5b4316a5a8a2f0129e
Author: Randy Palamar
Date: Tue, 17 Jun 2025 06:25:46 -0600
core: work around pebkac when beamformer is closed during live imaging
Diffstat:
6 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/beamformer_work_queue.h b/beamformer_work_queue.h
@@ -88,6 +88,10 @@ typedef BEAMFORM_WORK_QUEUE_PUSH_COMMIT_FN(beamform_work_queue_push_commit_fn);
typedef align_as(64) struct {
u32 version;
+ /* NOTE(rnp): causes future library calls to fail.
+ * see note in beamformer_invalidate_shared_memory() */
+ b32 invalid;
+
/* NOTE(rnp): not used for locking on w32 but we can use these to peek at the status of
* the lock without leaving userspace. also this struct needs a bunch of padding */
i32 locks[BeamformerSharedMemoryLockKind_Count];
diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c
@@ -177,13 +177,17 @@ check_shared_memory(void)
if (!g_shared_memory.region) {
g_shared_memory = os_open_shared_memory_area(OS_SHARED_MEMORY_NAME);
if (!g_shared_memory.region) {
- result = 0;
g_lib_last_error = BF_LIB_ERR_KIND_SHARED_MEMORY;
+ result = 0;
+ } else if (((BeamformerSharedMemory *)g_shared_memory.region)->version !=
+ BEAMFORMER_SHARED_MEMORY_VERSION)
+ {
+ g_lib_last_error = BF_LIB_ERR_KIND_VERSION_MISMATCH;
+ result = 0;
}
- } else if (((BeamformerSharedMemory *)g_shared_memory.region)->version
- != BEAMFORMER_SHARED_MEMORY_VERSION)
- {
- g_lib_last_error = BF_LIB_ERR_KIND_VERSION_MISMATCH;
+ }
+ if (result && ((BeamformerSharedMemory *)g_shared_memory.region)->invalid) {
+ g_lib_last_error = BF_LIB_ERR_KIND_INVALID_ACCESS;
result = 0;
}
if (result) g_bp = g_shared_memory.region;
diff --git a/helpers/ogl_beamformer_lib_base.h b/helpers/ogl_beamformer_lib_base.h
@@ -8,15 +8,16 @@
#define BEAMFORMER_LIB_ERRORS \
X(NONE, 0, "None") \
X(VERSION_MISMATCH, 1, "host-library version mismatch") \
- X(COMPUTE_STAGE_OVERFLOW, 2, "compute stage overflow: maximum stages: " str(MAX_COMPUTE_SHADER_STAGES)) \
- X(INVALID_COMPUTE_STAGE, 3, "invalid compute shader stage") \
- X(INVALID_IMAGE_PLANE, 4, "invalid image plane") \
- X(BUFFER_OVERFLOW, 5, "passed buffer size exceeds available space") \
- X(WORK_QUEUE_FULL, 6, "work queue full") \
- X(OPEN_EXPORT_PIPE, 7, "failed to open export pipe") \
- X(READ_EXPORT_PIPE, 8, "failed to read full export data from pipe") \
- X(SHARED_MEMORY, 9, "failed to open shared memory region") \
- X(SYNC_VARIABLE, 10, "failed to acquire lock within timeout period")
+ X(INVALID_ACCESS, 2, "library in invalid state") \
+ X(COMPUTE_STAGE_OVERFLOW, 3, "compute stage overflow: maximum stages: " str(MAX_COMPUTE_SHADER_STAGES)) \
+ X(INVALID_COMPUTE_STAGE, 4, "invalid compute shader stage") \
+ X(INVALID_IMAGE_PLANE, 5, "invalid image plane") \
+ X(BUFFER_OVERFLOW, 6, "passed buffer size exceeds available space") \
+ X(WORK_QUEUE_FULL, 7, "work queue full") \
+ X(OPEN_EXPORT_PIPE, 8, "failed to open export pipe") \
+ X(READ_EXPORT_PIPE, 9, "failed to read full export data from pipe") \
+ X(SHARED_MEMORY, 10, "failed to open shared memory region") \
+ X(SYNC_VARIABLE, 11, "failed to acquire lock within timeout period")
#define X(type, num, string) BF_LIB_ERR_KIND_ ##type = num,
typedef enum {BEAMFORMER_LIB_ERRORS} BeamformerLibErrorKind;
diff --git a/main_linux.c b/main_linux.c
@@ -114,6 +114,8 @@ main(void)
input.executable_reloaded = 0;
}
+ beamformer_invalidate_shared_memory(&ctx);
+
/* NOTE: make sure this will get cleaned up after external
* programs release their references */
shm_unlink(OS_SHARED_MEMORY_NAME);
diff --git a/main_w32.c b/main_w32.c
@@ -140,4 +140,6 @@ main(void)
input.executable_reloaded = 0;
}
+
+ beamformer_invalidate_shared_memory(&ctx);
}
diff --git a/static.c b/static.c
@@ -397,3 +397,22 @@ setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory)
reload_shader(&ctx->os, render_2d->path, (iptr)render_2d, *memory);
os_add_file_watch(&ctx->os, memory, render_2d->path, reload_shader, (iptr)render_2d);
}
+
+function void
+beamformer_invalidate_shared_memory(BeamformerCtx *ctx)
+{
+ /* NOTE(rnp): work around pebkac when the beamformer is closed while we are doing live
+ * imaging. if the verasonics is blocked in an external function (calling the library
+ * to start compute) it is impossible for us to get it to properly shut down which
+ * will sometimes result in us needing to power cycle the system. set the shared memory
+ * into an error state and release dispatch lock so that future calls will error instead
+ * of blocking.
+ */
+ BeamformerSharedMemory *sm = ctx->shared_memory.region;
+ BeamformerSharedMemoryLockKind lock = BeamformerSharedMemoryLockKind_DispatchCompute;
+ atomic_store_u32(&sm->invalid, 1);
+ atomic_store_u32(&sm->external_work_queue.ridx, sm->external_work_queue.widx);
+ DEBUG_DECL(if (sm->locks[lock])) {
+ os_shared_memory_region_unlock(&ctx->shared_memory, sm->locks, lock);
+ }
+}