some api changes to queue, and changing threading primatives to be more sensible
authorhgn <hgodden00@gmail.com>
Tue, 8 Apr 2025 16:22:19 +0000 (17:22 +0100)
committerhgn <hgodden00@gmail.com>
Tue, 8 Apr 2025 16:22:19 +0000 (17:22 +0100)
vg_async.c
vg_async.h
vg_console.c
vg_engine.c
vg_engine.h
vg_loader.c
vg_log.c
vg_log.h
vg_mem.c
vg_mem_queue.c
vg_mem_queue.h

index 00dfb9bed0eaedd19f4e694991dea56e8e2903be..c071641ff2aa80f0f70e3d1c9ef27483dea73da0 100644 (file)
@@ -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 );
 }
index 7f28c8ed270d8ad1b23fb43c32dcf7483a39b4a4..d20cccfceb7c6327a328626620bb3c3c59ed0fc2 100644 (file)
@@ -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 
index f9f56bb56021c036f72171e8f97c13fa3ee2078a..19937beb2b31add16b4c2497892bd5e6336e2509 100644 (file)
@@ -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 )
    {
index ed2ff7ccb0722697b2135c2f04b5e03e2004a6b6..82cea76b87cfbfbe19309eb59f10c7a3ab2b35b3 100644 (file)
@@ -7,46 +7,19 @@ struct vg_engine vg =
    .time_fixed_delta = VG_TIMESTEP_FIXED,
 };
 
-#include <string.h>
-#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 <string.h>
+#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 )
    {
index 6d872a92ce075cc0ed3bf41aa370046b14bb4385..15ea85e06a8b67cbfcf90668e613672dce4cd734 100644 (file)
@@ -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
index 9908689d2a1fc8a5f676a44737a4787e34e5ae05..8bbffd3279d812ef12d4358189b23554e12790d6 100644 (file)
@@ -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 )
    {
index 06df992a2276ad4de08f25da5d3cae6191694afc..59698c73b989f8d00c0c3022dcdf89315fc61bf4 100644 (file)
--- a/vg_log.c
+++ b/vg_log.c
@@ -5,6 +5,10 @@
 #include "vg_log.h"
 #include "vg_string.h"
 
+#ifndef VG_ENGINE
+#include <pthread.h>
+#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; i<VG_ARRAY_LEN(buffer); i ++ )
    {
@@ -103,6 +110,8 @@ void _vg_logx_va( FILE *file, const char *location, const char *prefix,
 #ifdef VG_ENGINE
    if( SDL_UnlockMutex( vg_log.mutex ) )
       vg_fatal_error( "" );
+#else
+   pthread_mutex_unlock( &vg_log.lock );
 #endif
 }
 
index 37e827ebf7c0d139b60140e17cbf0d9d063e747b..9084fe846fb337c56a80268472e615ba49546f5d 100644 (file)
--- a/vg_log.h
+++ b/vg_log.h
@@ -51,6 +51,8 @@ struct vg_log
    bool initialized;
 #ifdef VG_ENGINE
    SDL_mutex *mutex;
+#else
+   pthread_mutex_t lock;
 #endif
 }
 extern vg_log;
index 63c422b5440067f661d420e8200344eedde50c2e..c9a108c835527d99fc6620efb68e03c15827e97e 100644 (file)
--- a/vg_mem.c
+++ b/vg_mem.c
@@ -258,8 +258,7 @@ void vg_linear_clear( void *buffer )
  *        this should then only be checked and turned on in debugging.
  *
  */
-void *_vg_create_linear_allocator( void *lin_alloc, u32 size, 
-                                   u16 flags, const char *constr_name)
+void *_vg_create_linear_allocator( void *lin_alloc, u32 size, u16 flags, const char *constr_name)
 {
    VG_ASSERT( sizeof( vg_linear_allocator ) == 32 );
 
@@ -272,16 +271,13 @@ void *_vg_create_linear_allocator( void *lin_alloc, u32 size,
       vg_linear_allocator *alloc = vg_linear_header( lin_alloc );
 
       if( alloc->cur + 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 = 
index f050ebea68c6593039ee155d0fdec03fac3c380e..4f10fb36e95c092803425cc80d573d8641d2c17f 100644 (file)
@@ -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;
+}
index 22a1bdd63d09c5532bc65fe8ebaf6dd405d7df57..e1691f20e346fec860313ffd19d8ec7a33703e82 100644 (file)
@@ -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 );