From: hgn Date: Tue, 8 Apr 2025 16:22:19 +0000 (+0100) Subject: some api changes to queue, and changing threading primatives to be more sensible X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=f9297d73619e5bc8fa81828b94d58ba447598af1;p=vg.git some api changes to queue, and changing threading primatives to be more sensible --- diff --git a/vg_async.c b/vg_async.c index 00dfb9b..c071641 100644 --- a/vg_async.c +++ b/vg_async.c @@ -2,17 +2,15 @@ struct vg_async vg_async; -enum vg_thread_purpose vg_thread_purpose(void); -enum engine_status _vg_engine_status(void); +u32 vg_thread_purpose(void); vg_async_item *vg_async_alloc( u32 size ) { /* ditch out here if engine crashed. this serves as the 'quit checking' */ - if( _vg_engine_status() == k_engine_status_crashed ){ + if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed ) longjmp( vg.env_loader_exit, 1 ); - } - SDL_AtomicLock( &vg_async.sl_index ); + SDL_LockMutex( vg_async.lock ); u32 total_allocation = vg_align8(size) + vg_align8(sizeof(vg_async_item)), remaining = vg_linear_remaining( vg_async.buffer ), @@ -20,7 +18,7 @@ vg_async_item *vg_async_alloc( u32 size ) if( total_allocation > capacity ) { - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); vg_fatal_condition(); vg_info( "async alloc invalid size\n" ); vg_info( "Requested: %umb. Buffer size: %umb\n", @@ -31,9 +29,9 @@ vg_async_item *vg_async_alloc( u32 size ) if( total_allocation > remaining ) { - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); SDL_SemWait( vg_async.sem_wait_for_flush ); - SDL_AtomicLock( &vg_async.sl_index ); + SDL_LockMutex( vg_async.lock ); remaining = vg_linear_remaining( vg_async.buffer ); capacity = vg_linear_get_capacity( vg_async.buffer ); @@ -58,7 +56,7 @@ vg_async_item *vg_async_alloc( u32 size ) vg_async.end = entry; } - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); return entry; } @@ -79,9 +77,9 @@ void vg_async_dispatch( vg_async_item *item, if( SDL_SemValue(vg_async.sem_wait_for_flush) ) SDL_SemWait(vg_async.sem_wait_for_flush); - SDL_AtomicLock( &vg_async.sl_index ); + SDL_LockMutex( vg_async.lock ); item->fn_runner = runner; - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); } void vg_async_call( void (*runner)( void *payload, u32 size ), @@ -96,7 +94,7 @@ void vg_async_call( void (*runner)( void *payload, u32 size ), void vg_run_async_checked(void) { - SDL_AtomicLock( &vg_async.sl_index ); + SDL_LockMutex( vg_async.lock ); while( vg_async.start ) { @@ -121,7 +119,7 @@ void vg_run_async_checked(void) } else { - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); return; } } @@ -131,12 +129,16 @@ void vg_run_async_checked(void) SDL_SemPost( vg_async.sem_wait_for_flush ); } - SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_UnlockMutex( vg_async.lock ); } void vg_async_init(void) { + vg_async.lock = SDL_CreateMutex(); + VG_ASSERT( vg_async.lock ); + vg_async.sem_wait_for_flush = SDL_CreateSemaphore(0); - vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024, - VG_MEMORY_SYSTEM ); + VG_ASSERT( vg_async.sem_wait_for_flush ); + + vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024, VG_MEMORY_SYSTEM ); } diff --git a/vg_async.h b/vg_async.h index 7f28c8e..d20cccf 100644 --- a/vg_async.h +++ b/vg_async.h @@ -1,13 +1,15 @@ -/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved +/* Copyright (C) 2021-2025 Harry Godden (hgn) - All Rights Reserved * * primateves that you use when you need to run something from another thread * back in the main loop of vg, at the start of each frame + * + * TODO: Replace this with async2 in the future. */ #pragma once #include "vg_engine.h" -static void vg_assert_thread( enum vg_thread_purpose required ); +static void vg_assert_thread( u32 required ); typedef struct vg_async_item vg_async_item; struct vg_async_item @@ -27,7 +29,7 @@ struct vg_async vg_async_item *start, *end; SDL_sem *sem_wait_for_flush; - SDL_SpinLock sl_index; + SDL_mutex *lock; } extern vg_async; @@ -36,8 +38,7 @@ void vg_async_init(void); /* * Make a simple async call without allocating extra. */ -void vg_async_call( void (*runner)( void *payload, u32 size ), - void *payload, u32 size ); +void vg_async_call( void (*runner)( void *payload, u32 size ), void *payload, u32 size ); /* * Run as much of the async buffer as possible @@ -52,8 +53,7 @@ vg_async_item *vg_async_alloc( u32 size ); /* * Mark the call as being filled and ready to go */ -void vg_async_dispatch( vg_async_item *item, - void (*runner)( void *payload, u32 size ) ); +void vg_async_dispatch( vg_async_item *item, void (*runner)( void *payload, u32 size ) ); /* * Wait until the current stack of async calls is completely flushed out diff --git a/vg_console.c b/vg_console.c index f9f56bb..19937be 100644 --- a/vg_console.c +++ b/vg_console.c @@ -58,9 +58,7 @@ static int _vg_console_list( int argc, char const *argv[] ) static void vg_console_write_persistent(void) { - SDL_AtomicLock( &vg.sl_status ); - enum engine_status status = vg.engine_status; - SDL_AtomicUnlock( &vg.sl_status ); + enum engine_status status = SDL_AtomicGet( &vg.engine_status ); if( status < k_engine_status_running ) { diff --git a/vg_engine.c b/vg_engine.c index ed2ff7c..82cea76 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -7,46 +7,19 @@ struct vg_engine vg = .time_fixed_delta = VG_TIMESTEP_FIXED, }; -#include -#include "vg/vg_ui/imgui.c" -#include "vg/vg_ui/imgui_impl_opengl.c" -#include "vg/vg_default_font.gc" +const u32 k_thread_purpose_nothing = 0x00; +const u32 k_thread_purpose_main = 0x01; +const u32 k_thread_purpose_loader = 0x02; -enum engine_status _vg_engine_status(void) +u32 vg_thread_purpose(void) { - SDL_AtomicLock( &vg.sl_status ); - enum engine_status status = vg.engine_status; - SDL_AtomicUnlock( &vg.sl_status ); - - return status; + return *((u32 *)SDL_TLSGet( vg.thread_purpose )); } -enum vg_thread_purpose vg_thread_purpose(void) -{ - SDL_AtomicLock( &vg.sl_status ); - - SDL_threadID id = SDL_GetThreadID(NULL); - if( vg.thread_id_main == id ) - { - SDL_AtomicUnlock( &vg.sl_status ); - return k_thread_purpose_main; - } - else if( vg.thread_id_loader == id ) - { - SDL_AtomicUnlock( &vg.sl_status ); - return k_thread_purpose_loader; - } - else - { - SDL_AtomicUnlock( &vg.sl_status ); - return k_thread_purpose_nothing; - } -} - -static void _vg_opengl_sync_init(void) -{ - vg.sem_loader = SDL_CreateSemaphore(1); -} +#include +#include "vg/vg_ui/imgui.c" +#include "vg/vg_ui/imgui_impl_opengl.c" +#include "vg/vg_default_font.gc" #include "vg_console.h" #include "vg_profiler.h" @@ -104,15 +77,10 @@ void async_internal_complete( void *payload, u32 size ) { vg_success( "Internal async setup complete\n" ); - SDL_AtomicLock( &vg.sl_status ); - if( vg.engine_status == k_engine_status_crashed ) - { - SDL_AtomicUnlock( &vg.sl_status ); + if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed ) return; - } else - vg.engine_status = k_engine_status_running; - SDL_AtomicUnlock( &vg.sl_status ); + SDL_AtomicSet( &vg.engine_status, k_engine_status_running ); vg_magi_restore(); } @@ -471,7 +439,7 @@ static void _vg_gameloop(void) vg_changevsync(); - enum engine_status status = _vg_engine_status(); + enum engine_status status = SDL_AtomicGet( &vg.engine_status ); if( status == k_engine_status_running ) vg_profile_begin( &vg_prof_swap ); @@ -709,16 +677,11 @@ static void _vg_terminate(void) vg_magi_save(); vg_console_write_persistent(); - SDL_AtomicLock( &vg.sl_status ); - vg.engine_status = k_engine_status_none; - SDL_AtomicUnlock( &vg.sl_status ); - + SDL_AtomicSet( &vg.engine_status, k_engine_status_none ); vg_loader_atexit(); SDL_GL_DeleteContext( vg.gl_context ); SDL_Quit(); - - vg_success( "The program has terminated 'correctly'\n" ); exit(0); } @@ -731,6 +694,10 @@ static int cmd_log_memory( int argc, const char *argv[] ) static int cmd_vg_settings_toggle( int argc, const char *argv[] ); void vg_enter( int argc, char *argv[], const char *window_name ) { + vg.thread_purpose = SDL_TLSCreate(); + VG_ASSERT( vg.thread_purpose ); + SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_nothing, NULL ); + vg_rand_seed( &vg.rand, 461 ); _vg_process_launch_opts_internal( argc, argv ); @@ -754,15 +721,17 @@ void vg_enter( int argc, char *argv[], const char *window_name ) vg_async_init(); SDL_SetRelativeMouseMode(1); - vg.thread_id_main = SDL_GetThreadID(NULL); + /* multi-threaded loading phase */ + vg.sem_loader = SDL_CreateSemaphore(1); + VG_ASSERT( vg.sem_loader ); + SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal ); + SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_main, NULL ); /* Opengl-required systems */ vg_ui_init(); - vg.engine_status = k_engine_status_load_internal; vg_loader_step( vg_loader_init, vg_loader_free ); - _vg_opengl_sync_init(); vg_loader_start( _vg_load_full, NULL ); _vg_gameloop(); _vg_terminate(); @@ -794,9 +763,7 @@ void vg_fatal_exit(void) free( strings ); #endif - SDL_AtomicLock( &vg.sl_status ); - vg.engine_status = k_engine_status_crashed; - SDL_AtomicUnlock( &vg.sl_status ); + SDL_AtomicSet( &vg.engine_status, k_engine_status_crashed ); if( vg_thread_purpose() == k_thread_purpose_loader ) { diff --git a/vg_engine.h b/vg_engine.h index 6d872a9..15ea85e 100644 --- a/vg_engine.h +++ b/vg_engine.h @@ -111,14 +111,14 @@ enum quality_profile{ k_quality_profile_min = 2 }; -enum vg_thread_purpose +enum engine_status { - k_thread_purpose_nothing, - k_thread_purpose_main, - k_thread_purpose_loader + k_engine_status_none, + k_engine_status_load_internal, + k_engine_status_running, + k_engine_status_crashed }; - struct vg_engine { /* Engine sync */ @@ -126,21 +126,15 @@ struct vg_engine SDL_GLContext gl_context; SDL_sem *sem_loader; /* allows only one loader at a time */ - SDL_threadID thread_id_main, - thread_id_loader; + SDL_TLSID thread_purpose; - SDL_SpinLock sl_status; + //SDL_threadID thread_id_main, + // thread_id_loader; jmp_buf env_loader_exit; - void *thread_data; + void *thread_data; - enum engine_status{ - k_engine_status_none, - k_engine_status_load_internal, - k_engine_status_running, - k_engine_status_crashed - } - engine_status; + SDL_atomic_t engine_status; /* Window information */ int window_x, @@ -259,7 +253,12 @@ bool vg_settings_apply_button( ui_context *ctx, ui_rect inout_panel, bool validated ); enum engine_status _vg_engine_status(void); -enum vg_thread_purpose vg_thread_purpose(void); + + +extern const u32 k_thread_purpose_nothing; +extern const u32 k_thread_purpose_main; +extern const u32 k_thread_purpose_loader; +u32 vg_thread_purpose(void); void vg_checkgl( const char *src_info ); #define VG_STRINGIT( X ) #X diff --git a/vg_loader.c b/vg_loader.c index 9908689..8bbffd3 100644 --- a/vg_loader.c +++ b/vg_loader.c @@ -175,21 +175,16 @@ void vg_loader_render(void) static int _vg_loader_thread( void *pfn ) { - vg.thread_id_loader = SDL_GetThreadID(NULL); + SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL ); if( setjmp( vg.env_loader_exit ) ) - { - vg.thread_id_loader = 0; return 0; - } /* Run client loader */ void (*call_func)(void *data) = pfn; call_func( vg.thread_data ); SDL_SemPost( vg.sem_loader ); - vg.thread_id_loader = 0; - return 0; } @@ -237,9 +232,7 @@ void _vg_loader_step( void( *fn_load )(void), void( *fn_free )(void), vg_loader.step_buffer[ vg_loader.step_count ++ ] = step; } - SDL_AtomicLock( &vg.sl_status ); - enum engine_status status = vg.engine_status; - SDL_AtomicUnlock( &vg.sl_status ); + enum engine_status status = SDL_AtomicGet( &vg.engine_status ); if( status != k_engine_status_load_internal ) { diff --git a/vg_log.c b/vg_log.c index 06df992..59698c7 100644 --- a/vg_log.c +++ b/vg_log.c @@ -5,6 +5,10 @@ #include "vg_log.h" #include "vg_string.h" +#ifndef VG_ENGINE +#include +#endif + struct vg_log vg_log; static void _vg_log_append_line( const char *str ) @@ -29,6 +33,9 @@ void vg_log_init(void) printf( "SDL2 Error: %s\n", SDL_GetError() ); exit(-1); } +#else + if( pthread_mutex_init( &vg_log.lock, NULL ) ) + exit(-1); #endif } @@ -46,14 +53,14 @@ void _vg_logx_va( FILE *file, const char *location, const char *prefix, #ifdef VG_ENGINE if( SDL_LockMutex( vg_log.mutex ) ) vg_fatal_error( "" ); +#else + pthread_mutex_lock( &vg_log.lock ); #endif char buffer[4096], line[96]; - static char last_buffer[4096]; vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args ); int line_length = snprintf( line, 90, "%s%7s" KNRM "|%s ", colour, prefix, colour ); - strcpy( last_buffer, buffer ); for( u32 i=0; icur + block_size > alloc->size ) - vg_fatal_error( "Out of memory (%u + %u > %u)\n", - alloc->cur, block_size, alloc->size ); + vg_fatal_error( "Out of memory (%u + %u > %u)\n", alloc->cur, block_size, alloc->size ); if( alloc->allocation_count + 1 > VG_MAX_ALLOCATIONS ) - vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n", - VG_MAX_ALLOCATIONS ); + vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n", VG_MAX_ALLOCATIONS ); if( (flags && VG_MEMORY_SYSTEM) && (alloc->flags & VG_MEMORY_REALTIME) ) - vg_fatal_error( "Cannot declare realtime allocator inside systems " - "allocator"); + vg_fatal_error( "Cannot declare realtime allocator inside systems allocator"); if( vg_mem.use_libc_malloc ){ vg_allocation_meta *meta = diff --git a/vg_mem_queue.c b/vg_mem_queue.c index f050ebe..4f10fb3 100644 --- a/vg_mem_queue.c +++ b/vg_mem_queue.c @@ -164,6 +164,12 @@ void vg_queue_pop( vg_queue *q ) tail->prev_size = 0; } +u32 vg_queue_item_size( vg_queue *q, u32 item_id ) +{ + vg_queue_item *item = q->buffer + item_id; + return item->alloc_size; +} + bool vg_queue_previous( vg_queue *q, u32 item_id, u32 *out_prev ) { vg_queue_item *item = q->buffer + item_id; @@ -176,12 +182,6 @@ bool vg_queue_previous( vg_queue *q, u32 item_id, u32 *out_prev ) else return 0; } -u32 vg_queue_item_size( vg_queue *q, u32 item_id ) -{ - vg_queue_item *item = q->buffer + item_id; - return item->alloc_size; -} - bool vg_queue_next( vg_queue *q, u32 item_id, u32 *out_next ) { if( item_id != q->head_offset ) @@ -210,3 +210,10 @@ u32 vg_queue_usage( vg_queue *q ) else return 0; } + +void vg_queue_clear( vg_queue *q ) +{ + q->head_offset = 0; + q->tail_offset = 0; + q->allocation_count = 0; +} diff --git a/vg_mem_queue.h b/vg_mem_queue.h index 22a1bdd..e1691f2 100644 --- a/vg_mem_queue.h +++ b/vg_mem_queue.h @@ -35,3 +35,4 @@ u32 vg_queue_offset_upgrade( vg_queue *q, u32 offset ); void vg_queue_memcpy( vg_queue *q, void *dst, u32 start, u32 size ); u32 vg_queue_usage( vg_queue *q ); +void vg_queue_clear( vg_queue *q );