ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

Commit: 9caebc871d3d048f526864cd9403771257ee181f
Parent: d0bb8be1de86b0e323254d85ea7b87e2ce1e8d84
Author: Randy Palamar
Date:   Tue, 22 Jul 2025 10:37:15 -0600

lib: fix two race conditions when exporting data

1. if the lib pushes an export work item before it raises the
   semaphore that it will use to wait for its completion the
   other end may finish before the lib raises its end and will
   have to assume export failed

2. if the lib pushes a data with compute and then immediately
   pushes the export work item and calls start_compute for the
   export item it may fail because the previous one hasn't started
   yet. This shouldn't result in a failure for the export.

Diffstat:
Mhelpers/ogl_beamformer_lib.c | 22++++++++++------------
Mos_linux.c | 4++--
2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -118,15 +118,6 @@ lib_release_lock(BeamformerSharedMemoryLockKind lock) os_shared_memory_region_unlock(&g_shared_memory, g_bp->locks, (i32)lock); } -function b32 -try_wait_sync(BeamformerSharedMemoryLockKind lock, i32 timeout_ms) -{ - b32 result = lib_try_lock(lock, 0) && lib_try_lock(lock, timeout_ms); - /* TODO(rnp): non-critical race condition */ - if (result) lib_release_lock(lock); - return result; -} - u32 beamformer_get_api_version(void) { @@ -356,7 +347,7 @@ function b32 beamformer_export_buffer(BeamformerExportContext export_context) { BeamformWork *work = try_push_work_queue(); - b32 result = work != 0; + b32 result = work && lib_try_lock(BeamformerSharedMemoryLockKind_ExportSync, 0); if (result) { work->export_context = export_context; work->kind = BeamformerWorkKind_ExportBuffer; @@ -370,7 +361,8 @@ function b32 beamformer_read_output(void *out, uz size, i32 timeout_ms) { b32 result = 0; - if (try_wait_sync(BeamformerSharedMemoryLockKind_ExportSync, timeout_ms)) { + if (lib_try_lock(BeamformerSharedMemoryLockKind_ExportSync, timeout_ms)) { + lib_release_lock(BeamformerSharedMemoryLockKind_ExportSync); if (lib_try_lock(BeamformerSharedMemoryLockKind_ScratchSpace, 0)) { mem_copy(out, (u8 *)g_bp + BEAMFORMER_SCRATCH_OFF, size); lib_release_lock(BeamformerSharedMemoryLockKind_ScratchSpace); @@ -400,8 +392,14 @@ beamform_data_synchronized(void *data, u32 data_size, i32 output_points[3], f32 BeamformerExportContext export; export.kind = BeamformerExportKind_BeamformedData; export.size = (u32)output_size; - if (beamformer_export_buffer(export) && beamformer_start_compute(0)) + if (beamformer_export_buffer(export)) { + /* NOTE(rnp): if this fails it just means that the work from push_data hasn't + * started yet. This is here to catch the other case where the work started + * and finished before we finished queuing the export work item */ + beamformer_start_compute(0); + result = beamformer_read_output(out_data, output_size, timeout_ms); + } } else { g_lib_last_error = BF_LIB_ERR_KIND_EXPORT_SPACE_OVERFLOW; } diff --git a/os_linux.c b/os_linux.c @@ -277,8 +277,8 @@ function OS_SHARED_MEMORY_LOCK_REGION_FN(os_shared_memory_region_lock) { b32 result = 0; for (;;) { - i32 current = atomic_load_u32(locks + lock_index); - if (current == 0 && atomic_cas_u32(locks + lock_index, &current, 1)) { + i32 current = 0; + if (atomic_cas_u32(locks + lock_index, &current, 1)) { result = 1; break; }