eliminate bifurcated rw lock path based on exclusive mode; promote thread operations to base layer, use os layer as impl; first pass on moving file streaming layer to base layer's async wavefront

This commit is contained in:
Ryan Fleury
2025-09-17 14:47:55 -07:00
parent 99c989a3c3
commit 0d15b8670b
40 changed files with 450 additions and 607 deletions
+30 -61
View File
@@ -121,7 +121,7 @@ internal void *
os_lnx_thread_entry_point(void *ptr)
{
OS_LNX_Entity *entity = (OS_LNX_Entity *)ptr;
OS_ThreadFunctionType *func = entity->thread.func;
ThreadEntryPointFunctionType *func = entity->thread.func;
void *thread_ptr = entity->thread.ptr;
supplement_thread_base_entry_point(func, thread_ptr);
return 0;
@@ -801,7 +801,7 @@ os_process_kill(OS_Handle handle)
//~ rjf: @os_hooks Threads (Implemented Per-OS)
internal OS_Handle
os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params)
os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params)
{
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread);
entity->thread.func = func;
@@ -911,31 +911,22 @@ os_rw_mutex_release(OS_Handle rw_mutex)
}
internal void
os_rw_mutex_take_r(OS_Handle rw_mutex)
os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode)
{
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
pthread_rwlock_rdlock(&entity->rwmutex_handle);
if(write_mode)
{
pthread_rwlock_wrlock(&entity->rwmutex_handle);
}
else
{
pthread_rwlock_rdlock(&entity->rwmutex_handle);
}
}
internal void
os_rw_mutex_drop_r(OS_Handle rw_mutex)
{
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
pthread_rwlock_unlock(&entity->rwmutex_handle);
}
internal void
os_rw_mutex_take_w(OS_Handle rw_mutex)
{
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
pthread_rwlock_wrlock(&entity->rwmutex_handle);
}
internal void
os_rw_mutex_drop_w(OS_Handle rw_mutex)
os_rw_mutex_drop(OS_Handle rw_mutex, B32 write_mode)
{
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
@@ -995,7 +986,7 @@ os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us)
}
internal B32
os_cond_var_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us)
os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_us)
{
// TODO(rjf): because pthread does not supply cv/rw natively, I had to hack
// this together, but this would probably just be a lot better if we just
@@ -1016,49 +1007,27 @@ os_cond_var_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us)
int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec);
if(wait_result != ETIMEDOUT)
{
pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle);
if(write_mode)
{
pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle);
}
else
{
pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle);
}
result = 1;
break;
}
if(wait_result == ETIMEDOUT)
{
pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle);
break;
}
}
pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle);
return result;
}
internal B32
os_cond_var_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us)
{
// TODO(rjf): because pthread does not supply cv/rw natively, I had to hack
// this together, but this would probably just be a lot better if we just
// implemented the primitives ourselves with e.g. futexes
//
if(os_handle_match(cv, os_handle_zero())) { return 0; }
if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; }
OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0];
OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0];
struct timespec endt_timespec;
endt_timespec.tv_sec = endt_us/Million(1);
endt_timespec.tv_nsec = Thousand(1) * (endt_us - (endt_us/Million(1))*Million(1));
B32 result = 0;
pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle);
pthread_rwlock_unlock(&rw_mutex_entity->rwmutex_handle);
for(;;)
{
int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec);
if(wait_result != ETIMEDOUT)
{
pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle);
result = 1;
break;
}
if(wait_result == ETIMEDOUT)
{
pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle);
if(write_mode)
{
pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle);
}
else
{
pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle);
}
break;
}
}
@@ -1229,7 +1198,7 @@ os_library_close(OS_Handle lib)
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal void
os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr)
os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr)
{
// rjf: push handler to chain
OS_LNX_SafeCallChain chain = {0};
+2 -2
View File
@@ -54,7 +54,7 @@ typedef struct OS_LNX_SafeCallChain OS_LNX_SafeCallChain;
struct OS_LNX_SafeCallChain
{
OS_LNX_SafeCallChain *next;
OS_ThreadFunctionType *fail_handler;
ThreadEntryPointFunctionType *fail_handler;
void *ptr;
};
@@ -81,7 +81,7 @@ struct OS_LNX_Entity
struct
{
pthread_t handle;
OS_ThreadFunctionType *func;
ThreadEntryPointFunctionType *func;
void *ptr;
} thread;
pthread_mutex_t mutex_handle;
+3 -3
View File
@@ -783,7 +783,7 @@ lnx_free_entity(LNX_Entity *entity){
internal void*
lnx_thread_base(void *ptr){
LNX_Entity *entity = (LNX_Entity*)ptr;
OS_ThreadFunctionType *func = entity->thread.func;
ThreadEntryPointFunctionType *func = entity->thread.func;
void *thread_ptr = entity->thread.ptr;
TCTX tctx_;
@@ -1377,7 +1377,7 @@ os_launch_process(OS_LaunchOptions *options){
//~ rjf: @os_hooks Threads (Implemented Per-OS)
internal OS_Handle
os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params){
os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params){
// entity
LNX_Entity *entity = lnx_alloc_entity(LNX_EntityKind_Thread);
entity->reference_mask = 0x3;
@@ -1642,7 +1642,7 @@ os_library_close(OS_Handle lib)
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
internal void
os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr){
os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr){
LNX_SafeCallChain chain = {0};
SLLStackPush(lnx_safe_call_chain, &chain);
chain.fail_handler = fail_handler;
+2 -2
View File
@@ -48,7 +48,7 @@ struct LNX_Entity{
volatile U32 reference_mask;
union{
struct{
OS_ThreadFunctionType *func;
ThreadEntryPointFunctionType *func;
void *ptr;
pthread_t handle;
} thread;
@@ -62,7 +62,7 @@ struct LNX_Entity{
struct LNX_SafeCallChain{
LNX_SafeCallChain *next;
OS_ThreadFunctionType *fail_handler;
ThreadEntryPointFunctionType *fail_handler;
void *ptr;
};
-15
View File
@@ -40,21 +40,6 @@ os_handle_array_from_list(Arena *arena, OS_HandleList *list)
return result;
}
////////////////////////////////
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal String8List
os_string_list_from_argcv(Arena *arena, int argc, char **argv)
{
String8List result = {0};
for(int i = 0; i < argc; i += 1)
{
String8 str = str8_cstring(argv[i]);
str8_list_push(arena, &result, str);
}
return result;
}
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
+7 -26
View File
@@ -128,11 +128,6 @@ struct OS_ProcessLaunchParams
OS_Handle stdin_file;
};
////////////////////////////////
//~ rjf: Thread Types
typedef void OS_ThreadFunctionType(void *ptr);
////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
@@ -141,11 +136,6 @@ internal B32 os_handle_match(OS_Handle a, OS_Handle b);
internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle);
internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list);
////////////////////////////////
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
@@ -262,9 +252,9 @@ internal B32 os_process_kill(OS_Handle handle);
////////////////////////////////
//~ rjf: @os_hooks Threads (Implemented Per-OS)
internal OS_Handle os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params);
internal B32 os_thread_join(OS_Handle handle, U64 endt_us);
internal void os_thread_detach(OS_Handle handle);
internal Thread os_thread_launch(ThreadEntryPointFunctionType *f, void *p);
internal B32 os_thread_join(Thread handle, U64 endt_us);
internal void os_thread_detach(Thread handle);
////////////////////////////////
//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS)
@@ -278,18 +268,15 @@ internal void os_mutex_drop(Mutex mutex);
//- rjf: reader/writer mutexes
internal RWMutex os_rw_mutex_alloc(void);
internal void os_rw_mutex_release(RWMutex mutex);
internal void os_rw_mutex_take_r(RWMutex mutex);
internal void os_rw_mutex_drop_r(RWMutex mutex);
internal void os_rw_mutex_take_w(RWMutex mutex);
internal void os_rw_mutex_drop_w(RWMutex mutex);
internal void os_rw_mutex_take(RWMutex mutex, B32 write_mode);
internal void os_rw_mutex_drop(RWMutex mutex, B32 write_mode);
//- rjf: condition variables
internal CondVar os_cond_var_alloc(void);
internal void os_cond_var_release(CondVar cv);
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
internal B32 os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
internal B32 os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us);
internal B32 os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us);
internal B32 os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
internal void os_cond_var_signal(CondVar cv);
internal void os_cond_var_broadcast(CondVar cv);
@@ -306,12 +293,6 @@ internal Barrier os_barrier_alloc(U64 count);
internal void os_barrier_release(Barrier barrier);
internal void os_barrier_wait(Barrier barrier);
//- rjf: scope macros
#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex))
#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex))
#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex))
#define OS_MutexScopeRWPromote(mutex) DeferLoop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex)))
////////////////////////////////
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
@@ -322,7 +303,7 @@ internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name);
////////////////////////////////
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr);
internal void os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr);
////////////////////////////////
//~ rjf: @os_hooks GUIDs (Implemented Per-OS)
+29 -43
View File
@@ -144,7 +144,7 @@ internal DWORD
os_w32_thread_entry_point(void *ptr)
{
OS_W32_Entity *entity = (OS_W32_Entity *)ptr;
OS_ThreadFunctionType *func = entity->thread.func;
ThreadEntryPointFunctionType *func = entity->thread.func;
void *thread_ptr = entity->thread.ptr;
supplement_thread_base_entry_point(func, thread_ptr);
return 0;
@@ -1103,19 +1103,19 @@ os_process_detach(OS_Handle handle)
////////////////////////////////
//~ rjf: @os_hooks Threads (Implemented Per-OS)
internal OS_Handle
os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params)
internal Thread
os_thread_launch(ThreadEntryPointFunctionType *f, void *p)
{
OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Thread);
entity->thread.func = func;
entity->thread.ptr = ptr;
entity->thread.func = f;
entity->thread.ptr = p;
entity->thread.handle = CreateThread(0, 0, os_w32_thread_entry_point, entity, 0, &entity->thread.tid);
OS_Handle result = {IntFromPtr(entity)};
Thread result = {IntFromPtr(entity)};
return result;
}
internal B32
os_thread_join(OS_Handle handle, U64 endt_us)
os_thread_join(Thread handle, U64 endt_us)
{
DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
OS_W32_Entity *entity = (OS_W32_Entity *)PtrFromInt(handle.u64[0]);
@@ -1130,7 +1130,7 @@ os_thread_join(OS_Handle handle, U64 endt_us)
}
internal void
os_thread_detach(OS_Handle thread)
os_thread_detach(Thread thread)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]);
if(entity != 0)
@@ -1194,31 +1194,31 @@ os_rw_mutex_release(RWMutex rw_mutex)
}
internal void
os_rw_mutex_take_r(RWMutex rw_mutex)
os_rw_mutex_take(RWMutex rw_mutex, B32 write_mode)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]);
AcquireSRWLockShared(&entity->rw_mutex);
if(write_mode)
{
AcquireSRWLockExclusive(&entity->rw_mutex);
}
else
{
AcquireSRWLockShared(&entity->rw_mutex);
}
}
internal void
os_rw_mutex_drop_r(RWMutex rw_mutex)
os_rw_mutex_drop(RWMutex rw_mutex, B32 write_mode)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]);
ReleaseSRWLockShared(&entity->rw_mutex);
}
internal void
os_rw_mutex_take_w(RWMutex rw_mutex)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]);
AcquireSRWLockExclusive(&entity->rw_mutex);
}
internal void
os_rw_mutex_drop_w(RWMutex rw_mutex)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]);
ReleaseSRWLockExclusive(&entity->rw_mutex);
if(write_mode)
{
ReleaseSRWLockExclusive(&entity->rw_mutex);
}
else
{
ReleaseSRWLockShared(&entity->rw_mutex);
}
}
//- rjf: condition variables
@@ -1254,7 +1254,7 @@ os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us)
}
internal B32
os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us)
os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us)
{
U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
BOOL result = 0;
@@ -1263,21 +1263,7 @@ os_cond_var_wait_rw_r(CondVar cv, RWMutex mutex_rw, U64 endt_us)
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]);
OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]);
result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms,
CONDITION_VARIABLE_LOCKMODE_SHARED);
}
return result;
}
internal B32
os_cond_var_wait_rw_w(CondVar cv, RWMutex mutex_rw, U64 endt_us)
{
U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
BOOL result = 0;
if(sleep_ms > 0)
{
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]);
OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]);
result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0);
write_mode ? 0 : CONDITION_VARIABLE_LOCKMODE_SHARED);
}
return result;
}
@@ -1413,7 +1399,7 @@ os_library_close(OS_Handle lib)
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal void
os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr)
os_safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr)
{
__try
{
+1 -1
View File
@@ -62,7 +62,7 @@ struct OS_W32_Entity
{
struct
{
OS_ThreadFunctionType *func;
ThreadEntryPointFunctionType *func;
void *ptr;
HANDLE handle;
DWORD tid;