ogl_beamforming

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

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:
Mbeamformer.c | 4++--
Mbuild.sh | 2+-
Mmain_linux.c | 4++--
Mmain_w32.c | 2+-
Aos_linux.c | 294+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dos_unix.c | 290-------------------------------------------------------------------------------
Mos_win32.c | 28+++++++++++++++-------------
Mstatic.c | 19+++++++++++++------
Mutil.h | 11++++++-----
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, &current, 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)