#ifndef VG_ASYNC_H
#define VG_ASYNC_H
+#define VG_GAME
#include "vg/vg.h"
+static void vg_assert_thread( enum vg_thread_purpose required );
typedef struct vg_async_item vg_async_item;
}
static vg_async;
+static enum vg_thread_purpose vg_thread_purpose(void);
+static enum engine_status _vg_engine_status(void);
+
/*
* Allocate an asynchronous call with a bit of memory
*/
-VG_STATIC vg_async_item *vg_async_alloc( u32 size )
+static 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 ){
+ assert( vg_thread_purpose() == k_thread_purpose_loader );
+ longjmp( vg.env_loader_exit, 1 );
+ }
+
SDL_AtomicLock( &vg_async.sl_index );
u32 total_allocation = vg_align8(size) + vg_align8(sizeof(vg_async_item)),
vg_error( "Requested: %umb. Buffer size: %umb\n",
(total_allocation/1024)/1024,
(capacity/1024)/1024 );
- vg_fatal_exit_loop( "async alloc invalid size\n" );
+
+ vg_fatal_error( "async alloc invalid size\n" );
}
if( total_allocation > remaining ){
vg_async_item *entry = block;
entry->next = NULL;
- entry->payload = ((u8*)block) + vg_align8(sizeof(vg_async_item));
+
+ if( size ) entry->payload = ((u8*)block) + vg_align8(sizeof(vg_async_item));
+ else entry->payload = NULL;
+
entry->size = size;
entry->fn_runner = NULL;
return entry;
}
+/*
+ * Wait until the current stack of async calls is completely flushed out
+ */
+static void vg_async_stall(void){
+ vg_assert_thread(k_thread_purpose_loader);
+#if 0
+ vg_info( "async_stall: %d\n", SDL_SemValue( vg_async.sem_wait_for_flush ) );
+#endif
+ SDL_SemWait( vg_async.sem_wait_for_flush );
+}
+
/*
* Mark the call as being filled and ready to go
*/
-VG_STATIC void vg_async_dispatch( vg_async_item *item,
+static void vg_async_dispatch( vg_async_item *item,
void (*runner)( void *payload, u32 size ) )
{
+ vg_assert_thread(k_thread_purpose_loader);
+ if( SDL_SemValue(vg_async.sem_wait_for_flush) )
+ SDL_SemWait(vg_async.sem_wait_for_flush);
+
SDL_AtomicLock( &vg_async.sl_index );
item->fn_runner = runner;
SDL_AtomicUnlock( &vg_async.sl_index );
}
+/*
+ * Make a simple async call without allocating extra.
+ */
+static void vg_async_call( void (*runner)( void *payload, u32 size ),
+ void *payload, u32 size )
+{
+ vg_assert_thread(k_thread_purpose_loader);
+ vg_async_item *call = vg_async_alloc(0);
+ call->payload = payload;
+ call->size = size;
+ vg_async_dispatch( call, runner );
+}
+
/*
* Run as much of the async buffer as possible
*/
-VG_STATIC void vg_run_async_checked(void)
+static void vg_run_async_checked(void)
{
SDL_AtomicLock( &vg_async.sl_index );
}
}
else{
- break;
+ SDL_AtomicUnlock( &vg_async.sl_index );
+ return;
}
/* TODO: if exceed max frametime.... */
}
+ if( !SDL_SemValue( vg_async.sem_wait_for_flush ) ){
+ SDL_SemPost( vg_async.sem_wait_for_flush );
+ }
+
SDL_AtomicUnlock( &vg_async.sl_index );
}
-VG_STATIC void vg_async_init(void)
+static void vg_async_init(void)
{
vg_async.sem_wait_for_flush = SDL_CreateSemaphore(0);
vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024,
- VG_MEMORY_REALTIME );
+ VG_MEMORY_SYSTEM );
}
#endif /* VG_ASYNC_H */