Commit: 19f298ce4ec4b79fcacb5693c4e3eee989aff9cd
Parent: 26bb15ea111f9dc85fbd484d00ceb89d630f9476
Author: Randy Palamar
Date: Sat, 5 Apr 2025 15:42:21 -0600
core: use futex for synchronization instead of semaphore
This will allow inter-process synchronization. Unfortunately this
means that the "linux" version is now definitely linux only (not
that I'm testing this elsewhere atm).
Diffstat:
9 files changed, 334 insertions(+), 320 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -773,7 +773,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue);
if (fill_frame_compute_work(ctx, work)) {
beamform_work_queue_push_commit(ctx->beamform_work_queue);
- ctx->os.wake_thread(ctx->os.compute_worker.sync_handle);
+ ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable);
ctx->start_compute = 0;
}
}
@@ -832,7 +832,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
if (ctx->start_compute) {
ctx->start_compute = 0;
- ctx->os.wake_thread(ctx->os.compute_worker.sync_handle);
+ ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable);
}
BeamformComputeFrame *frame_to_draw;
diff --git a/build.sh b/build.sh
@@ -30,7 +30,7 @@ MINGW64*)
raylib="libraylib.dll"
main="main_w32.c"
libname="beamformer.dll"
- ldflags="${ldflags} -lgdi32 -lwinmm"
+ ldflags="${ldflags} -lgdi32 -lwinmm -lntdll"
if [ ! ${NO_MATLAB} ]; then
libcflags="${libcflags} -DMATLAB_CONSOLE"
extra_ldflags="-llibmat -llibmex"
diff --git a/main_linux.c b/main_linux.c
@@ -5,7 +5,7 @@
#include "beamformer.h"
-#include "os_unix.c"
+#include "os_linux.c"
#define OS_DEBUG_LIB_NAME "./beamformer.so"
#define OS_DEBUG_LIB_TEMP_NAME "./beamformer_temp.so"
@@ -85,7 +85,7 @@ main(void)
debug_init(&ctx.os, (iptr)&input, &temp_memory);
setup_beamformer(&ctx, &temp_memory);
- os_wake_thread(ctx.os.compute_worker.sync_handle);
+ os_wake_waiters(&ctx.os.compute_worker.sync_variable);
struct pollfd fds[2] = {{0}, {0}};
fds[0].fd = ctx.os.file_watch_context.handle;
diff --git a/main_w32.c b/main_w32.c
@@ -161,7 +161,7 @@ main(void)
debug_init(&ctx.os, (iptr)&input, &temp_memory);
setup_beamformer(&ctx, &temp_memory);
- os_wake_thread(ctx.os.compute_worker.sync_handle);
+ os_wake_waiters(&ctx.os.compute_worker.sync_variable);
while (!ctx.should_exit) {
clear_io_queue(&ctx.os, &input, temp_memory);
diff --git a/os_linux.c b/os_linux.c
@@ -0,0 +1,294 @@
+/* See LICENSE for license details. */
+
+/* NOTE(rnp): provides the platform layer for the beamformer. This code must
+ * be provided by any platform the beamformer is ported to. */
+
+#include "util.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sys/inotify.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+i64 syscall(i64, ...);
+
+#ifdef _DEBUG
+static void *
+os_get_module(char *name, Stream *e)
+{
+ void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD);
+ if (!result && e) {
+ s8 errs[] = {s8("os_get_module(\""), c_str_to_s8(name), s8("\"): "),
+ c_str_to_s8(dlerror()), s8("\n")};
+ stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
+ }
+ return result;
+}
+#endif
+
+static OS_WRITE_FILE_FN(os_write_file)
+{
+ while (raw.len) {
+ iz r = write(file, raw.data, raw.len);
+ if (r < 0) return 0;
+ raw = s8_cut_head(raw, r);
+ }
+ return 1;
+}
+
+static void __attribute__((noreturn))
+os_fatal(s8 msg)
+{
+ os_write_file(STDERR_FILENO, msg);
+ _exit(1);
+ unreachable();
+}
+
+static OS_ALLOC_ARENA_FN(os_alloc_arena)
+{
+ Arena result;
+ iz pagesize = sysconf(_SC_PAGESIZE);
+ if (capacity % pagesize != 0)
+ capacity += pagesize - capacity % pagesize;
+
+ iz oldsize = old.end - old.beg;
+ if (oldsize > capacity)
+ return old;
+
+ if (old.beg)
+ munmap(old.beg, oldsize);
+
+ result.beg = mmap(0, capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if (result.beg == MAP_FAILED)
+ os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
+ result.end = result.beg + capacity;
+ return result;
+}
+
+static OS_CLOSE_FN(os_close)
+{
+ close(file);
+}
+
+static OS_OPEN_FOR_WRITE_FN(os_open_for_write)
+{
+ iptr result = open(fname, O_WRONLY|O_TRUNC);
+ if (result == -1)
+ result = INVALID_FILE;
+ return result;
+}
+
+static OS_READ_WHOLE_FILE_FN(os_read_whole_file)
+{
+ s8 result = {0};
+
+ struct stat sb;
+ i32 fd = open(file, O_RDONLY);
+ if (fd >= 0 && fstat(fd, &sb) >= 0) {
+ result = s8_alloc(arena, sb.st_size);
+ iz rlen = read(fd, result.data, result.len);
+ if (rlen != result.len)
+ result = (s8){0};
+ }
+ if (fd >= 0) close(fd);
+
+ return result;
+}
+
+static OS_WRITE_NEW_FILE_FN(os_write_new_file)
+{
+ iptr fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600);
+ if (fd == INVALID_FILE)
+ return 0;
+ b32 ret = os_write_file(fd, raw);
+ close(fd);
+ return ret;
+}
+
+static b32
+os_file_exists(char *path)
+{
+ struct stat st;
+ b32 result = stat(path, &st) == 0;
+ return result;
+}
+
+static Pipe
+os_open_named_pipe(char *name)
+{
+ mkfifo(name, 0660);
+ return (Pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name};
+}
+
+static OS_READ_FILE_FN(os_read_file)
+{
+ iz r = 0, total_read = 0;
+ do {
+ if (r != -1)
+ total_read += r;
+ r = read(file, buf + total_read, size - total_read);
+ } while (r);
+ return total_read;
+}
+
+static void *
+os_open_shared_memory_area(char *name, iz cap)
+{
+ i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
+ if (fd == -1)
+ return NULL;
+
+ if (ftruncate(fd, cap) == -1) {
+ close(fd);
+ return NULL;
+ }
+
+ void *new = mmap(NULL, cap, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (new == MAP_FAILED)
+ return NULL;
+
+ return new;
+}
+
+/* NOTE: complete garbage because there is no standarized copyfile() in POSix */
+static b32
+os_copy_file(char *name, char *new)
+{
+ b32 result = 0;
+ struct stat sb;
+ if (stat(name, &sb) < 0)
+ return 0;
+
+ i32 fd_old = open(name, O_RDONLY);
+ i32 fd_new = open(new, O_WRONLY|O_TRUNC, sb.st_mode);
+
+ if (fd_old < 0 || fd_new < 0)
+ goto ret;
+ u8 buf[4096];
+ iz copied = 0;
+ while (copied != sb.st_size) {
+ iz r = read(fd_old, buf, ARRAY_COUNT(buf));
+ if (r < 0) goto ret;
+ iz w = write(fd_new, buf, r);
+ if (w < 0) goto ret;
+ copied += w;
+ }
+ result = 1;
+ret:
+ if (fd_old != -1) close(fd_old);
+ if (fd_new != -1) close(fd_new);
+ return result;
+}
+
+static void *
+os_load_library(char *name, char *temp_name, Stream *e)
+{
+ if (temp_name) {
+ if (os_copy_file(name, temp_name))
+ name = temp_name;
+ }
+
+ void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL);
+ if (!result && e) {
+ s8 errs[] = {s8("os_load_library(\""), c_str_to_s8(name), s8("\"): "),
+ c_str_to_s8(dlerror()), s8("\n")};
+ stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
+ }
+
+ if (temp_name)
+ unlink(temp_name);
+
+ return result;
+}
+
+static void *
+os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
+{
+ void *result = 0;
+ if (h) {
+ result = dlsym(h, name);
+ if (!result && e) {
+ s8 errs[] = {s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name),
+ s8("\"): "), c_str_to_s8(dlerror()), s8("\n")};
+ stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
+ }
+ }
+ return result;
+}
+
+static void
+os_unload_library(void *h)
+{
+ /* NOTE: glibc is buggy gnuware so we need to check this */
+ if (h)
+ dlclose(h);
+}
+
+static OS_ADD_FILE_WATCH_FN(os_add_file_watch)
+{
+ s8 directory = path;
+ directory.len = s8_scan_backwards(path, '/');
+ ASSERT(directory.len > 0);
+
+ u64 hash = s8_hash(directory);
+ FileWatchContext *fwctx = &os->file_watch_context;
+ FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash);
+ if (!dir) {
+ ASSERT(path.data[directory.len] == '/');
+
+ dir = fwctx->directory_watches + fwctx->directory_watch_count++;
+ dir->hash = hash;
+ dir->name = push_s8_zero(a, directory);
+ i32 mask = IN_MOVED_TO|IN_CLOSE_WRITE;
+ dir->handle = inotify_add_watch(fwctx->handle, (c8 *)dir->name.data, mask);
+ }
+
+ insert_file_watch(dir, s8_cut_head(path, dir->name.len + 1), user_data, callback);
+}
+
+i32 pthread_setname_np(pthread_t, char *);
+static iptr
+os_create_thread(Arena arena, iptr user_context, s8 name, os_thread_entry_point_fn *fn)
+{
+ pthread_t result;
+ pthread_create(&result, 0, (void *(*)(void *))fn, (void *)user_context);
+ pthread_setname_np(result, (char *)name.data);
+ return (iptr)result;
+}
+
+static void
+os_wait_on_value(i32 *value, i32 current, u32 timeout_ms)
+{
+ struct timespec *timeout = 0, timeout_value;
+ if (timeout_ms != U32_MAX) {
+ timeout_value.tv_sec = timeout_ms / 1000;
+ timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000;
+ timeout = &timeout_value;
+ }
+ syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0);
+}
+
+static OS_WAKE_WAITERS_FN(os_wake_waiters)
+{
+ if (sync) {
+ atomic_inc(sync, 1);
+ syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0);
+ }
+}
+
+/* TODO(rnp): what do if not X11? */
+iptr glfwGetGLXContext(iptr);
+
+static iptr
+os_get_native_gl_context(iptr window)
+{
+ return glfwGetGLXContext(window);
+}
diff --git a/os_unix.c b/os_unix.c
@@ -1,290 +0,0 @@
-/* See LICENSE for license details. */
-
-/* NOTE(rnp): provides the platform layer for the beamformer. This code must
- * be provided by any platform the beamformer is ported to. */
-
-#include "util.h"
-
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <sys/inotify.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#ifdef _DEBUG
-static void *
-os_get_module(char *name, Stream *e)
-{
- void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD);
- if (!result && e) {
- s8 errs[] = {s8("os_get_module(\""), c_str_to_s8(name), s8("\"): "),
- c_str_to_s8(dlerror()), s8("\n")};
- stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
- }
- return result;
-}
-#endif
-
-static OS_WRITE_FILE_FN(os_write_file)
-{
- while (raw.len) {
- iz r = write(file, raw.data, raw.len);
- if (r < 0) return 0;
- raw = s8_cut_head(raw, r);
- }
- return 1;
-}
-
-static void __attribute__((noreturn))
-os_fatal(s8 msg)
-{
- os_write_file(STDERR_FILENO, msg);
- _exit(1);
- unreachable();
-}
-
-static OS_ALLOC_ARENA_FN(os_alloc_arena)
-{
- Arena result;
- iz pagesize = sysconf(_SC_PAGESIZE);
- if (capacity % pagesize != 0)
- capacity += pagesize - capacity % pagesize;
-
- iz oldsize = old.end - old.beg;
- if (oldsize > capacity)
- return old;
-
- if (old.beg)
- munmap(old.beg, oldsize);
-
- result.beg = mmap(0, capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- if (result.beg == MAP_FAILED)
- os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
- result.end = result.beg + capacity;
- return result;
-}
-
-static OS_CLOSE_FN(os_close)
-{
- close(file);
-}
-
-static OS_OPEN_FOR_WRITE_FN(os_open_for_write)
-{
- iptr result = open(fname, O_WRONLY|O_TRUNC);
- if (result == -1)
- result = INVALID_FILE;
- return result;
-}
-
-static OS_READ_WHOLE_FILE_FN(os_read_whole_file)
-{
- s8 result = {0};
-
- struct stat sb;
- i32 fd = open(file, O_RDONLY);
- if (fd >= 0 && fstat(fd, &sb) >= 0) {
- result = s8_alloc(arena, sb.st_size);
- iz rlen = read(fd, result.data, result.len);
- if (rlen != result.len)
- result = (s8){0};
- }
- if (fd >= 0) close(fd);
-
- return result;
-}
-
-static OS_WRITE_NEW_FILE_FN(os_write_new_file)
-{
- iptr fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600);
- if (fd == INVALID_FILE)
- return 0;
- b32 ret = os_write_file(fd, raw);
- close(fd);
- return ret;
-}
-
-static b32
-os_file_exists(char *path)
-{
- struct stat st;
- b32 result = stat(path, &st) == 0;
- return result;
-}
-
-static Pipe
-os_open_named_pipe(char *name)
-{
- mkfifo(name, 0660);
- return (Pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name};
-}
-
-static OS_READ_FILE_FN(os_read_file)
-{
- iz r = 0, total_read = 0;
- do {
- if (r != -1)
- total_read += r;
- r = read(file, buf + total_read, size - total_read);
- } while (r);
- return total_read;
-}
-
-static void *
-os_open_shared_memory_area(char *name, iz cap)
-{
- i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
- if (fd == -1)
- return NULL;
-
- if (ftruncate(fd, cap) == -1) {
- close(fd);
- return NULL;
- }
-
- void *new = mmap(NULL, cap, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- close(fd);
-
- if (new == MAP_FAILED)
- return NULL;
-
- return new;
-}
-
-/* NOTE: complete garbage because there is no standarized copyfile() in POSix */
-static b32
-os_copy_file(char *name, char *new)
-{
- b32 result = 0;
- struct stat sb;
- if (stat(name, &sb) < 0)
- return 0;
-
- i32 fd_old = open(name, O_RDONLY);
- i32 fd_new = open(new, O_WRONLY|O_TRUNC, sb.st_mode);
-
- if (fd_old < 0 || fd_new < 0)
- goto ret;
- u8 buf[4096];
- iz copied = 0;
- while (copied != sb.st_size) {
- iz r = read(fd_old, buf, ARRAY_COUNT(buf));
- if (r < 0) goto ret;
- iz w = write(fd_new, buf, r);
- if (w < 0) goto ret;
- copied += w;
- }
- result = 1;
-ret:
- if (fd_old != -1) close(fd_old);
- if (fd_new != -1) close(fd_new);
- return result;
-}
-
-static void *
-os_load_library(char *name, char *temp_name, Stream *e)
-{
- if (temp_name) {
- if (os_copy_file(name, temp_name))
- name = temp_name;
- }
-
- void *result = dlopen(name, RTLD_NOW|RTLD_LOCAL);
- if (!result && e) {
- s8 errs[] = {s8("os_load_library(\""), c_str_to_s8(name), s8("\"): "),
- c_str_to_s8(dlerror()), s8("\n")};
- stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
- }
-
- if (temp_name)
- unlink(temp_name);
-
- return result;
-}
-
-static void *
-os_lookup_dynamic_symbol(void *h, char *name, Stream *e)
-{
- void *result = 0;
- if (h) {
- result = dlsym(h, name);
- if (!result && e) {
- s8 errs[] = {s8("os_lookup_dynamic_symbol(\""), c_str_to_s8(name),
- s8("\"): "), c_str_to_s8(dlerror()), s8("\n")};
- stream_append_s8_array(e, errs, ARRAY_COUNT(errs));
- }
- }
- return result;
-}
-
-static void
-os_unload_library(void *h)
-{
- /* NOTE: glibc is buggy gnuware so we need to check this */
- if (h)
- dlclose(h);
-}
-
-static OS_ADD_FILE_WATCH_FN(os_add_file_watch)
-{
- s8 directory = path;
- directory.len = s8_scan_backwards(path, '/');
- ASSERT(directory.len > 0);
-
- u64 hash = s8_hash(directory);
- FileWatchContext *fwctx = &os->file_watch_context;
- FileWatchDirectory *dir = lookup_file_watch_directory(fwctx, hash);
- if (!dir) {
- ASSERT(path.data[directory.len] == '/');
-
- dir = fwctx->directory_watches + fwctx->directory_watch_count++;
- dir->hash = hash;
- dir->name = push_s8_zero(a, directory);
- i32 mask = IN_MOVED_TO|IN_CLOSE_WRITE;
- dir->handle = inotify_add_watch(fwctx->handle, (c8 *)dir->name.data, mask);
- }
-
- insert_file_watch(dir, s8_cut_head(path, dir->name.len + 1), user_data, callback);
-}
-
-i32 pthread_setname_np(pthread_t, char *);
-static iptr
-os_create_thread(Arena arena, iptr user_context, s8 name, os_thread_entry_point_fn *fn)
-{
- pthread_t result;
- pthread_create(&result, 0, (void *(*)(void *))fn, (void *)user_context);
- pthread_setname_np(result, (char *)name.data);
- return (iptr)result;
-}
-
-static iptr
-os_create_sync_object(Arena *arena)
-{
- sem_t *result = push_struct(arena, sem_t);
- sem_init(result, 0, 0);
- return (iptr)result;
-}
-
-static void
-os_sleep_thread(iptr sync_handle)
-{
- sem_wait((sem_t *)sync_handle);
-}
-
-static OS_WAKE_THREAD_FN(os_wake_thread)
-{
- sem_post((sem_t *)sync_handle);
-}
-
-/* TODO(rnp): what do if not X11? */
-iptr glfwGetGLXContext(iptr);
-
-static iptr
-os_get_native_gl_context(iptr window)
-{
- return glfwGetGLXContext(window);
-}
diff --git a/os_win32.c b/os_win32.c
@@ -90,7 +90,6 @@ W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *);
W32(iptr) CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *);
W32(iptr) CreateIoCompletionPort(iptr, iptr, uptr, u32);
W32(iptr) CreateNamedPipeA(c8 *, u32, u32, u32, u32, u32, u32, void *);
-W32(iptr) CreateSemaphoreA(iptr, i64, i64, c8 *);
W32(iptr) CreateThread(iptr, uz, iptr, iptr, u32, u32 *);
W32(b32) DeleteFileA(c8 *);
W32(b32) DisconnectNamedPipe(iptr);
@@ -109,8 +108,9 @@ W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64);
W32(b32) ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *);
W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *);
W32(b32) ReleaseSemaphore(iptr, i64, i64 *);
+W32(i32) RtlWakeAddressAll(void *);
+W32(i32) RtlWaitOnAddress(void *, void *, uz, void *);
W32(i32) SetThreadDescription(iptr, u16 *);
-W32(u32) WaitForSingleObjectEx(iptr, u32, b32);
W32(b32) WriteFile(iptr, u8 *, i32, i32 *, void *);
W32(void *) VirtualAlloc(u8 *, iz, u32, u32);
W32(b32) VirtualFree(u8 *, iz, u32);
@@ -339,22 +339,24 @@ os_create_thread(Arena arena, iptr user_context, s8 name, os_thread_entry_point_
return result;
}
-static iptr
-os_create_sync_object(Arena *arena)
-{
- iptr result = CreateSemaphoreA(0, 0, 1, 0);
- return result;
-}
-
static void
-os_sleep_thread(iptr sync_handle)
+os_wait_on_value(i32 *value, i32 current, u32 timeout_ms)
{
- WaitForSingleObjectEx(sync_handle, 0xFFFFFFFF, 0);
+ i64 *timeout = 0, timeout_value;
+ if (timeout_ms != U32_MAX) {
+ /* TODO(rnp): not sure about this one, but this is how wine converts the ms */
+ timeout_value = -(i64)timeout_ms * 10000;
+ timeout = &timeout_value;
+ }
+ RtlWaitOnAddress(value, ¤t, sizeof(*value), timeout);
}
-static OS_WAKE_THREAD_FN(os_wake_thread)
+static OS_WAKE_WAITERS_FN(os_wake_waiters)
{
- ReleaseSemaphore(sync_handle, 1, 0);
+ if (sync) {
+ atomic_inc(sync, 1);
+ RtlWakeAddressAll(sync);
+ }
}
iptr glfwGetWGLContext(iptr);
diff --git a/static.c b/static.c
@@ -211,7 +211,7 @@ static FILE_WATCH_CALLBACK_FN(queue_compute_shader_reload)
work->type = BW_RELOAD_SHADER;
work->reload_shader_ctx = csr;
beamform_work_queue_push_commit(ctx->beamform_work_queue);
- ctx->os.wake_thread(ctx->os.compute_worker.sync_handle);
+ ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable);
}
return 1;
}
@@ -254,9 +254,17 @@ static OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point)
ctx->gl_context = os_get_native_gl_context(ctx->window_handle);
for (;;) {
- ctx->asleep = 1;
- os_sleep_thread(ctx->sync_handle);
- ctx->asleep = 0;
+ for (;;) {
+ i32 current = atomic_load(&ctx->sync_variable);
+ if (current) {
+ atomic_inc(&ctx->sync_variable, -current);
+ break;
+ }
+
+ ctx->asleep = 1;
+ os_wait_on_value(&ctx->sync_variable, current, -1);
+ ctx->asleep = 0;
+ }
beamformer_complete_compute(ctx->user_context, ctx->arena, ctx->gl_context);
}
@@ -285,7 +293,6 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
iptr raylib_window_handle = (iptr)GetPlatformWindowHandle();
GLWorkerThreadContext *worker = &ctx->os.compute_worker;
worker->window_handle = glfwCreateWindow(320, 240, "", 0, raylib_window_handle);
- worker->sync_handle = os_create_sync_object(memory);
worker->handle = os_create_thread(*memory, (iptr)worker, s8("[compute]"),
compute_worker_thread_entry_point);
/* TODO(rnp): we should lock this down after we have something working */
@@ -341,7 +348,7 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory)
} while (0);
COMPUTE_SHADERS
#undef X
- os_wake_thread(worker->sync_handle);
+ os_wake_waiters(&worker->sync_variable);
s8 render = s8(static_path_join("shaders", "render.glsl"));
reload_render_shader(&ctx->os, render, (iptr)&ctx->fsctx, *memory);
diff --git a/util.h b/util.h
@@ -75,6 +75,7 @@
#define MB(a) ((a) << 20ULL)
#define GB(a) ((a) << 30ULL)
+#define I32_MAX (0x7FFFFFFFL)
#define U32_MAX (0xFFFFFFFFUL)
#define F32_INFINITY (__builtin_inff())
@@ -199,8 +200,8 @@ typedef struct {
iptr handle;
iptr window_handle;
iptr gl_context;
- iptr sync_handle;
iptr user_context;
+ i32 sync_variable;
b32 asleep;
} GLWorkerThreadContext;
@@ -251,8 +252,8 @@ typedef OS_READ_WHOLE_FILE_FN(os_read_whole_file_fn);
#define OS_READ_FILE_FN(name) iz name(iptr file, void *buf, iz size)
typedef OS_READ_FILE_FN(os_read_file_fn);
-#define OS_WAKE_THREAD_FN(name) void name(iptr sync_handle)
-typedef OS_WAKE_THREAD_FN(os_wake_thread_fn);
+#define OS_WAKE_WAITERS_FN(name) void name(i32 *sync)
+typedef OS_WAKE_WAITERS_FN(os_wake_waiters_fn);
#define OS_WRITE_NEW_FILE_FN(name) b32 name(char *fname, s8 raw)
typedef OS_WRITE_NEW_FILE_FN(os_write_new_file_fn);
@@ -268,9 +269,9 @@ typedef OS_THREAD_ENTRY_POINT_FN(os_thread_entry_point_fn);
X(alloc_arena) \
X(close) \
X(open_for_write) \
- X(read_whole_file) \
X(read_file) \
- X(wake_thread) \
+ X(read_whole_file) \
+ X(wake_waiters) \
X(write_new_file) \
X(write_file)