diff --git a/src/asset_cache/asset_cache_core.c b/src/asset_cache/asset_cache_core.c index 687e4faa..1243312e 100644 --- a/src/asset_cache/asset_cache_core.c +++ b/src/asset_cache/asset_cache_core.c @@ -29,7 +29,7 @@ void AC_RefreshDebugTable(void) { #if RtcIsEnabled AC_SharedState *g = &AC_shared_state; - P_Lock lock = P_LockE(&g->dbg_table_mutex); + Lock lock = LockE(&g->dbg_table_mutex); ZeroArray(g->dbg_table); g->dbg_table_count = 0; for (u64 i = 0; i < countof(g->lookup); ++i) @@ -40,16 +40,16 @@ void AC_RefreshDebugTable(void) g->dbg_table[g->dbg_table_count++] = asset; } } - P_Unlock(&lock); + Unlock(&lock); #endif } /* Returns first matching slot or first empty slot if not found. * Check returned slot->hash != 0 for presence. */ -AC_Asset *AC_GetAssetCacheSlotLocked(P_Lock *lock, String key, u64 hash) +AC_Asset *AC_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash) { AC_SharedState *g = &AC_shared_state; - P_AssertLockedES(lock, &g->lookup_mutex); + AssertLockedES(lock, &g->lookup_mutex); LAX lock; u64 index = hash % countof(g->lookup); @@ -96,9 +96,9 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) /* Lookup */ { - P_Lock lock = P_LockS(&g->lookup_mutex); + Lock lock = LockS(&g->lookup_mutex); asset = AC_GetAssetCacheSlotLocked(&lock, key, hash); - P_Unlock(&lock); + Unlock(&lock); } /* Insert if not found */ @@ -111,7 +111,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) } else { - P_Lock lock = P_LockE(&g->lookup_mutex); + Lock lock = LockE(&g->lookup_mutex); /* Re-check asset presence in case it was inserted since lock */ asset = AC_GetAssetCacheSlotLocked(&lock, key, hash); @@ -136,7 +136,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) .hash = hash, .key = key_stored }; - P_CounterAdd(&asset->counter, 1); + AddCounter(&asset->counter, 1); if (is_first_touch) { *is_first_touch = 1; @@ -146,7 +146,7 @@ AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch) AC_RefreshDebugTable(); } - P_Unlock(&lock); + Unlock(&lock); } return asset; @@ -166,12 +166,12 @@ void AC_MarkReady(AC_Asset *asset, void *store_data) { asset->store_data = store_data; asset->status = ASSET_STATUS_READY; - P_CounterAdd(&asset->counter, -1); + AddCounter(&asset->counter, -1); } void AC_WaitOnAssetReady(AC_Asset *asset) { - P_WaitOnCounter(&asset->counter); + WaitOnCounter(&asset->counter); } //////////////////////////////// @@ -193,7 +193,7 @@ void *AC_DataFromStore(AC_Asset *asset) AC_Store AC_OpenStore(void) { AC_SharedState *g = &AC_shared_state; - P_Lock lock = P_LockE(&g->store_mutex); + Lock lock = LockE(&g->store_mutex); AC_Store store = { .lock = lock, .arena = g->store_arena @@ -203,5 +203,5 @@ AC_Store AC_OpenStore(void) void AC_CloseStore(AC_Store *store) { - P_Unlock(&store->lock); + Unlock(&store->lock); } diff --git a/src/asset_cache/asset_cache_core.h b/src/asset_cache/asset_cache_core.h index eb8b6a6b..f2c31109 100644 --- a/src/asset_cache/asset_cache_core.h +++ b/src/asset_cache/asset_cache_core.h @@ -34,7 +34,7 @@ Struct(AC_Store) Arena *arena; /* internal */ - P_Lock lock; + Lock lock; }; //////////////////////////////// @@ -45,18 +45,18 @@ Struct(AC_Store) Struct(AC_SharedState) { - P_Mutex lookup_mutex; + Mutex lookup_mutex; AC_Asset lookup[AC_AssetLookupTableCapacity]; u64 num_assets; - P_Mutex store_mutex; + Mutex store_mutex; Arena *store_arena; #if RtcIsEnabled /* Array of len `num_assets` pointing into populated entries of `lookup`. */ AC_Asset *dbg_table[AC_AssetLookupTableCapacity]; u64 dbg_table_count; - P_Mutex dbg_table_mutex; + Mutex dbg_table_mutex; #endif }; @@ -77,7 +77,7 @@ u64 AC_HashFromKey(String key); //~ Cache operations void AC_RefreshDebugTable(void); -AC_Asset *AC_GetAssetCacheSlotLocked(P_Lock *lock, String key, u64 hash); +AC_Asset *AC_GetAssetCacheSlotLocked(Lock *lock, String key, u64 hash); AC_Asset *AC_TouchCache(String key, u64 hash, b32 *is_first_touch); //////////////////////////////// diff --git a/src/base/base.c b/src/base/base.c index 70c7fd18..93fe0db1 100644 --- a/src/base/base.c +++ b/src/base/base.c @@ -10,9 +10,10 @@ #include "base_uid.c" #include "base_uni.c" #include "base_incbin.c" +#include "base_snc.c" #if PlatformIsWindows # include "win32/base_win32.c" #else # error Base layer platform backend not implemented -#enidf +#endif diff --git a/src/base/base.h b/src/base/base.h index 2fa051bc..e88a6980 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -8,8 +8,9 @@ #include "../prof/prof.h" # include "base_intrinsics.h" # include "base_memory.h" -# include "base_job.h" # include "base_arena.h" +# include "base_snc.h" +# include "base_job.h" # include "base_uid.h" # include "base_string.h" # include "base_uni.h" diff --git a/src/base/base_core.h b/src/base/base_core.h index 4cc5a5aa..71f77ab9 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -548,6 +548,23 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm) } #endif +//////////////////////////////// +//~ Fibers + +#define MaxFibers 4096 + +#if !LanguageIsGpu +ForceInline i16 FiberId(void) +{ + /* FIXME */ + //return (i16)(i64)GetFiberData(); + Assert(0); + return 0; +} +StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */ +#endif + + //////////////////////////////// //~ Config diff --git a/src/base/base_job.h b/src/base/base_job.h index 42091594..fb1b1f83 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -33,30 +33,59 @@ typedef i32 PriorityKind; enum }; //////////////////////////////// -//~ @hookdecl Fiber helpers +//~ @hookdecl Futex -#define MaxFibers 4096 - -i16 FiberId(void); -StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */ +/* Futex-like wait & wake */ +void FutexWait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns); +void FutexWake(void *addr, i32 count); //////////////////////////////// //~ @hookdecl Job helpers #define EmptySig { i32 _; } +typedef void GenericJobFunc(void *, i32); + +Struct(GenericJobDesc) +{ + Arena *arena; + void *sig; + GenericJobFunc *func; + i32 count; + PoolKind pool; + PriorityKind priority; + Counter *counter; +}; + +Struct(JobDescParams) +{ + i32 count; + PoolKind pool; + PriorityKind priority; + Counter *counter; +}; + #define JobDecl(job, sigdef) \ typedef struct job##_Sig sigdef job##_Sig; \ - Struct(job##_Desc) { Counter *counter; Arena *job_arena; job##_Sig *sig; }; \ - void job(job##_Sig *) + Struct(job##_Desc) { Arena *arena; job##_Sig *sig; GenericJobFunc *func; i32 count; PoolKind pool; PriorityKind priority; Counter *counter;}; \ + void job(job##_Sig *, i32) -#define JobDef(job, sig_arg) void job(job##_Sig *sig_arg) +#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), (GenericJobFunc *)(i64)job, (JobDescParams) { .count = 1, .pool = PoolKind_Inherit, .priority = PriorityKind_Inherit, .counter = 0, __VA_ARGS__ }) +GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params); -#define RunJob(job, desc) job(&desc->sig) +#define JobDef(job, sig_arg, id_arg) void job(job##_Sig *sig_arg, i32 id_arg) + +#define RunJob(_count, job, _pool, _priority, _counter, ...) do { \ + job##_Desc *__job_desc = (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), (GenericJobFunc *)(i64)job, (JobDescParams) { .count = _count, .pool = _pool, .priority = _priority, .counter = _counter,}); \ + *__job_desc->sig = (job##_Sig) { __VA_ARGS__ }; \ +} while (0) +void RunJobEx(GenericJobDesc *desc); //////////////////////////////// -//~ @hookdecl Wait +//~ @hookdecl Helpers -/* Futex-like wait & wake */ -void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns); -void P_Wake(void *addr, i32 count); +i64 TimeNs(void); + +u32 GetLogicalProcessorCount(void); +u32 ThreadId(void); +i64 GetCurrentSchedulerPeriodNs(void); diff --git a/src/base/base_rand.c b/src/base/base_rand.c index f554c950..9cb1e809 100644 --- a/src/base/base_rand.c +++ b/src/base/base_rand.c @@ -2,8 +2,10 @@ //~ True randomness #if PlatformIsWindows +#if 0 # define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); +#endif void TrueRand(String buffer) { BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); diff --git a/src/platform/platform_snc.c b/src/base/base_snc.c similarity index 76% rename from src/platform/platform_snc.c rename to src/base/base_snc.c index 1013640b..6964ac9a 100644 --- a/src/platform/platform_snc.c +++ b/src/base/base_snc.c @@ -2,7 +2,7 @@ //~ Mutex //- Exclusive mutex lock -P_Lock P_LockSpinE(P_Mutex *m, i32 spin) +Lock LockSpinE(Mutex *m, i32 spin) { b32 locked = 0; i32 spin_cnt = 0; @@ -49,7 +49,7 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin) } else { - P_Wait(&m->v, &v, 4, I64Max); + FutexWait(&m->v, &v, 4, I64Max); spin_cnt = 0; } } @@ -59,14 +59,14 @@ P_Lock P_LockSpinE(P_Mutex *m, i32 spin) Atomic32FetchSet(&m->exclusive_fiber_id, FiberId()); #endif - P_Lock lock = ZI; + Lock lock = ZI; lock.exclusive = 1; lock.mutex = m; return lock; } //- Shared mutex lock -P_Lock P_LockSpinS(P_Mutex *m, i32 spin) +Lock LockSpinS(Mutex *m, i32 spin) { b32 locked = 0; i32 spin_cnt = 0; @@ -96,30 +96,30 @@ P_Lock P_LockSpinS(P_Mutex *m, i32 spin) } else { - P_Wait(&m->v, &v, 4, I64Max); + FutexWait(&m->v, &v, 4, I64Max); spin_cnt = 0; } } } - P_Lock lock = ZI; + Lock lock = ZI; lock.mutex = m; return lock; } //- Mutex lock wrappers -P_Lock P_LockE(P_Mutex *m) +Lock LockE(Mutex *m) { - return P_LockSpinE(m, P_DefaultMutexSpin); + return LockSpinE(m, DefaultMutexSpin); } -P_Lock P_LockS(P_Mutex *m) +Lock LockS(Mutex *m) { - return P_LockSpinS(m, P_DefaultMutexSpin); + return LockSpinS(m, DefaultMutexSpin); } -void P_Unlock(P_Lock *l) +void Unlock(Lock *l) { - P_Mutex *m = l->mutex; + Mutex *m = l->mutex; if (l->exclusive) { #if RtcIsEnabled @@ -131,64 +131,64 @@ void P_Unlock(P_Lock *l) { Atomic32FetchAdd(&m->v, -1); } - P_Wake(&m->v, I32Max); + FutexWake(&m->v, I32Max); ZeroStruct(l); } //////////////////////////////// //~ Condition variable -void P_WaitOnCv(P_Cv *cv, P_Lock *l) +void WaitOnCv(Cv *cv, Lock *l) { - P_WaitOnCvTime(cv, l, I64Max); + WaitOnCvTime(cv, l, I64Max); } -void P_WaitOnCvTime(P_Cv *cv, P_Lock *l, i64 timeout_ns) +void WaitOnCvTime(Cv *cv, Lock *l, i64 timeout_ns) { u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen); - P_Mutex *mutex = l->mutex; + Mutex *mutex = l->mutex; b32 exclusive = l->exclusive; { - P_Unlock(l); + Unlock(l); { - P_Wait(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen), timeout_ns); + FutexWait(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen), timeout_ns); } if (exclusive) { - *l = P_LockE(mutex); + *l = LockE(mutex); } else { - *l = P_LockS(mutex); + *l = LockS(mutex); } } } -void P_SignalCv(P_Cv *cv, i32 count) +void SignalCv(Cv *cv, i32 count) { Atomic64FetchAdd(&cv->wake_gen, 1); - P_Wake(&cv->wake_gen, count); + FutexWake(&cv->wake_gen, count); } //////////////////////////////// //~ Counter -void P_CounterAdd(Counter *counter, i64 x) +void AddCounter(Counter *counter, i64 x) { i64 old_v = Atomic64FetchAdd(&counter->v, x); i64 new_v = old_v + x; if (old_v > 0 && new_v <= 0) { - P_Wake(&counter->v, I32Max); + FutexWake(&counter->v, I32Max); } } -void P_WaitOnCounter(Counter *counter) +void WaitOnCounter(Counter *counter) { i64 v = Atomic64Fetch(&counter->v); while (v > 0) { - P_Wait(&counter->v, &v, sizeof(v), I64Max); + FutexWait(&counter->v, &v, sizeof(v), I64Max); v = Atomic64Fetch(&counter->v); } } diff --git a/src/base/base_snc.h b/src/base/base_snc.h new file mode 100644 index 00000000..d272ec11 --- /dev/null +++ b/src/base/base_snc.h @@ -0,0 +1,83 @@ +//////////////////////////////// +//~ Mutex types + +#define DefaultMutexSpin 4000 + +AlignedStruct(Mutex, 64) +{ + /* Bit 31 = Exclusive lock is held + * Bit 30 = Exclusive lock is pending + * Bit 0-30 = Shared locks count + */ + Atomic32 v; + +#if RtcIsEnabled + Atomic32 exclusive_fiber_id; + u8 _pad[56]; +#else + u8 _pad[60]; +#endif +}; +StaticAssert(sizeof(Mutex) == 64); /* Padding validation */ +StaticAssert(alignof(Mutex) == 64); /* Prevent false sharing */ + +Struct(Lock) +{ + Mutex *mutex; + b32 exclusive; +}; + +//////////////////////////////// +//~ Condition variable types + +AlignedStruct(Cv, 64) +{ + Atomic64 wake_gen; + u8 _pad[56]; +}; +StaticAssert(sizeof(Cv) == 64); /* Padding validation */ +StaticAssert(alignof(Cv) == 64); /* Prevent false sharing */ + +//////////////////////////////// +//~ Counter types + +AlignedStruct(Counter, 64) +{ + Atomic64 v; + u8 _pad[56]; +}; +StaticAssert(sizeof(Counter) == 64); /* Padding validation */ +StaticAssert(alignof(Counter) == 64); /* Prevent false sharing */ + +//////////////////////////////// +//~ Mutex operations + +Lock LockSpinE(Mutex *m, i32 spin); +Lock LockSpinS(Mutex *m, i32 spin); + +Lock LockE(Mutex *m); +Lock LockS(Mutex *m); + +void Unlock(Lock *lock); + +//- Lock assertion +#if RtcIsEnabled +# define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1) +# define AssertLockedES(l, m) Assert((l)->mutex == (m)) +#else +# define AssertLockedE(l, m) LAX l +# define AssertLockedES(l, m) LAX l +#endif + +//////////////////////////////// +//~ Condition variable operations + +void WaitOnCv(Cv *cv, Lock *lock); +void WaitOnCvTime(Cv *cv, Lock *l, i64 timeout_ns); +void SignalCv(Cv *cv, i32 count); + +//////////////////////////////// +//~ Counter operations + +void AddCounter(Counter *counter, i64 x); +void WaitOnCounter(Counter *counter); diff --git a/src/base/base_string.c b/src/base/base_string.c index 94c0190f..f81bf5aa 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -63,12 +63,12 @@ String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill) u8 len = 0; if (n < 0) { - /* PushStruct sign */ + /* Push sign */ StringFromChar(arena, '-'); len = 1; n = -n; } - /* PushStruct unsigned number */ + /* Push unsigned number */ String uint_str = StringFromU64(arena, n, base, zfill); return (String) { diff --git a/src/base/win32/base_win32_job.c b/src/base/win32/base_win32_job.c index 2f265e59..43add503 100644 --- a/src/base/win32/base_win32_job.c +++ b/src/base/win32/base_win32_job.c @@ -1,5 +1,7 @@ W32_SharedCtx W32_shared_ctx = ZI; +/* FIXME: Enable logs, panic, shutdown */ + //////////////////////////////// //~ Win32 libs @@ -21,6 +23,19 @@ void StartupJobs(void) { W32_SharedCtx *g = &W32_shared_ctx; + /* Init timer */ + { + LARGE_INTEGER qpf; + QueryPerformanceFrequency(&qpf); + g->ns_per_qpc = 1000000000 / qpf.QuadPart; + } + { + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + g->timer_start_qpc = qpc.QuadPart; + } + + /* Init fibers */ g->num_fibers = 1; /* Fiber at index 0 always nil */ g->fiber_names_arena = AllocArena(Gibi(64)); @@ -47,6 +62,7 @@ void StartupJobs(void) /* Start job scheduler */ Atomic64FetchSet(&g->current_scheduler_cycle_period_ns.v, W32_DefaultSchedulerPeriodNs); W32_Thread *scheduler_thread = W32_AllocThread(W32_JobSchedulerEntryFunc, 0, Lit("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER); + LAX scheduler_thread; //- Start job workers /* TODO: Heuristic worker counts & affinities */ @@ -114,12 +130,12 @@ void StartupJobs(void) } } - P_OnExit(ShutdownJobs); + //P_OnExit(ShutdownJobs); } //////////////////////////////// //~ Shutdown - +#if 0 void ShutdownJobs(void) { /* Signal shutdown */ @@ -162,7 +178,7 @@ void ShutdownJobs(void) /* Find any dangling threads that haven't exited gracefully by now */ if (!Atomic32Fetch(&g->panicking)) { - P_Lock lock = P_LockS(&g->threads_mutex); + LockTicketMutex(&g->threads_tm); if (g->first_thread) { TempArena scratch = BeginScratchNoConflict(); @@ -176,29 +192,13 @@ void ShutdownJobs(void) ++num_dangling_threads; } threads_msg = StringFormat(scratch.arena, Lit("%F dangling thread(s):\n%F"), FmtUint(num_dangling_threads), FmtString(threads_msg)); - P_Panic(threads_msg); + //P_Panic(threads_msg); EndScratch(scratch); } - P_Unlock(&lock); + UnlockTicketMutex(&g->threads_tm); } } - -//////////////////////////////// -//~ Win32 ticket mutex - -void LockTicketMutex(W32_TicketMutex *tm) -{ - i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1); - while (Atomic64Fetch(&tm->serving.v) != ticket) - { - _mm_pause(); - } -} - -void UnlockTicketMutex(W32_TicketMutex *tm) -{ - Atomic64FetchAdd(&tm->serving.v, 1); -} +#endif //////////////////////////////// //~ Win32 thread @@ -219,7 +219,7 @@ DWORD WINAPI W32_Win32ThreadProc(LPVOID vt) SetThreadDescription(GetCurrentThread(), t->thread_name_wstr); } - P_LogInfoF("New thread \"%F\" created with ID %F", FmtString(StringFromCstrNoLimit(t->thread_name_cstr)), FmtUint(P_GetThreadId())); + //P_LogInfoF("New thread \"%F\" created with ID %F", FmtString(StringFromCstrNoLimit(t->thread_name_cstr)), FmtUint(ThreadId())); /* Enter thread entry point */ t->entry_point(t->thread_data); @@ -236,12 +236,12 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri TempArena scratch = BeginScratchNoConflict(); W32_SharedCtx *g = &W32_shared_ctx; Assert(entry_point != 0); - P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name)); + //P_LogInfoF("Creating thread \"%F\"", FmtString(thread_name)); /* Allocate thread object */ W32_Thread *t = 0; { - P_Lock lock = P_LockE(&g->threads_mutex); + LockTicketMutex(&g->threads_tm); if (g->first_free_thread) { t = g->first_free_thread; @@ -262,7 +262,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri g->first_thread = t; } g->last_thread = t; - P_Unlock(&lock); + UnlockTicketMutex(&g->threads_tm); } t->entry_point = entry_point; @@ -293,7 +293,7 @@ W32_Thread *W32_AllocThread(W32_ThreadFunc *entry_point, void *thread_data, Stri if (!t->handle) { - P_Panic(Lit("Failed to create thread")); + //P_Panic(Lit("Failed to create thread")); } EndScratch(scratch); @@ -319,7 +319,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds) success = 1; CloseHandle(handle); { - P_Lock lock = P_LockE(&g->threads_mutex); + LockTicketMutex(&g->threads_tm); { W32_Thread *prev = t->prev; W32_Thread *next = t->next; @@ -342,7 +342,7 @@ b32 W32_TryReleaseThread(W32_Thread *thread, f32 timeout_seconds) t->next = g->first_free_thread; g->first_free_thread = t; } - P_Unlock(&lock); + UnlockTicketMutex(&g->threads_tm); } } } @@ -710,30 +710,30 @@ W32_Fiber *W32_AllocFiber(W32_JobPool *pool) { if (pool != 0) { - LockTicketMutex(&pool->free_fibers_lock); + LockTicketMutex(&pool->free_fibers_tm); if (pool->first_free_fiber_id) { fiber_id = pool->first_free_fiber_id; fiber = &g->fibers[fiber_id]; pool->first_free_fiber_id = fiber->parent_id; } - UnlockTicketMutex(&pool->free_fibers_lock); + UnlockTicketMutex(&pool->free_fibers_tm); } if (!fiber_id) { - LockTicketMutex(&g->fibers_lock); + LockTicketMutex(&g->fibers_tm); { { fiber_id = g->num_fibers++; if (fiber_id >= MaxFibers) { - P_Panic(Lit("Max fibers reached")); + //P_Panic(Lit("Max fibers reached")); } fiber = &g->fibers[fiber_id]; new_name_cstr = PushStructs(g->fiber_names_arena, char, W32_FiberNameMaxSize); } } - UnlockTicketMutex(&g->fibers_lock); + UnlockTicketMutex(&g->fibers_tm); } } @@ -809,13 +809,13 @@ W32_Fiber *W32_AllocFiber(W32_JobPool *pool) //- Release fiber void W32_ReleaseFiber(W32_JobPool *pool, W32_Fiber *fiber) { - LockTicketMutex(&pool->free_fibers_lock); + LockTicketMutex(&pool->free_fibers_tm); { i16 fiber_id = fiber->id; fiber->parent_id = pool->first_free_fiber_id; pool->first_free_fiber_id = fiber_id; } - UnlockTicketMutex(&pool->free_fibers_lock); + UnlockTicketMutex(&pool->free_fibers_tm); } @@ -855,6 +855,7 @@ void W32_YieldFiber(W32_Fiber *fiber, W32_Fiber *parent_fiber) } //- Fiber entry + void W32_FiberEntryPoint(void *id_ptr) { i16 id = (i32)(i64)id_ptr; @@ -866,12 +867,10 @@ void W32_FiberEntryPoint(void *id_ptr) { W32_YieldParam *yield_param = fiber->yield_param; yield_param->kind = W32_YieldKind_None; - P_JobData data = ZI; - data.id = fiber->job_id; - data.sig = fiber->job_sig; { MemoryBarrier(); - fiber->job_func(data); + GenericJobFunc *job_func = fiber->job_func; + job_func(fiber->job_sig, fiber->job_id); MemoryBarrier(); } } @@ -881,7 +880,7 @@ void W32_FiberEntryPoint(void *id_ptr) Counter *job_counter = fiber->job_counter; if (job_counter) { - P_CounterAdd(job_counter, -1); + AddCounter(job_counter, -1); } /* Yield to worker */ fiber->yield_param->kind = W32_YieldKind_Done; @@ -959,7 +958,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) PriorityKind job_priority = 0; i16 job_fiber_id = 0; i32 job_id = 0; - P_JobFunc *job_func = 0; + GenericJobFunc *job_func = 0; void *job_sig = 0; Counter *job_counter = 0; { @@ -1064,7 +1063,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) { /* Invalid yield kind */ TempArena scratch = BeginScratchNoConflict(); - P_Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind))); + //P_Panic(StringFormat(scratch.arena, Lit("Invalid fiber yield kind \"%F\""), FmtSint(yield.kind))); EndScratch(scratch); } break; @@ -1133,11 +1132,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) } else { - LockTicketMutex(&g->wait_lists_arena_lock); + LockTicketMutex(&g->wait_lists_arena_tm); { wait_addr_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList); } - UnlockTicketMutex(&g->wait_lists_arena_lock); + UnlockTicketMutex(&g->wait_lists_arena_tm); } ZeroStruct(wait_addr_list); wait_addr_list->value = (u64)wait_addr; @@ -1187,11 +1186,11 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg) } else { - LockTicketMutex(&g->wait_lists_arena_lock); + LockTicketMutex(&g->wait_lists_arena_tm); { wait_time_list = PushStructNoZero(g->wait_lists_arena, W32_WaitList); } - UnlockTicketMutex(&g->wait_lists_arena_lock); + UnlockTicketMutex(&g->wait_lists_arena_tm); } ZeroStruct(wait_time_list); wait_time_list->value = wait_time; @@ -1291,7 +1290,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (!timer) { - P_Panic(Lit("Failed to create high resolution timer")); + //P_Panic(Lit("Failed to create high resolution timer")); } /* Create rolling buffer of scheduler cycles initialized to default value */ @@ -1319,7 +1318,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) } /* Calculate mean period */ - i64 now_ns = P_TimeNs(); + i64 now_ns = TimeNs(); i64 period_ns = last_cycle_ns == 0 ? W32_DefaultSchedulerPeriodNs : now_ns - last_cycle_ns; last_cycle_ns = now_ns; @@ -1348,9 +1347,9 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg) } //////////////////////////////// -//~ Wait / wake +//~ @hookdef Futex -void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns) +void FutexWait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns) { W32_Fiber *fiber = W32_FiberFromId(FiberId()); i16 parent_id = fiber->parent_id; @@ -1390,31 +1389,46 @@ void P_Wait(volatile void *addr, void *cmp, u32 size, i64 timeout_ns) } } -void P_Wake(void *addr, i32 count) +void FutexWake(void *addr, i32 count) { W32_WakeByAddress(addr, count); } //////////////////////////////// -//~ Fiber +//~ @hoodef Job -i16 FiberId(void) +GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params) { - return (i16)(i64)GetFiberData(); + GenericJobDesc *result = 0; + /* FIXME: Pool arenas */ + Arena *arena = AllocArena(Mebi(1)); + result = PushStruct(arena, GenericJobDesc); + result->arena = arena; + result->sig = PushBytes(arena, sig_size, sig_align); + result->func = func; + result->count = params.count; + result->pool = params.pool; + result->priority = params.priority; + result->counter = params.counter; + return result; } -//////////////////////////////// -//~ Job - -void P_Run(i32 count, P_JobFunc *func, void *sig, PoolKind pool_kind, PriorityKind priority, Counter *counter) +#if 1 +void RunJobEx(GenericJobDesc *desc) { __prof; struct W32_SharedCtx *g = &W32_shared_ctx; + i32 count = desc->count; + Counter *counter = desc->counter; + PoolKind pool_kind = desc->pool; + PriorityKind priority = desc->priority; + GenericJobFunc *func = desc->func; + void *sig = desc->sig; if (count > 0) { if (counter) { - P_CounterAdd(counter, count); + AddCounter(counter, count); } W32_Fiber *fiber = W32_FiberFromId(FiberId()); priority = ClampI32(priority, fiber->job_priority, PriorityKind_Count - 1); /* A job cannot create a job with a higher priority than itself */ @@ -1474,3 +1488,101 @@ void P_Run(i32 count, P_JobFunc *func, void *sig, PoolKind pool_kind, PriorityKi } } } +#else +void RunJob(i32 count, GenericJobFunc *func, void *sig, PoolKind pool_kind, PriorityKind priority, Counter *counter) +{ + __prof; + struct W32_SharedCtx *g = &W32_shared_ctx; + if (count > 0) + { + if (counter) + { + AddCounter(counter, count); + } + W32_Fiber *fiber = W32_FiberFromId(FiberId()); + priority = ClampI32(priority, fiber->job_priority, PriorityKind_Count - 1); /* A job cannot create a job with a higher priority than itself */ + if (pool_kind == PoolKind_Inherit) + { + pool_kind = fiber->job_pool; + } + W32_JobPool *pool = &g->job_pools[pool_kind]; + W32_JobQueue *queue = &pool->job_queues[priority]; + LockTicketMutex(&queue->lock); + { + W32_JobInfo *info = 0; + if (queue->first_free) + { + info = queue->first_free; + queue->first_free = info->next; + } + else + { + info = PushStructNoZero(queue->arena, W32_JobInfo); + } + ZeroStruct(info); + info->count = count; + info->func = func; + info->sig = sig; + info->counter = counter; + if (queue->last) + { + queue->last->next = info; + } + else + { + queue->first = info; + } + queue->last = info; + } + UnlockTicketMutex(&queue->lock); + + /* Wake workers */ + { + LockTicketMutex(&pool->workers_wake_tm); + { + Atomic64FetchAdd(&pool->num_jobs_in_queue.v, count); + if (count >= W32_WakeAllThreshold) + { + WakeByAddressAll(&pool->num_jobs_in_queue); + } + else + { + for (i32 i = 0; i < count; ++i) + { + WakeByAddressSingle(&pool->num_jobs_in_queue); + } + } + } + UnlockTicketMutex(&pool->workers_wake_tm); + } + } +} +#endif + +//////////////////////////////// +//~ @hookdef Helpers + +i64 TimeNs(void) +{ + struct W32_SharedCtx *g = &W32_shared_ctx; + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + i64 result = (qpc.QuadPart - g->timer_start_qpc) * g->ns_per_qpc; + return result; +} + +u32 GetLogicalProcessorCount(void) +{ + return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); +} + +u32 ThreadId(void) +{ + return GetCurrentThreadId(); +} + +i64 GetCurrentSchedulerPeriodNs(void) +{ + W32_SharedCtx *g = &W32_shared_ctx; + return Atomic64Fetch(&g->current_scheduler_cycle_period_ns.v); +} diff --git a/src/base/win32/base_win32_job.h b/src/base/win32/base_win32_job.h index 8f370588..dfd9b8c2 100644 --- a/src/base/win32/base_win32_job.h +++ b/src/base/win32/base_win32_job.h @@ -5,7 +5,6 @@ # define UNICODE # define WIN32_LEAN_AND_MEAN # include -#if 0 # include # include # include @@ -16,7 +15,6 @@ # include # include # include -#endif #pragma warning(pop) //////////////////////////////// @@ -123,7 +121,7 @@ AlignedStruct(W32_Fiber, 64) /* ---------------------------------------------------- */ /* -------------------- Cache line -------------------- */ /* ---------------------------------------------------- */ - void *job_func; /* 08 bytes */ + GenericJobFunc *job_func; /* 08 bytes */ /* ---------------------------------------------------- */ void *job_sig; /* 08 bytes */ /* ---------------------------------------------------- */ @@ -158,7 +156,7 @@ Struct(W32_JobInfo) i32 num_dispatched; i32 count; - void *func; + GenericJobFunc *func; void *sig; struct Counter *counter; @@ -217,6 +215,8 @@ AlignedStruct(W32_JobPool, 64) Struct(W32_SharedCtx) { + i64 timer_start_qpc; + i64 ns_per_qpc; Atomic32 shutdown; //- Worker thread pool diff --git a/src/font/font_core.c b/src/font/font_core.c index 6c647afe..dc7265bb 100644 --- a/src/font/font_core.c +++ b/src/font/font_core.c @@ -1,7 +1,7 @@ //////////////////////////////// //~ Load job -JobDef(F_LoadAssetJob, job) +JobDef(F_LoadJob, sig, _) { __prof; TempArena scratch = BeginScratchNoConflict(); @@ -25,13 +25,12 @@ JobDef(F_LoadAssetJob, job) 0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF }; - F_LoadJobSig *params = job.sig; - String path = STRING(params->path_len, (u8 *)params->path_cstr); - f32 point_size = params->point_size; - AC_Asset *asset = params->asset; + String path = sig->path; + f32 point_size = sig->point_size; + AC_Asset *asset = sig->asset; P_LogInfoF("Loading font \"%F\" (point size %F)", FmtString(path), FmtFloat((f64)point_size)); - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); Assert(StringEndsWith(path, Lit(".ttf"))); Assert(countof(font_codes) < F_LookupTableSize); @@ -87,7 +86,7 @@ JobDef(F_LoadAssetJob, job) font->lookup[codepoint] = result.cache_indices[i]; } - P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns))); + P_LogSuccessF("Loaded font \"%F\" (point size %F) in %F seconds", FmtString(path), FmtFloat((f64)point_size), FmtFloat(SecondsFromNs(TimeNs() - start_ns))); AC_MarkReady(asset, font); EndScratch(scratch); @@ -113,22 +112,12 @@ AC_Asset *F_LoadAsset(String path, f32 point_size, b32 wait) if (is_first_touch) { - /* Assemble task params */ - F_LoadJobSig *params = F_AllocJobSig(); - if (path.len > (sizeof(params->path_cstr) - 1)) - { - P_Panic(StringFormat(scratch.arena, - Lit("Font path \"%F\" too long!"), - FmtString(path))); - } - CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path); - params->path_len = path.len; - params->asset = asset; - params->point_size = point_size; - - /* PushStruct task */ AC_MarkLoading(asset); - P_Run(1, F_LoadAssetJob, params, PoolKind_Background, PriorityKind_Low, 0); + F_LoadJob_Desc *desc = PushJobDesc(F_LoadJob, .pool = PoolKind_Background, .priority = PriorityKind_Low); + desc->sig->asset = asset; + desc->sig->path = PushString(desc->arena, path); + desc->sig->point_size = point_size; + RunJobEx((GenericJobDesc *)desc); if (wait) { AC_WaitOnAssetReady(asset); diff --git a/src/font/font_core.h b/src/font/font_core.h index 7a7e2ce6..d9bd209d 100644 --- a/src/font/font_core.h +++ b/src/font/font_core.h @@ -27,7 +27,7 @@ Struct(F_Font) //////////////////////////////// //~ Font load job -JobDecl(F_LoadAssetJob, { AC_Asset *asset; f32 point_size; String path; }); +JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; String path; }); //////////////////////////////// //~ Font load operations diff --git a/src/gpu/gpu_dx12.c b/src/gpu/gpu_dx12.c index d08f21a4..fd0c2fb0 100644 --- a/src/gpu/gpu_dx12.c +++ b/src/gpu/gpu_dx12.c @@ -71,7 +71,7 @@ void GPU_Startup(void) P_OnExit(GPU_D12_Shutdown); /* Start evictor job */ - P_Run(1, GPU_D12_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->evictor_job_counter); + RunJob(1, GPU_D12_EvictorJob, PoolKind_Background, PriorityKind_Low, &g->evictor_job_counter, 0); } P_ExitFuncDef(GPU_D12_Shutdown) @@ -92,12 +92,12 @@ P_ExitFuncDef(GPU_D12_Shutdown) #endif { - P_Lock lock = P_LockE(&g->evictor_wake_mutex); + Lock lock = LockE(&g->evictor_wake_mutex); g->evictor_shutdown = 1; - P_SignalCv(&g->evictor_wake_cv, I32Max); - P_Unlock(&lock); + SignalCv(&g->evictor_wake_cv, I32Max); + Unlock(&lock); } - P_WaitOnCounter(&g->evictor_job_counter); + WaitOnCounter(&g->evictor_job_counter); } /* ========================== * @@ -322,13 +322,10 @@ void GPU_D12_InitObjects(void) {.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH, .dbg_name = Lit("Copy queue") }, {.type = D3D12_COMMAND_LIST_TYPE_COPY, .priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, .dbg_name = Lit("Background copy queue") } }; - GPU_D12_AllocCommandQueueJobSig sig = ZI; - sig.descs_in = params; - sig.cqs_out = g->command_queues; { Counter counter = ZI; - P_Run(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + RunJob(DX12_NUM_QUEUES, GPU_D12_AllocCommandQueueJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = params, .cqs_out = g->command_queues); + WaitOnCounter(&counter); } #if ProfilingIsEnabled { @@ -418,12 +415,9 @@ void GPU_InitPipelines(void) GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines); { __profn("Allocate pipelines"); - GPU_D12_AllocPipelineJobSig sig = ZI; - sig.descs_in = descs; - sig.pipelines_out = pipelines; Counter counter = ZI; - P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .descs_in = descs, .pipelines_out = pipelines); + WaitOnCounter(&counter); } for (u32 i = 0; i < num_pipelines; ++i) { @@ -502,11 +496,8 @@ void GPU_D12_InitNoise(void) /* Upload texture */ { Counter counter = ZI; - GPU_D12_UploadJobSig sig = ZI; - sig.resource = r; - sig.data = data.text; - P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Low, &counter, .resource = r, .data = data.text); + WaitOnCounter(&counter); } } } @@ -526,17 +517,16 @@ void GPU_D12_InitNoise(void) #if RESOURCE_RELOADING -JobDef(GPU_D12_CompileShaderJob, job) +JobDef(GPU_D12_CompileShaderJob, sig, id) { __prof; - GPU_D12_CompileShaderJobSig *sig = job.sig; Arena *arena = sig->arena; - GPU_D12_ShaderDesc *desc = &sig->descs[job.id]; - GPU_D12_CompiledShaderResult *result = &sig->results[job.id]; + GPU_D12_ShaderDesc *desc = &sig->descs[id]; + GPU_D12_CompiledShaderResult *result = &sig->results[id]; TempArena scratch = BeginScratch(arena); { - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); DXC_Result dxc_result = ZI; { __profn("Compile shader"); @@ -565,7 +555,7 @@ JobDef(GPU_D12_CompileShaderJob, job) result->success = dxc_result.success; result->dxc = dxc_result.dxc; result->errors = dxc_result.errors; - result->elapsed_ns = P_TimeNs() - start_ns; + result->elapsed_ns = TimeNs() - start_ns; } EndScratch(scratch); @@ -577,17 +567,16 @@ JobDef(GPU_D12_CompileShaderJob, job) * Pipeline * ========================== */ -JobDef(GPU_D12_AllocPipelineJob, job) +JobDef(GPU_D12_AllocPipelineJob, sig, id) { __prof; GPU_D12_SharedState *g = &GPU_D12_shared_state; - GPU_D12_AllocPipelineJobSig *sig = job.sig; - GPU_D12_PipelineDesc *desc = &sig->descs_in[job.id]; + GPU_D12_PipelineDesc *desc = &sig->descs_in[id]; GPU_D12_Pipeline **pipelines_out = sig->pipelines_out; GPU_D12_Pipeline *pipeline = 0; { - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); if (g->first_free_pipeline) { pipeline = g->first_free_pipeline; @@ -597,17 +586,17 @@ JobDef(GPU_D12_AllocPipelineJob, job) { pipeline = PushStructNoZero(g->pipelines_arena, GPU_D12_Pipeline); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(pipeline); - pipelines_out[job.id] = pipeline; + pipelines_out[id] = pipeline; pipeline->desc = *desc; pipeline->name = desc->name; pipeline->hash = HashFnv64(Fnv64Basis, pipeline->name); TempArena scratch = BeginScratchNoConflict(); { - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); String pipeline_name = pipeline->name; P_LogInfoF("Loading pipeline \"%F\"", FmtString(pipeline_name)); b32 success = 1; @@ -880,7 +869,7 @@ JobDef(GPU_D12_AllocPipelineJob, job) pipeline->pso = pso; pipeline->rootsig = rootsig; - pipeline->compilation_time_ns = P_TimeNs() - start_ns; + pipeline->compilation_time_ns = TimeNs() - start_ns; pipeline->success = success; pipeline->is_gfx = cs_dxc.len == 0; pipeline->error = error_str; @@ -913,12 +902,12 @@ void GPU_D12_ReleasePipelineNow(GPU_D12_Pipeline *pipeline) { ID3D12PipelineState_Release(pipeline->pso); } - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); { pipeline->next = g->first_free_pipeline; g->first_free_pipeline = pipeline; } - P_Unlock(&lock); + Unlock(&lock); } /* ========================== * @@ -931,13 +920,13 @@ GPU_D12_PipelineScope *GPU_D12_BeginPipelineScope(void) GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_PipelineScope *scope = 0; { - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); if (g->first_free_pipeline_scope) { scope = g->first_free_pipeline_scope; g->first_free_pipeline_scope = scope->next_free; } - P_Unlock(&lock); + Unlock(&lock); } Arena *arena = 0; if (scope) @@ -959,7 +948,7 @@ void GPU_D12_EndPipelineScope(GPU_D12_PipelineScope *scope) { __prof; GPU_D12_SharedState *g = &GPU_D12_shared_state; - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); { for (DictEntry *entry = scope->refs->first; entry; entry = entry->next) { @@ -972,7 +961,7 @@ void GPU_D12_EndPipelineScope(GPU_D12_PipelineScope *scope) scope->next_free = g->first_free_pipeline_scope; g->first_free_pipeline_scope = scope; } - P_Unlock(&lock); + Unlock(&lock); } Readonly GPU_D12_Pipeline GPU_D12_nil_pipeline = ZI; @@ -991,13 +980,13 @@ GPU_D12_Pipeline *GPU_D12_PipelineFromName(GPU_D12_PipelineScope *scope, String else { { - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); tmp = (GPU_D12_Pipeline *)DictValueFromHash(g->top_successful_pipelines, hash); if (tmp) { ++tmp->refcount; } - P_Unlock(&lock); + Unlock(&lock); } if (tmp) { @@ -1013,7 +1002,7 @@ void GPU_D12_RegisterPipeline(u64 num_pipelines, GPU_D12_Pipeline **pipelines) { __prof; GPU_D12_SharedState *g = &GPU_D12_shared_state; - P_Lock lock = P_LockE(&g->pipelines_mutex); + Lock lock = LockE(&g->pipelines_mutex); { for (u64 i = 0; i < num_pipelines; ++i) { @@ -1042,7 +1031,7 @@ void GPU_D12_RegisterPipeline(u64 num_pipelines, GPU_D12_Pipeline **pipelines) } } } - P_Unlock(&lock); + Unlock(&lock); } #if RESOURCE_RELOADING @@ -1085,40 +1074,42 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name) pipeline_name = split.count > 1 ? split.strings[split.count - 2] : pipeline_name; } { - GPU_D12_CompileShaderJobSig sig = ZI; - sig.arena = scratch.arena; + GPU_D12_CompileShaderJob_Desc *job_desc = PushJobDesc(GPU_D12_CompileShaderJob, .count = 0); + job_desc->sig->arena = scratch.arena; if (is_rs) { num_shaders = 2; shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders); shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders); - sig.descs = shader_descs; - sig.results = shader_results; - sig.descs[0].src = data; - sig.descs[0].friendly_name = friendly_name; - sig.descs[0].entry = Lit("vs"); - sig.descs[0].target = Lit("vs_6_6"); - sig.descs[1].src = data; - sig.descs[1].friendly_name = friendly_name; - sig.descs[1].entry = Lit("ps"); - sig.descs[1].target = Lit("ps_6_6"); + job_desc->sig->descs = shader_descs; + job_desc->sig->results = shader_results; + job_desc->sig->descs[0].src = data; + job_desc->sig->descs[0].friendly_name = friendly_name; + job_desc->sig->descs[0].entry = Lit("vs"); + job_desc->sig->descs[0].target = Lit("vs_6_6"); + job_desc->sig->descs[1].src = data; + job_desc->sig->descs[1].friendly_name = friendly_name; + job_desc->sig->descs[1].entry = Lit("ps"); + job_desc->sig->descs[1].target = Lit("ps_6_6"); } else if (is_cs) { num_shaders = 1; shader_descs = PushStructs(scratch.arena, GPU_D12_ShaderDesc, num_shaders); shader_results = PushStructs(scratch.arena, GPU_D12_CompiledShaderResult, num_shaders); - sig.descs = shader_descs; - sig.results = shader_results; - sig.descs[0].src = data; - sig.descs[0].friendly_name = friendly_name; - sig.descs[0].entry = Lit("cs"); - sig.descs[0].target = Lit("cs_6_6"); + job_desc->sig->descs = shader_descs; + job_desc->sig->results = shader_results; + job_desc->sig->descs[0].src = data; + job_desc->sig->descs[0].friendly_name = friendly_name; + job_desc->sig->descs[0].entry = Lit("cs"); + job_desc->sig->descs[0].target = Lit("cs_6_6"); } { Counter counter = ZI; - P_Run(num_shaders, GPU_D12_CompileShaderJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + job_desc->count = num_shaders; + job_desc->counter = &counter; + RunJobEx((GenericJobDesc *)job_desc); + WaitOnCounter(&counter); } } P_CloseFIle(file); @@ -1177,15 +1168,12 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name) __profn("Compile dirty pipelines"); GPU_D12_Pipeline **pipelines = PushStructs(scratch.arena, GPU_D12_Pipeline *, num_pipelines); { - GPU_D12_AllocPipelineJobSig sig = ZI; - sig.descs_in = pipeline_descs; - sig.pipelines_out = pipelines; Counter counter = ZI; - P_Run(num_pipelines, GPU_D12_AllocPipelineJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + RunJob(num_pipelines, GPU_D12_AllocPipelineJob, PoolKind_Inherit, PriorityKind_Low, &counter, .descs_in = pipeline_descs, .pipelines_out = pipelines); + WaitOnCounter(&counter); } { - P_Lock lock = P_LockS(&g->pipelines_mutex); + Lock lock = LockS(&g->pipelines_mutex); for (u32 i = 0; i < num_pipelines; ++i) { GPU_D12_Pipeline *pipeline = pipelines[i]; @@ -1216,7 +1204,7 @@ W_CallbackFuncDef(GPU_D12_WatchPipelineCallback, name) } } - P_Unlock(&lock); + Unlock(&lock); } GPU_D12_RegisterPipeline(num_pipelines, pipelines); } @@ -1237,7 +1225,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh) u32 index = 0; D3D12_CPU_DESCRIPTOR_HANDLE handle = ZI; { - P_Lock lock = P_LockE(&dh->mutex); + Lock lock = LockE(&dh->mutex); if (dh->first_free_descriptor) { d = dh->first_free_descriptor; @@ -1255,7 +1243,7 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh) index = dh->num_descriptors_reserved++; handle.ptr = dh->handle.ptr + (index * dh->descriptor_size); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(d); d->heap = dh; @@ -1267,12 +1255,12 @@ GPU_D12_Descriptor *GPU_D12_AllocDescriptor(GPU_D12_CpuDescriptorHeap *dh) void GPU_D12_ReleaseDescriptor(GPU_D12_Descriptor *descriptor) { GPU_D12_CpuDescriptorHeap *dh = descriptor->heap; - P_Lock lock = P_LockE(&dh->mutex); + Lock lock = LockE(&dh->mutex); { descriptor->next_free = dh->first_free_descriptor; dh->first_free_descriptor = descriptor; } - P_Unlock(&lock); + Unlock(&lock); } /* ========================== * @@ -1342,31 +1330,31 @@ void GPU_D12_ReleaseDataFenced(void *data, GPU_D12_FencedReleaseKind kind) for (u32 i = 0; i < countof(g->command_queues); ++i) { GPU_D12_CommandQueue *cq = g->command_queues[i]; - P_Lock lock = P_LockS(&cq->submit_fence_mutex); + Lock lock = LockS(&cq->submit_fence_mutex); { fr_targets[i] = cq->submit_fence_target; } - P_Unlock(&lock); + Unlock(&lock); } - /* PushStruct data to release queue */ + /* Push data to release queue */ { - P_Lock lock = P_LockE(&g->fenced_releases_mutex); + Lock lock = LockE(&g->fenced_releases_mutex); { *PushStruct(g->fenced_releases_arena, GPU_D12_FencedReleaseData) = fr; CopyBytes(g->fenced_release_targets, fr_targets, sizeof(fr_targets)); } - P_Unlock(&lock); + Unlock(&lock); } /* Wake evictor */ { - P_Lock lock = P_LockE(&g->evictor_wake_mutex); + Lock lock = LockE(&g->evictor_wake_mutex); { ++g->evictor_wake_gen; - P_SignalCv(&g->evictor_wake_cv, I32Max); + SignalCv(&g->evictor_wake_cv, I32Max); } - P_Unlock(&lock); + Unlock(&lock); } } @@ -1380,7 +1368,7 @@ GPU_D12_Resource *GPU_D12_AllocResource(D3D12_HEAP_PROPERTIES heap_props, D3D12_ GPU_D12_SharedState *g = &GPU_D12_shared_state; GPU_D12_Resource *r = 0; { - P_Lock lock = P_LockE(&g->resources_mutex); + Lock lock = LockE(&g->resources_mutex); if (g->first_free_resource) { r = g->first_free_resource; @@ -1390,7 +1378,7 @@ GPU_D12_Resource *GPU_D12_AllocResource(D3D12_HEAP_PROPERTIES heap_props, D3D12_ { r = PushStructNoZero(g->resources_arena, GPU_D12_Resource); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(r); @@ -1441,10 +1429,10 @@ void GPU_D12_ReleaseResourceNow(GPU_D12_Resource *t) ID3D12Resource_Release(t->resource); /* Add to free list */ - P_Lock lock = P_LockE(&g->resources_mutex); + Lock lock = LockE(&g->resources_mutex); t->next_free = g->first_free_resource; g->first_free_resource = t; - P_Unlock(&lock); + Unlock(&lock); } void GPU_ReleaseResourceFenced(GPU_Resource *resource) @@ -1515,12 +1503,11 @@ void GPU_D12_InsertBarrier(ID3D12GraphicsCommandList *cl, i32 num_descs, GPU_D12 GPU_D12_CommandListPool *GPU_D12_AllocCommandListPool(GPU_D12_CommandQueue *cq); -JobDef(GPU_D12_AllocCommandQueueJob, job) +JobDef(GPU_D12_AllocCommandQueueJob, sig, id) { __prof; GPU_D12_SharedState *g = &GPU_D12_shared_state; - GPU_D12_AllocCommandQueueJobSig *sig = job.sig; - GPU_D12_CommandQueueDesc *desc = &sig->descs_in[job.id]; + GPU_D12_CommandQueueDesc *desc = &sig->descs_in[id]; { GPU_D12_CommandQueue *cq = 0; { @@ -1548,7 +1535,7 @@ JobDef(GPU_D12_AllocCommandQueueJob, job) cq->cl_pool = GPU_D12_AllocCommandListPool(cq); - sig->cqs_out[job.id] = cq; + sig->cqs_out[id] = cq; } } @@ -1587,7 +1574,7 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool) struct ID3D12GraphicsCommandList *old_cl = 0; struct ID3D12CommandAllocator *old_ca = 0; { - P_Lock lock = P_LockE(&pool->mutex); + Lock lock = LockE(&pool->mutex); /* Find first command list ready for reuse */ for (GPU_D12_CommandList *tmp = pool->first_submitted_command_list; tmp; tmp = tmp->next_submitted) { @@ -1625,12 +1612,12 @@ GPU_D12_CommandList *GPU_D12_BeginCommandList(GPU_D12_CommandListPool *pool) { cl = PushStructNoZero(pool->arena, GPU_D12_CommandList); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(cl); cl->cq = cq; cl->pool = pool; - cl->global_record_lock = P_LockS(&g->global_command_list_record_mutex); + cl->global_record_lock = LockS(&g->global_command_list_record_mutex); HRESULT hr = 0; if (old_cl) @@ -1698,20 +1685,20 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl) u64 submit_fence_target = 0; { __profn("Execute"); - P_Lock submit_lock = P_LockS(&g->global_submit_mutex); - P_Lock fence_lock = P_LockE(&cq->submit_fence_mutex); + Lock submit_lock = LockS(&g->global_submit_mutex); + Lock fence_lock = LockE(&cq->submit_fence_mutex); { submit_fence_target = ++cq->submit_fence_target; ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target); } - P_Unlock(&fence_lock); - P_Unlock(&submit_lock); + Unlock(&fence_lock); + Unlock(&submit_lock); } /* Add descriptor heaps to submitted list */ { - P_Lock lock = P_LockE(&g->command_descriptor_heaps_mutex); + Lock lock = LockE(&g->command_descriptor_heaps_mutex); for (GPU_D12_CommandDescriptorHeap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list) { cdh->submitted_cq = cq; @@ -1726,12 +1713,12 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl) } g->last_submitted_command_descriptor_heap = cdh; } - P_Unlock(&lock); + Unlock(&lock); } /* Add command buffers to submitted list */ { - P_Lock lock = P_LockE(&g->command_buffers_mutex); + Lock lock = LockE(&g->command_buffers_mutex); for (GPU_D12_CommandBuffer *cb = cl->first_command_buffer; cb; cb = cb->next_in_command_list) { GPU_D12_CommandBufferGroup *group = cb->group; @@ -1747,14 +1734,14 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl) } group->last_submitted = cb; } - P_Unlock(&lock); + Unlock(&lock); } /* Add command list to pool submitted list */ - P_Unlock(&cl->global_record_lock); + Unlock(&cl->global_record_lock); cl->submitted_fence_target = submit_fence_target; { - P_Lock lock = P_LockE(&pool->mutex); + Lock lock = LockE(&pool->mutex); if (pool->last_submitted_command_list) { pool->last_submitted_command_list->next_submitted = cl; @@ -1764,7 +1751,7 @@ u64 GPU_D12_EndCommandList(GPU_D12_CommandList *cl) pool->first_submitted_command_list = cl; } pool->last_submitted_command_list = cl; - P_Unlock(&lock); + Unlock(&lock); } return submit_fence_target; @@ -1786,7 +1773,7 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c D3D12_CPU_DESCRIPTOR_HANDLE old_start_cpu_handle = ZI; D3D12_GPU_DESCRIPTOR_HANDLE old_start_gpu_handle = ZI; { - P_Lock lock = P_LockE(&g->command_descriptor_heaps_mutex); + Lock lock = LockE(&g->command_descriptor_heaps_mutex); /* Find first heap ready for reuse */ for (GPU_D12_CommandDescriptorHeap *tmp = g->first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted) { @@ -1828,7 +1815,7 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c /* No available heap available for reuse, allocate new */ cdh = PushStructNoZero(g->command_descriptor_heaps_arena, GPU_D12_CommandDescriptorHeap); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(cdh); @@ -1855,9 +1842,9 @@ GPU_D12_CommandDescriptorHeap *GPU_D12_PushDescriptorHeap(GPU_D12_CommandList *c /* Copy CPU heap */ { - P_Lock lock = P_LockS(&dh_cpu->mutex); + Lock lock = LockS(&dh_cpu->mutex); ID3D12Device_CopyDescriptorsSimple(g->device, dh_cpu->num_descriptors_reserved, cdh->start_cpu_handle, dh_cpu->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - P_Unlock(&lock); + Unlock(&lock); } /* Insert into command list */ @@ -1894,7 +1881,7 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d GPU_D12_CommandBuffer *cb = 0; GPU_D12_Resource *r = 0; { - P_Lock lock = P_LockE(&g->command_buffers_mutex); + Lock lock = LockE(&g->command_buffers_mutex); { u64 group_hash = GPU_D12_CommandBufferHashFromSize(size); @@ -1946,7 +1933,7 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d /* Allocate new */ cb = PushStructNoZero(g->command_buffers_arena, GPU_D12_CommandBuffer); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(cb); cb->group = cb_group; @@ -2017,10 +2004,9 @@ GPU_D12_CommandBuffer *GPU_D12__PushCommandBuffer(GPU_D12_CommandList *cl, u64 d * Wait job * ========================== */ -JobDef(GPU_D12_WaitOnFenceJob, job) +JobDef(GPU_D12_WaitOnFenceJob, sig, UNUSED id) { __prof; - GPU_D12_WaitOnFenceJobSig *sig = job.sig; ID3D12Fence *fence = sig->fence; u64 target = sig->target; if (ID3D12Fence_GetCompletedValue(fence) < target) @@ -2100,11 +2086,8 @@ GPU_Resource *GPU_AllocTexture(GPU_TextureFormat format, u32 flags, Vec2I32 size { /* TODO: Make wait optional */ Counter counter = ZI; - GPU_D12_UploadJobSig sig = ZI; - sig.resource = r; - sig.data = initial_data; - P_Run(1, GPU_D12_UploadJob, &sig, PoolKind_Inherit, PriorityKind_Inherit, &counter); - P_WaitOnCounter(&counter); + RunJob(1, GPU_D12_UploadJob, PoolKind_Inherit, PriorityKind_Inherit, &counter, .resource = r, .data = initial_data); + WaitOnCounter(&counter); } return (GPU_Resource *)r; @@ -2120,10 +2103,9 @@ Vec2I32 GPU_GetTextureSize(GPU_Resource *resource) * Upload * ========================== */ -JobDef(GPU_D12_UploadJob, job) +JobDef(GPU_D12_UploadJob, sig, UNUSED id) { GPU_D12_SharedState *g = &GPU_D12_shared_state; - GPU_D12_UploadJobSig *sig = job.sig; GPU_D12_Resource *r = sig->resource; void *data = sig->data; @@ -2216,12 +2198,9 @@ JobDef(GPU_D12_UploadJob, job) /* Wait on fence so we know it's safe to release upload heap */ if (ID3D12Fence_GetCompletedValue(cq->submit_fence) < fence_target) { - GPU_D12_WaitOnFenceJobSig wait_sig = ZI; - wait_sig.fence = cq->submit_fence; - wait_sig.target = fence_target; Counter counter = ZI; - P_Run(1, GPU_D12_WaitOnFenceJob, &wait_sig, PoolKind_Floating, PriorityKind_Low, &counter); - P_WaitOnCounter(&counter); + RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = fence_target); + WaitOnCounter(&counter); } /* Release upload heap now */ @@ -3040,7 +3019,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution) GPU_D12_Swapchain *swapchain = 0; { - P_Lock lock = P_LockE(&g->swapchains_mutex); + Lock lock = LockE(&g->swapchains_mutex); if (g->first_free_swapchain) { swapchain = g->first_free_swapchain; @@ -3050,7 +3029,7 @@ GPU_Swapchain *GPU_AllocSwapchain(P_Window *window, Vec2I32 resolution) { swapchain = PushStruct(g->swapchains_arena, GPU_D12_Swapchain); } - P_Unlock(&lock); + Unlock(&lock); } /* Create swapchain1 */ @@ -3132,9 +3111,9 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V GPU_D12_CommandQueue *cq = g->command_queues[DX12_QUEUE_DIRECT]; /* Lock direct queue submissions (in case any write to backbuffer) */ /* TODO: Less overkill approach - Only flush GPU_D12_BlitToSwapchain since we know it's the only operation targeting backbuffer */ - P_Lock lock = P_LockE(&cq->submit_fence_mutex); + Lock lock = LockE(&cq->submit_fence_mutex); //DEBUGBREAKABLE; - //P_Lock lock = P_LockE(&g->global_command_list_record_mutex); + //Lock lock = LockE(&g->global_command_list_record_mutex); { /* Flush direct queue */ //ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target); @@ -3161,7 +3140,7 @@ GPU_D12_SwapchainBuffer *GPU_D12_UpdateSwapchain(GPU_D12_Swapchain *swapchain, V P_Panic(Lit("Failed to resize swapchain")); } } - P_Unlock(&lock); + Unlock(&lock); GPU_D12_InitSwapchainResources(swapchain); @@ -3309,7 +3288,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu __profn("Mark queue frames"); /* Lock because frame marks shouldn't occur while command lists are recording */ - P_Lock lock = P_LockE(&g->global_command_list_record_mutex); + Lock lock = LockE(&g->global_command_list_record_mutex); for (u32 i = 0; i < countof(g->command_queues); ++i) { { @@ -3317,7 +3296,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu __prof_dx12_new_frame(cq->prof); } } - P_Unlock(&lock); + Unlock(&lock); } { __profn("Collect queues"); @@ -3334,7 +3313,7 @@ void GPU_PresentSwapchain(GPU_Swapchain *gp_swapchain, Vec2I32 backbuffer_resolu * Evictor job * ========================== */ -JobDef(GPU_D12_EvictorJob, _) +JobDef(GPU_D12_EvictorJob, UNUSED sig, UNUSED id) { GPU_D12_SharedState *g = &GPU_D12_shared_state; u64 completed_targets[DX12_NUM_QUEUES] = ZI; @@ -3352,13 +3331,13 @@ JobDef(GPU_D12_EvictorJob, _) GPU_D12_FencedReleaseData *fenced_releases = 0; { __profn("Copy queued releases"); - P_Lock lock = P_LockE(&g->fenced_releases_mutex); + Lock lock = LockE(&g->fenced_releases_mutex); num_fenced_releases = g->fenced_releases_arena->pos / sizeof(GPU_D12_FencedReleaseData); fenced_releases = PushStructsNoZero(scratch.arena, GPU_D12_FencedReleaseData, num_fenced_releases); CopyBytes(fenced_releases, ArenaBase(g->fenced_releases_arena), g->fenced_releases_arena->pos); ResetArena(g->fenced_releases_arena); CopyBytes(targets, g->fenced_release_targets, sizeof(targets)); - P_Unlock(&lock); + Unlock(&lock); } /* Wait until fences reach target */ @@ -3374,14 +3353,9 @@ JobDef(GPU_D12_EvictorJob, _) { __profn("Wait on fence"); { - GPU_D12_WaitOnFenceJobSig sig = ZI; - sig.fence = cq->submit_fence; - sig.target = targets[i]; - { - Counter counter = ZI; - P_Run(1, GPU_D12_WaitOnFenceJob, &sig, PoolKind_Floating, PriorityKind_Low, &counter); - P_WaitOnCounter(&counter); - } + Counter counter = ZI; + RunJob(1, GPU_D12_WaitOnFenceJob, PoolKind_Floating, PriorityKind_Inherit, &counter, .fence = cq->submit_fence, .target = targets[i]); + WaitOnCounter(&counter); } } } @@ -3415,15 +3389,15 @@ JobDef(GPU_D12_EvictorJob, _) } EndScratch(scratch); } - P_Lock lock = P_LockE(&g->evictor_wake_mutex); + Lock lock = LockE(&g->evictor_wake_mutex); { while (!g->evictor_shutdown && g->evictor_wake_gen == 0) { - P_WaitOnCv(&g->evictor_wake_cv, &lock); + WaitOnCv(&g->evictor_wake_cv, &lock); } shutdown = g->evictor_shutdown; g->evictor_wake_gen = 0; } - P_Unlock(&lock); + Unlock(&lock); } } diff --git a/src/gpu/gpu_dx12.h b/src/gpu/gpu_dx12.h index e5002003..100478ea 100644 --- a/src/gpu/gpu_dx12.h +++ b/src/gpu/gpu_dx12.h @@ -133,7 +133,7 @@ Struct(GPU_D12_CommandQueue) ID3D12CommandQueue *cq; Arena *arena; - P_Mutex submit_fence_mutex; + Mutex submit_fence_mutex; u64 submit_fence_target; ID3D12Fence *submit_fence; @@ -148,7 +148,7 @@ Struct(GPU_D12_CommandListPool) { GPU_D12_CommandQueue *cq; Arena *arena; - P_Mutex mutex; + Mutex mutex; struct GPU_D12_CommandList *first_submitted_command_list; struct GPU_D12_CommandList *last_submitted_command_list; }; @@ -197,7 +197,7 @@ Struct(GPU_D12_CommandList) GPU_D12_CommandListPool *pool; struct ID3D12CommandAllocator *ca; struct ID3D12GraphicsCommandList *cl; - P_Lock global_record_lock; + Lock global_record_lock; GPU_D12_Pipeline *cur_pipeline; @@ -232,7 +232,7 @@ Struct(GPU_D12_CpuDescriptorHeap) { enum D3D12_DESCRIPTOR_HEAP_TYPE type; Arena *arena; - P_Mutex mutex; + Mutex mutex; u32 descriptor_size; u32 num_descriptors_reserved; @@ -352,23 +352,23 @@ Struct(GPU_D12_SharedState) Atomic32 initialized; /* Descriptor heaps pool */ - P_Mutex command_descriptor_heaps_mutex; + Mutex command_descriptor_heaps_mutex; Arena *command_descriptor_heaps_arena; GPU_D12_CommandDescriptorHeap *first_submitted_command_descriptor_heap; GPU_D12_CommandDescriptorHeap *last_submitted_command_descriptor_heap; /* Command buffers pool */ - P_Mutex command_buffers_mutex; + Mutex command_buffers_mutex; Arena *command_buffers_arena; Dict *command_buffers_dict; /* Resources pool */ - P_Mutex resources_mutex; + Mutex resources_mutex; Arena *resources_arena; GPU_D12_Resource *first_free_resource; /* Swapchains pool */ - P_Mutex swapchains_mutex; + Mutex swapchains_mutex; Arena *swapchains_arena; GPU_D12_Swapchain *first_free_swapchain; @@ -376,7 +376,7 @@ Struct(GPU_D12_SharedState) TAR_Archive dxc_archive; /* Pipeline cache */ - P_Mutex pipelines_mutex; + Mutex pipelines_mutex; Arena *pipelines_arena; GPU_D12_Pipeline *first_free_pipeline; Dict *pipeline_descs; @@ -385,7 +385,7 @@ Struct(GPU_D12_SharedState) GPU_D12_PipelineScope *first_free_pipeline_scope; /* Fenced release queue */ - P_Mutex fenced_releases_mutex; + Mutex fenced_releases_mutex; Arena *fenced_releases_arena; u64 fenced_release_targets[DX12_NUM_QUEUES]; @@ -407,14 +407,14 @@ Struct(GPU_D12_SharedState) GPU_D12_CpuDescriptorHeap *rtv_heap; /* Command queues */ - P_Mutex global_command_list_record_mutex; - P_Mutex global_submit_mutex; + Mutex global_command_list_record_mutex; + Mutex global_submit_mutex; GPU_D12_CommandQueue *command_queues[DX12_NUM_QUEUES]; /* Evictor job */ Counter evictor_job_counter; - P_Cv evictor_wake_cv; - P_Mutex evictor_wake_mutex; + Cv evictor_wake_cv; + Mutex evictor_wake_mutex; i64 evictor_wake_gen; b32 evictor_shutdown; }; @@ -457,7 +457,7 @@ void GPU_D12_InitNoise(void); * Shader compilation * ========================== */ -JobDecl(GPU_D12_CompileShaderJob, { Arena *arena; GPU_D12_ShaderDesc *decs; GPU_D12_CompiledShaderResult results; }); +JobDecl(GPU_D12_CompileShaderJob, { Arena *arena; GPU_D12_ShaderDesc *descs; GPU_D12_CompiledShaderResult *results; }); /* ========================== * * Pipeline diff --git a/src/json/json_core.c b/src/json/json_core.c index 81ceebd4..3ae5bfad 100644 --- a/src/json/json_core.c +++ b/src/json/json_core.c @@ -873,7 +873,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p) if (is_new_parent) { - /* PushStruct self back to stack to re-check for closing brace later */ + /* Push self back to stack to re-check for closing brace later */ *PushStructNoZero(scratch.arena, JSON_Blob *) = json; ++stack_count; diff --git a/src/mixer/mixer_core.c b/src/mixer/mixer_core.c index 074bfe2f..26468130 100644 --- a/src/mixer/mixer_core.c +++ b/src/mixer/mixer_core.c @@ -53,10 +53,10 @@ MIX_Track *MIX_TrackFromHandle(MIX_Handle handle) } } -MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound) +MIX_Track *MIX_AllocTrackLocked(Lock *lock, SND_Sound *sound) { MIX_SharedState *g = &M_shared_state; - P_AssertLockedE(lock, &g->mutex); + AssertLockedE(lock, &g->mutex); LAX lock; MIX_Track *track = 0; @@ -100,10 +100,10 @@ MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound) return track; } -void MIX_ReleaseTrackLocked(P_Lock *lock, MIX_Track *track) +void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track) { MIX_SharedState *g = &M_shared_state; - P_AssertLockedE(lock, &g->mutex); + AssertLockedE(lock, &g->mutex); LAX lock; /* Remove from playing list */ @@ -155,12 +155,12 @@ MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc) MIX_SharedState *g = &M_shared_state; MIX_Track *track; { - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); { track = MIX_AllocTrackLocked(&lock, sound); track->desc = desc; } - P_Unlock(&lock); + Unlock(&lock); } return MIX_HandleFromTrack(track); } @@ -175,7 +175,7 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle) if (track) { /* TODO: Only lock mutex on track itself or something */ - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); { /* Confirm handle is still valid now that we're locked */ track = MIX_TrackFromHandle(handle); @@ -184,7 +184,7 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle) result = track->desc; } } - P_Unlock(&lock); + Unlock(&lock); } return result; @@ -198,7 +198,7 @@ void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc) if (track) { /* TODO: Only lock mutex on track itself or something */ - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); { /* Confirm handle is still valid now that we're locked */ track = MIX_TrackFromHandle(handle); @@ -207,19 +207,19 @@ void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc) track->desc = desc; } } - P_Unlock(&lock); + Unlock(&lock); } } void MIX_UpdateListener(Vec2 pos, Vec2 dir) { MIX_SharedState *g = &M_shared_state; - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); { g->listener_pos = pos; g->listener_dir = NormVec2(dir); } - P_Unlock(&lock); + Unlock(&lock); } //////////////////////////////// @@ -260,7 +260,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) MIX_MixData **mixes = 0; u64 mixes_count = 0; { - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); /* Read listener info */ listener_pos = g->listener_pos; @@ -276,7 +276,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) mixes[mixes_count++] = mix; } - P_Unlock(&lock); + Unlock(&lock); } //- Process mix data @@ -461,7 +461,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) //- Update track effect data { __profn("Update track effect data"); - P_Lock lock = P_LockE(&g->mutex); + Lock lock = LockE(&g->mutex); for (u64 i = 0; i < mixes_count; ++i) { MIX_MixData *mix = mixes[i]; @@ -475,7 +475,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) } } } - P_Unlock(&lock); + Unlock(&lock); } EndScratch(scratch); diff --git a/src/mixer/mixer_core.h b/src/mixer/mixer_core.h index 98a05823..1f480f8e 100644 --- a/src/mixer/mixer_core.h +++ b/src/mixer/mixer_core.h @@ -79,7 +79,7 @@ Struct(MIX_Track){ Struct(MIX_SharedState) { - P_Mutex mutex; + Mutex mutex; /* Listener */ Vec2 listener_pos; @@ -106,8 +106,8 @@ MIX_StartupReceipt MIX_Startup(void); MIX_Handle MIX_HandleFromTrack(MIX_Track *track); MIX_Track *MIX_TrackFromHandle(MIX_Handle handle); -MIX_Track *MIX_AllocTrackLocked(P_Lock *lock, SND_Sound *sound); -void MIX_ReleaseTrackLocked(P_Lock *lock, MIX_Track *track); +MIX_Track *MIX_AllocTrackLocked(Lock *lock, SND_Sound *sound); +void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track); //////////////////////////////// //~ Mixer state operations diff --git a/src/mp3/mp3_mmf.c b/src/mp3/mp3_mmf.c index f35dfc91..ca2ddd2a 100644 --- a/src/mp3/mp3_mmf.c +++ b/src/mp3/mp3_mmf.c @@ -11,6 +11,7 @@ # include # include # include +# include #pragma warning(pop) #pragma comment(lib, "mfplat") @@ -121,7 +122,8 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF IMFSourceReader_Release(reader); IMFByteStream_Close(byte_stream); - IStream_Release(i_stream); + /* FIXME: Enable this */ + //IStream_Release(i_stream); MFShutdown(); return result; diff --git a/src/net/net_core.c b/src/net/net_core.c index 7fcb4329..a57d5764 100644 --- a/src/net/net_core.c +++ b/src/net/net_core.c @@ -542,7 +542,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host) TempArena scratch = BeginScratch(arena); N_EventList events = ZI; - i64 now_ns = P_TimeNs(); + i64 now_ns = TimeNs(); { __profn("Read packets"); diff --git a/src/net/net_core.h b/src/net/net_core.h index 6e0273eb..434e73d4 100644 --- a/src/net/net_core.h +++ b/src/net/net_core.h @@ -246,7 +246,7 @@ Struct(N_Host) u64 num_msg_assembler_lookup_bins; /* Double buffer for incoming data */ - P_Mutex rcv_buffer_write_mutex; + Mutex rcv_buffer_write_mutex; N_RcvBuffer *rcv_buffer_read; N_RcvBuffer *rcv_buffer_write; diff --git a/src/platform/platform.c b/src/platform/platform.c index cad458c5..096ed58d 100644 --- a/src/platform/platform.c +++ b/src/platform/platform.c @@ -1,6 +1,5 @@ #include "platform.h" -#include "platform_snc.c" #include "platform_log.c" #if PlatformIsWindows diff --git a/src/platform/platform.h b/src/platform/platform.h index 053f2d51..57722ec8 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -3,7 +3,6 @@ #include "../base/base.h" -#include "platform_snc.h" #include "platform_core.h" #include "platform_log.h" diff --git a/src/platform/platform_core.h b/src/platform/platform_core.h index 60efb84c..1b7c8a01 100644 --- a/src/platform/platform_core.h +++ b/src/platform/platform_core.h @@ -311,7 +311,6 @@ typedef P_ExitFuncDef(P_ExitFunc); //~ @hookdecl Time helper operations P_DateTime P_LocalTime(void); -i64 P_TimeNs(void); //////////////////////////////// //~ @hookdecl File system operations @@ -403,9 +402,6 @@ void P_WriteSock(P_Sock *sock, P_Address address, String data); void P_MessageBox(P_MessageBoxKind kind, String message); void P_SetClipboardText(String str); String P_GetClipboardText(Arena *arena); -u32 P_GetLogicalProcessorCount(void); -u32 P_GetThreadId(void); -i64 P_GetCurrentSchedulerPeriodNs(void); //////////////////////////////// //~ @hookdecl Sleep diff --git a/src/platform/platform_log.c b/src/platform/platform_log.c index d6ed1cde..fe349b70 100644 --- a/src/platform/platform_log.c +++ b/src/platform/platform_log.c @@ -32,7 +32,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level) { P_SharedLogState *ctx = &P_shared_log_state; if (!Atomic32Fetch(&ctx->initialized)) { return; } - P_Lock lock = P_LockE(&ctx->callbacks_mutex); + Lock lock = LockE(&ctx->callbacks_mutex); { LogEventCallback *callback = PushStruct(ctx->callbacks_arena, LogEventCallback); callback->func = func; @@ -47,7 +47,7 @@ void P_RegisterLogCallback(P_LogEventCallbackFunc *func, i32 level) } ctx->last_callback = callback; } - P_Unlock(&lock); + Unlock(&lock); } //////////////////////////////// @@ -149,12 +149,12 @@ void P_Log_(i32 level, String msg) } - u32 tid = P_GetThreadId(); + u32 tid = ThreadId(); //- Format message P_DateTime datetime = P_LocalTime(); - i64 time_ns = P_TimeNs(); + i64 time_ns = TimeNs(); String shorthand = settings.shorthand; #if P_IncludeLogSourceLocation @@ -217,7 +217,7 @@ void P_Log_(i32 level, String msg) event.line = line; #endif { - P_Lock lock = P_LockS(&ctx->callbacks_mutex); + Lock lock = LockS(&ctx->callbacks_mutex); for (LogEventCallback *callback = ctx->first_callback; callback; callback = callback->next) { if (level <= callback->level) @@ -226,7 +226,7 @@ void P_Log_(i32 level, String msg) callback->func(event); } } - P_Unlock(&lock); + Unlock(&lock); } EndScratch(scratch); diff --git a/src/platform/platform_log.h b/src/platform/platform_log.h index 3200acf9..51fabc32 100644 --- a/src/platform/platform_log.h +++ b/src/platform/platform_log.h @@ -63,7 +63,7 @@ Struct(P_SharedLogState) { Atomic32 initialized; - P_Mutex callbacks_mutex; + Mutex callbacks_mutex; Arena *callbacks_arena; LogEventCallback *first_callback; LogEventCallback *last_callback; diff --git a/src/platform/platform_snc.h b/src/platform/platform_snc.h deleted file mode 100644 index 49bd1c3a..00000000 --- a/src/platform/platform_snc.h +++ /dev/null @@ -1,83 +0,0 @@ -//////////////////////////////// -//~ Mutex types - -#define P_DefaultMutexSpin 4000 - -AlignedStruct(P_Mutex, 64) -{ - /* Bit 31 = Exclusive lock is held - * Bit 30 = Exclusive lock is pending - * Bit 0-30 = Shared locks count - */ - Atomic32 v; - -#if RtcIsEnabled - Atomic32 exclusive_fiber_id; - u8 _pad[56]; -#else - u8 _pad[60]; -#endif -}; -StaticAssert(sizeof(P_Mutex) == 64); /* Padding validation */ -StaticAssert(alignof(P_Mutex) == 64); /* Prevent false sharing */ - -Struct(P_Lock) -{ - P_Mutex *mutex; - b32 exclusive; -}; - -//////////////////////////////// -//~ Condition variable types - -AlignedStruct(P_Cv, 64) -{ - Atomic64 wake_gen; - u8 _pad[56]; -}; -StaticAssert(sizeof(P_Cv) == 64); /* Padding validation */ -StaticAssert(alignof(P_Cv) == 64); /* Prevent false sharing */ - -//////////////////////////////// -//~ Counter types - -AlignedStruct(Counter, 64) -{ - Atomic64 v; - u8 _pad[56]; -}; -StaticAssert(sizeof(Counter) == 64); /* Padding validation */ -StaticAssert(alignof(Counter) == 64); /* Prevent false sharing */ - -//////////////////////////////// -//~ Mutex operations - -P_Lock P_LockSpinE(P_Mutex *m, i32 spin); -P_Lock P_LockSpinS(P_Mutex *m, i32 spin); - -P_Lock P_LockE(P_Mutex *m); -P_Lock P_LockS(P_Mutex *m); - -void P_Unlock(P_Lock *lock); - -//- Lock assertion -#if RtcIsEnabled -# define P_AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1) -# define P_AssertLockedES(l, m) Assert((l)->mutex == (m)) -#else -# define P_AssertLockedE(l, m) LAX l -# define P_AssertLockedES(l, m) LAX l -#endif - -//////////////////////////////// -//~ Condition variable operations - -void P_WaitOnCv(P_Cv *cv, P_Lock *lock); -void P_WaitOnCvTime(P_Cv *cv, P_Lock *l, i64 timeout_ns); -void P_SignalCv(P_Cv *cv, i32 count); - -//////////////////////////////// -//~ Counter operations - -void P_CounterAdd(Counter *counter, i64 x); -void P_WaitOnCounter(Counter *counter); diff --git a/src/platform/platform_win32.c b/src/platform/platform_win32.c index 75b17eec..f5625120 100644 --- a/src/platform/platform_win32.c +++ b/src/platform/platform_win32.c @@ -72,7 +72,7 @@ P_W32_Window *P_W32_AllocWindow(void) P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_Window *window = 0; { - P_Lock lock = P_LockE(&g->windows_mutex); + Lock lock = LockE(&g->windows_mutex); if (g->first_free_window) { window = g->first_free_window; @@ -82,7 +82,7 @@ P_W32_Window *P_W32_AllocWindow(void) { window = PushStructNoZero(g->windows_arena, P_W32_Window); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(window); @@ -93,9 +93,9 @@ P_W32_Window *P_W32_AllocWindow(void) /* NOTE: This thread must finish building for the window to actually be * created and receive a HWND, because on Windows a the event proc must run on * the same thread that created the window. */ - P_CounterAdd(&window->ready_fence, 1); - window->window_thread = P_W32_AllocThread(&W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW); - P_WaitOnCounter(&window->ready_fence); + AddCounter(&window->ready_fence, 1); + window->window_thread = W32_AllocThread(&P_W32_WindowThreadEntryFunc, window, Lit("Window thread"), PROF_THREAD_GROUP_WINDOW); + WaitOnCounter(&window->ready_fence); return window; } @@ -106,14 +106,14 @@ void P_W32_ReleaseWindow(P_W32_Window *window) Atomic32FetchSet(&window->shutdown, 1); P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_WakeWindow(window); - P_W32_WaitReleaseThread(window->window_thread); + W32_WaitReleaseThread(window->window_thread); - P_Lock lock = P_LockE(&g->windows_mutex); + Lock lock = LockE(&g->windows_mutex); { window->next_free = g->first_free_window; g->first_free_window = window; } - P_Unlock(&lock); + Unlock(&lock); } HWND P_W32_InitWindow(P_W32_Window *window) @@ -302,7 +302,7 @@ void P_W32_UpdateWindowFromSettings(P_W32_Window *window, P_WindowSettings *sett //////////////////////////////// //~ Win32 window thread -W32_ThreadDef(W32_WindowThreadEntryFunc, arg) +W32_ThreadDef(P_W32_WindowThreadEntryFunc, arg) { P_W32_Window *window = (P_W32_Window *)arg; @@ -310,7 +310,7 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg) window->hwnd = P_W32_InitWindow(window); P_W32_UpdateWindowFromSystem(window); BringWindowToTop(window->hwnd); - P_CounterAdd(&window->ready_fence, -1); + AddCounter(&window->ready_fence, -1); while (!Atomic32Fetch(&window->shutdown)) { @@ -335,11 +335,11 @@ W32_ThreadDef(W32_WindowThreadEntryFunc, arg) void P_W32_ProcessWindowEvent(P_W32_Window *window, P_WindowEvent event) { __prof; - P_Lock lock = P_LockE(&window->event_arena_swp_mutex); + Lock lock = LockE(&window->event_arena_swp_mutex); { *PushStruct(window->event_arenas[window->current_event_arena_index], P_WindowEvent) = event; } - P_Unlock(&lock); + Unlock(&lock); } void P_W32_WakeWindow(P_W32_Window *window) @@ -785,15 +785,6 @@ P_DateTime P_LocalTime(void) return P_W32_DateTimeFromWin32SystemTime(lt); } -i64 P_TimeNs(void) -{ - struct P_W32_SharedCtx *g = &P_W32_shared_ctx; - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - i64 result = (qpc.QuadPart - g->timer_start_qpc) * g->ns_per_qpc; - return result; -} - //////////////////////////////// //~ @hookdef File system hooks @@ -1166,7 +1157,7 @@ P_Watch *P_AllocWatch(String dir_path) P_W32_Watch *w32_watch = 0; { - P_Lock lock = P_LockE(&g->watches_mutex); + Lock lock = LockE(&g->watches_mutex); { if (g->watches_first_free) { @@ -1178,7 +1169,7 @@ P_Watch *P_AllocWatch(String dir_path) w32_watch = PushStructNoZero(g->watches_arena, P_W32_Watch); } } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(w32_watch); @@ -1206,12 +1197,12 @@ void P_ReleaseWatch(P_Watch *dw) CloseHandle(w32_watch->dir_handle); CloseHandle(w32_watch->wake_handle); - P_Lock lock = P_LockE(&g->watches_mutex); + Lock lock = LockE(&g->watches_mutex); { w32_watch->next_free = g->watches_first_free; g->watches_first_free = w32_watch; } - P_Unlock(&lock); + Unlock(&lock); } P_WatchInfoList P_ReadWatchWait(Arena *arena, P_Watch *dw) @@ -1369,10 +1360,10 @@ P_WindowEventArray P_PopWindowEvents(Arena *arena, P_Window *p_window) i32 event_arena_index = 0; { /* Swap event buffers */ - P_Lock lock = P_LockE(&window->event_arena_swp_mutex); + Lock lock = LockE(&window->event_arena_swp_mutex); event_arena_index = window->current_event_arena_index; window->current_event_arena_index = 1 - window->current_event_arena_index; - P_Unlock(&lock); + Unlock(&lock); } Arena *events_arena = window->event_arenas[event_arena_index]; P_WindowEventArray events = ZI; @@ -1388,11 +1379,11 @@ void P_UpdateWindowSettings(P_Window *p_window, P_WindowSettings *settings) { __prof; P_W32_Window *window = (P_W32_Window *)p_window; - P_Lock lock = P_LockE(&window->settings_mutex); + Lock lock = LockE(&window->settings_mutex); { P_W32_UpdateWindowFromSettings(window, settings); } - P_Unlock(&lock); + Unlock(&lock); } /* FIXME: Lock settings mutex for these functions */ @@ -1407,7 +1398,7 @@ void P_ShowWindow(P_Window *p_window) { P_W32_Window *window = (P_W32_Window *)p_window; HWND hwnd = window->hwnd; - P_Lock lock = P_LockE(&window->settings_mutex); + Lock lock = LockE(&window->settings_mutex); { i32 show_cmd = SW_NORMAL; P_WindowSettings *settings = &window->settings; @@ -1423,7 +1414,7 @@ void P_ShowWindow(P_Window *p_window) ShowWindow(hwnd, show_cmd); BringWindowToTop(hwnd); } - P_Unlock(&lock); + Unlock(&lock); } void P_SetWindowCursorPos(P_Window *p_window, Vec2 pos) @@ -1699,7 +1690,7 @@ P_Sock *P_AllocSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_Sock *ws = 0; { - P_Lock lock = P_LockE(&g->socks_mutex); + Lock lock = LockE(&g->socks_mutex); if (g->first_free_sock) { ws = g->first_free_sock; @@ -1709,7 +1700,7 @@ P_Sock *P_AllocSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) { ws = PushStructNoZero(g->socks_arena, P_W32_Sock); } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(ws); @@ -1734,12 +1725,12 @@ void P_ReleaseSock(P_Sock *sock) P_W32_SharedCtx *g = &P_W32_shared_ctx; P_W32_Sock *ws = (P_W32_Sock *)sock; closesocket(ws->sock); - P_Lock lock = P_LockE(&g->socks_mutex); + Lock lock = LockE(&g->socks_mutex); { ws->next_free = g->first_free_sock; g->first_free_sock = ws; } - P_Unlock(&lock); + Unlock(&lock); } P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock) @@ -1885,22 +1876,6 @@ String P_GetClipboardText(Arena *arena) return result; } -u32 P_GetLogicalProcessorCount(void) -{ - return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); -} - -u32 P_GetThreadId(void) -{ - return GetCurrentThreadId(); -} - -i64 P_GetCurrentSchedulerPeriodNs(void) -{ - P_W32_SharedCtx *g = &P_W32_shared_ctx; - return Atomic64Fetch(&g->current_scheduler_cycle_period_ns.v); -} - //////////////////////////////// //~ @hookdef Sleep hooks @@ -1908,19 +1883,19 @@ void P_SleepPrecise(i64 sleep_time_ns) { __prof; - i64 big_sleep = P_GetCurrentSchedulerPeriodNs(); + i64 big_sleep = GetCurrentSchedulerPeriodNs(); i64 tolerance = (f64)big_sleep * 0.5; //i64 tolerance = 1000000000; - i64 now_ns = P_TimeNs(); + i64 now_ns = TimeNs(); i64 target_ns = now_ns + sleep_time_ns; /* Sleep */ while (now_ns < target_ns - big_sleep - tolerance) { __profn("Sleep part"); - P_Wait(0, 0, 0, big_sleep); - now_ns = P_TimeNs(); + FutexWait(0, 0, 0, big_sleep); + now_ns = TimeNs(); } /* Spin */ @@ -1929,7 +1904,7 @@ void P_SleepPrecise(i64 sleep_time_ns) while (now_ns < target_ns) { _mm_pause(); - now_ns = P_TimeNs(); + now_ns = TimeNs(); } } } @@ -1938,7 +1913,7 @@ void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns) { if (last_frame_time_ns != 0 && target_dt_ns > 0) { - i64 now_ns = P_TimeNs(); + i64 now_ns = TimeNs(); i64 last_frame_dt_ns = now_ns - last_frame_time_ns; i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns; if (sleep_time_ns > 0) @@ -2073,7 +2048,7 @@ void P_W32_InitBtnTable(void) g->vk_btn_table[VK_OEM_1] = P_Btn_Semicolon; } -JobDef(P_W32_AppStartupJob, UNUSED job) +JobDef(P_W32_AppStartupJob, UNUSED sig, UNUSED id) { P_W32_SharedCtx *g = &P_W32_shared_ctx; TempArena scratch = BeginScratchNoConflict(); @@ -2085,7 +2060,7 @@ JobDef(P_W32_AppStartupJob, UNUSED job) EndScratch(scratch); } -JobDef(P_W32_AppShutdownJob, _) +JobDef(P_W32_AppShutdownJob, UNUSED sig, UNUSED id) { __prof; P_W32_SharedCtx *g = &P_W32_shared_ctx; @@ -2188,18 +2163,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, g->exit_begin_event = CreateEventW(0, 1, 0, 0); g->exit_end_event = CreateEventW(0, 1, 0, 0); - /* Init timer */ - { - LARGE_INTEGER qpf; - QueryPerformanceFrequency(&qpf); - g->ns_per_qpc = 1000000000 / qpf.QuadPart; - } - { - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - g->timer_start_qpc = qpc.QuadPart; - } - /* Convert main thread to fiber */ W32_AllocFiber(0); @@ -2253,9 +2216,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, LAX success; } - /* Init threads pool */ - g->threads_arena = AllocArena(Gibi(64)); - /* Init watches pool */ g->watches_arena = AllocArena(Gibi(64)); @@ -2271,7 +2231,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Run app start job */ if (!Atomic32Fetch(&g->panicking)) { - P_Run(1, P_W32_AppStartupJob, 0, PoolKind_Floating, PriorityKind_High, 0); + RunJob(1, P_W32_AppStartupJob, 0, PoolKind_Floating, PriorityKind_High, 0); } /* Wait for startup end or panic */ @@ -2299,7 +2259,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Run exit callbacks job */ if (!Atomic32Fetch(&g->panicking)) { - P_Run(1, P_W32_AppShutdownJob, 0, PoolKind_Floating, PriorityKind_High, 0); + RunJob(1, P_W32_AppShutdownJob, 0, PoolKind_Floating, PriorityKind_High, 0); } /* Wait for exit end or panic */ diff --git a/src/platform/platform_win32.h b/src/platform/platform_win32.h index e734b57a..3068110b 100644 --- a/src/platform/platform_win32.h +++ b/src/platform/platform_win32.h @@ -39,7 +39,7 @@ Struct(P_W32_Window) u16 utf16_high_surrogate_last_input; - P_Mutex settings_mutex; + Mutex settings_mutex; P_WindowSettings settings; i32 monitor_width; @@ -57,7 +57,7 @@ Struct(P_W32_Window) Atomic32 topmost_toggles; b32 is_topmost; - P_Mutex event_arena_swp_mutex; + Mutex event_arena_swp_mutex; i32 current_event_arena_index; Arena *event_arenas[2]; @@ -113,8 +113,6 @@ Struct(P_W32_Sock) Struct(P_W32_SharedCtx) { SYSTEM_INFO info; - i64 timer_start_qpc; - i64 ns_per_qpc; u32 main_thread_id; Atomic32 shutdown; @@ -132,20 +130,20 @@ Struct(P_W32_SharedCtx) P_Btn vk_btn_table[256]; //- Watches pool - P_Mutex watches_mutex; + Mutex watches_mutex; Arena *watches_arena; P_W32_Watch *watches_first_free; //- Windows pool WNDCLASSEXW window_class; - P_Mutex windows_mutex; + Mutex windows_mutex; Arena *windows_arena; P_W32_Window *first_free_window; //- Socket pool WSADATA wsa_data; Arena *socks_arena; - P_Mutex socks_mutex; + Mutex socks_mutex; P_W32_Sock *first_free_sock; //- Exit funcs diff --git a/src/playback/playback_win32.c b/src/playback/playback_win32.c index 5581be39..97cdfd3e 100644 --- a/src/playback/playback_win32.c +++ b/src/playback/playback_win32.c @@ -16,7 +16,7 @@ PB_StartupReceipt PB_Startup(MIX_StartupReceipt *mixer_sr) LAX mixer_sr; PB_WSP_InitializeWasapi(); /* Start playback job */ - P_Run(1, PB_WSP_PlaybackJob, 0, PoolKind_Audio, PriorityKind_High, &g->PB_WSP_PlaybackJob_counter); + RunJob(1, PB_WSP_PlaybackJob, 0, PoolKind_Audio, PriorityKind_High, &g->PB_WSP_PlaybackJob_counter); P_OnExit(&PB_WSP_Shutdown); return (PB_StartupReceipt) { 0 }; @@ -27,7 +27,7 @@ P_ExitFuncDef(PB_WSP_Shutdown) __prof; PB_WSP_SharedState *g = &PB_WSP_shared_state; Atomic32FetchSet(&g->shutdown, 1); - P_WaitOnCounter(&g->PB_WSP_PlaybackJob_counter); + WaitOnCounter(&g->PB_WSP_PlaybackJob_counter); } void PB_WSP_InitializeWasapi(void) @@ -184,7 +184,7 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src) //////////////////////////////// //~ Playback job -JobDef(PB_WSP_PlaybackJob, _) +JobDef(PB_WSP_PlaybackJob, UNUSED sig, UNUSED id) { __prof; PB_WSP_SharedState *g = &PB_WSP_shared_state; diff --git a/src/pp/pp_core.c b/src/pp/pp_core.c index 1cb33ef3..b9eabc31 100644 --- a/src/pp/pp_core.c +++ b/src/pp/pp_core.c @@ -11,11 +11,9 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr, String connect_address_str) { __prof; - LAX font_sr; LAX sprite_sr; LAX draw_sr; LAX asset_cache_sr; - LAX sound_sr; LAX mixer_sr; LAX sim_sr; SharedUserState *g = &shared_user_state; @@ -23,7 +21,7 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr, SetGstat(GSTAT_DEBUG_STEPS, U64Max); g->arena = AllocArena(Gibi(64)); - g->real_time_ns = P_TimeNs(); + g->real_time_ns = TimeNs(); /* TODO: Remove this */ g->connect_address_str = PushString(g->arena, connect_address_str); @@ -55,8 +53,8 @@ UserStartupReceipt StartupUser(S_StartupReceipt *sprite_sr, P_ShowWindow(g->window); /* Start jobs */ - P_Run(1, UpdateUserJob, 0, PoolKind_User, PriorityKind_High, &g->shutdown_job_counters); - P_Run(1, SimJob, 0, PoolKind_Sim, PriorityKind_High, &g->shutdown_job_counters); + RunJob(1, UpdateUserJob, 0, PoolKind_User, PriorityKind_High, &g->shutdown_job_counters); + RunJob(1, SimJob, 0, PoolKind_Sim, PriorityKind_High, &g->shutdown_job_counters); P_OnExit(&ShutdownUser); return (UserStartupReceipt) { 0 }; @@ -70,7 +68,7 @@ P_ExitFuncDef(ShutdownUser) __prof; SharedUserState *g = &shared_user_state; Atomic32FetchSet(&g->shutdown, 1); - P_WaitOnCounter(&g->shutdown_job_counters); + WaitOnCounter(&g->shutdown_job_counters); P_ReleaseWindow(g->window); } @@ -234,7 +232,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log) { __prof; SharedUserState *g = &shared_user_state; - P_Lock lock = P_LockE(&g->console_logs_mutex); + Lock lock = LockE(&g->console_logs_mutex); { ConsoleLog *clog = PushStruct(g->console_logs_arena, ConsoleLog); clog->level = log.level; @@ -257,7 +255,7 @@ P_LogEventCallbackFuncDef(ConsoleLogCallback, log) } g->last_console_log = clog; } - P_Unlock(&lock); + Unlock(&lock); } //- Draw console @@ -298,11 +296,11 @@ void DrawDebugConsole(i32 level, b32 minimized) } g->console_logs_height = 0; - i64 now_ns = P_TimeNs(); + i64 now_ns = TimeNs(); F_Font *font = F_LoadFontAsync(Lit("font/fixedsys.ttf"), 12.0f); if (font) { - P_Lock lock = P_LockE(&g->console_logs_mutex); + Lock lock = LockE(&g->console_logs_mutex); { for (ConsoleLog *log = g->last_console_log; log; log = log->prev) { @@ -356,7 +354,7 @@ void DrawDebugConsole(i32 level, b32 minimized) } } } - P_Unlock(&lock); + Unlock(&lock); } if (bounds_top < F32Infinity && bounds_bottom > -F32Infinity) { @@ -417,7 +415,7 @@ void UpdateUser(P_Window *window) TempArena scratch = BeginScratchNoConflict(); //- Begin frame - g->real_dt_ns = P_TimeNs() - g->real_time_ns; + g->real_dt_ns = TimeNs() - g->real_time_ns; g->real_time_ns += g->real_dt_ns; g->screen_size = P_GetWindowSize(window); S_Scope *sprite_frame_scope = S_BeginScope(); @@ -426,7 +424,7 @@ void UpdateUser(P_Window *window) { __profn("Pull snapshot"); - P_Lock lock = P_LockE(&g->local_to_user_client_mutex); + Lock lock = LockE(&g->local_to_user_client_mutex); u64 old_last_tick = g->user_unblended_client->last_tick; u64 last_tick = g->local_to_user_client->last_tick; if (last_tick > old_last_tick) @@ -437,7 +435,7 @@ void UpdateUser(P_Window *window) g->average_local_to_user_snapshot_publish_dt_ns -= g->average_local_to_user_snapshot_publish_dt_ns / 50; g->average_local_to_user_snapshot_publish_dt_ns += g->local_to_user_client_publish_dt_ns / 50; } - P_Unlock(&lock); + Unlock(&lock); } //- Create user world from blended snapshots @@ -1832,7 +1830,7 @@ void UpdateUser(P_Window *window) /* Set user sim control */ { - P_Lock lock = P_LockE(&g->user_sim_cmd_mutex); + Lock lock = LockE(&g->user_sim_cmd_mutex); /* Reset flags */ if (g->user_sim_cmd_gen != g->last_user_sim_cmd_gen) @@ -1845,7 +1843,7 @@ void UpdateUser(P_Window *window) g->user_sim_cmd_control = control; g->user_sim_cmd_control.flags |= old_flags; g->user_hovered_ent = hovered_ent->id; - P_Unlock(&lock); + Unlock(&lock); } } @@ -1869,7 +1867,7 @@ void UpdateUser(P_Window *window) { /* Update network usage stats */ - i64 stat_now_ns = P_TimeNs(); + i64 stat_now_ns = TimeNs(); g->net_bytes_read.last_second_end = GetGstat(GSTAT_SOCK_BYTES_RECEIVED); g->net_bytes_sent.last_second_end = GetGstat(GSTAT_SOCK_BYTES_SENT); if (stat_now_ns - g->last_second_reset_ns > NsFromSeconds(1)) @@ -2066,10 +2064,10 @@ void UpdateUser(P_Window *window) //- User update job -JobDef(UpdateUserJob, _) +JobDef(UpdateUserJob, UNUSED sig, UNUSED id) { SharedUserState *g = &shared_user_state; - i64 time_ns = P_TimeNs(); + i64 time_ns = TimeNs(); while (!Atomic32Fetch(&g->shutdown)) { P_Window *window = g->window; @@ -2082,7 +2080,7 @@ JobDef(UpdateUserJob, _) { __profn("Frame limiter wait"); P_SleepFrame(time_ns, 1000000000 / FPS_LIMIT); - time_ns = P_TimeNs(); + time_ns = TimeNs(); } } UpdateUser(window); @@ -2109,7 +2107,7 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick) sim_ent_activate(control_cmd, user_input_ss->tick); } { - P_Lock lock = P_LockE(&g->user_sim_cmd_mutex); + Lock lock = LockE(&g->user_sim_cmd_mutex); /* Update control cmd */ { control_cmd->cmd_control = g->user_sim_cmd_control; @@ -2125,14 +2123,14 @@ void GenerateuserInputCmds(Client *user_input_client, u64 tick) } #endif ++g->user_sim_cmd_gen; - P_Unlock(&lock); + Unlock(&lock); } } //////////////////////////////// //~ Sim update -JobDef(SimJob, UNUSED job) +JobDef(SimJob, UNUSED sig, UNUSED id) { SharedUserState *g = &shared_user_state; #if 0 @@ -2221,7 +2219,7 @@ JobDef(SimJob, UNUSED job) { __profn("Sim update"); - real_dt_ns = P_TimeNs() - real_time_ns; + real_dt_ns = TimeNs() - real_time_ns; real_time_ns += real_dt_ns; N_EventList host_events = N_BeginUpdate(scratch.arena, host); @@ -2798,9 +2796,9 @@ JobDef(SimJob, UNUSED job) if (local_ss->valid) { /* TODO: Double buffer */ - P_Lock lock = P_LockE(&g->local_to_user_client_mutex); + Lock lock = LockE(&g->local_to_user_client_mutex); sim_snapshot_alloc(g->local_to_user_client, local_ss, local_ss->tick); - i64 publish_ns = P_TimeNs(); + i64 publish_ns = TimeNs(); if (last_publish_to_user_ns == 0) { last_publish_to_user_ns = publish_ns - g->average_local_to_user_snapshot_publish_dt_ns; @@ -2809,7 +2807,7 @@ JobDef(SimJob, UNUSED job) g->local_to_user_client_publish_time_ns = publish_ns; last_publish_to_user_ns = publish_ns; sim_snapshot_release_ticks_in_range(g->local_to_user_client, 0, local_ss->tick - 1); - P_Unlock(&lock); + Unlock(&lock); } } diff --git a/src/pp/pp_core.h b/src/pp/pp_core.h index 3619327a..6805d9aa 100644 --- a/src/pp/pp_core.h +++ b/src/pp/pp_core.h @@ -185,7 +185,7 @@ Struct(SharedUserState) b32 debug_draw; //- Debug console - P_Mutex console_logs_mutex; + Mutex console_logs_mutex; Arena *console_logs_arena; ConsoleLog *first_console_log; ConsoleLog *last_console_log; @@ -194,11 +194,11 @@ Struct(SharedUserState) b32 debug_console; //- Window -> user - P_Mutex sys_window_events_mutex; + Mutex sys_window_events_mutex; Arena *sys_window_events_arena; //- User -> sim - P_Mutex user_sim_cmd_mutex; + Mutex user_sim_cmd_mutex; ControlData user_sim_cmd_control; EntityId user_hovered_ent; u64 last_user_sim_cmd_gen; @@ -208,7 +208,7 @@ Struct(SharedUserState) Atomic32 user_paused_steps; //- Sim -> user - P_Mutex local_to_user_client_mutex; + Mutex local_to_user_client_mutex; ClientStore *local_to_user_client_store; Client *local_to_user_client; i64 local_to_user_client_publish_dt_ns; diff --git a/src/pp/pp_sim.c b/src/pp/pp_sim.c index 61f3b7e4..d8c77f5e 100644 --- a/src/pp/pp_sim.c +++ b/src/pp/pp_sim.c @@ -329,14 +329,14 @@ Snapshot *sim_snapshot_alloc(Client *client, Snapshot *src, u64 tick) if (ss->num_ents_reserved == 0) { /* Copying from nil snapshot, need to create blank & root entity */ - /* PushStruct blank ent at index 0 (because index 0 is never valid anyway since it maps to sim_ent_nil()) */ + /* Push blank ent at index 0 (because index 0 is never valid anyway since it maps to sim_ent_nil()) */ { PushStruct(ss->ents_arena, Entity); ++ss->num_ents_allocated; ++ss->num_ents_reserved; } - /* PushStruct root ent with constant id */ + /* Push root ent with constant id */ { Entity *root = PushStructNoZero(ss->ents_arena, Entity); *root = *sim_ent_nil(); diff --git a/src/sound/sound_core.c b/src/sound/sound_core.c index 1c0f9fa8..6f0559cd 100644 --- a/src/sound/sound_core.c +++ b/src/sound/sound_core.c @@ -1,17 +1,16 @@ //////////////////////////////// //~ Load job -JobDef(SND_LoadAssetJob, job) +JobDef(SND_LoadJob, sig, UNUSED id) { __prof; - SND_LoadAssetJobSig *params = job.sig; TempArena scratch = BeginScratchNoConflict(); - String path = STRING(params->path_len, (u8 *)params->path_cstr); - AC_Asset *asset = params->asset; - SND_SoundFlag flags = params->flags; + String path = sig->path; + AC_Asset *asset = sig->asset; + SND_SoundFlag flags = sig->flags; P_LogInfoF("Loading sound \"%F\"", FmtString(path)); - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); String error_msg = Lit("Unknown error"); @@ -61,7 +60,7 @@ JobDef(SND_LoadAssetJob, job) sound->samples = samples; CopyBytes(sound->samples, decoded.samples, decoded.samples_count * sizeof(*decoded.samples)); - P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(P_TimeNs() - start_ns))); + P_LogSuccessF("Loaded sound \"%F\" in %F seconds", FmtString(path), FmtFloat(SecondsFromNs(TimeNs() - start_ns))); AC_MarkReady(asset, sound); } else @@ -101,22 +100,12 @@ AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait) if (is_first_touch) { - /* Assemble task params */ - SND_LoadAssetJobSig *params = SND_AllocJobSig(); - if (path.len > (sizeof(params->path_cstr) - 1)) - { - P_Panic(StringFormat(scratch.arena, - Lit("Sound path \"%F\" too long!"), - FmtString(path))); - } - CstrBuffFromStringToBuff(StringFromArray(params->path_cstr), path); - params->path_len = path.len; - params->asset = asset; - params->flags = flags; - - /* PushStruct task */ AC_MarkLoading(asset); - P_Run(1, SND_LoadAssetJob, params, PoolKind_Background, PriorityKind_Low, &asset->counter); + SND_LoadJob_Desc *desc = PushJobDesc(SND_LoadJob, .pool = PoolKind_Background, .priority = PriorityKind_Low, .counter = &asset->counter); + desc->sig->path = PushString(desc->arena, path); + desc->sig->asset = asset; + desc->sig->flags = flags; + RunJobEx((GenericJobDesc *)desc); if (wait) { AC_WaitOnAssetReady(asset); diff --git a/src/sound/sound_core.h b/src/sound/sound_core.h index 31e6eb9e..f1f22fb9 100644 --- a/src/sound/sound_core.h +++ b/src/sound/sound_core.h @@ -19,7 +19,7 @@ Struct(SND_Sound) //////////////////////////////// //~ Sound load operations -JobDecl(SND_LoadAssetJob, { SND_SoundFlag flags; AC_Asset *asset; String path; }); +JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; String path; }); AC_Asset *SND_LoadAsset(String path, SND_SoundFlag flags, b32 wait); SND_Sound *SND_LoadSoundAsync(String path, SND_SoundFlag flags); SND_Sound *SND_LoadSoundWait(String path, SND_SoundFlag flags); diff --git a/src/sprite/sprite_core.c b/src/sprite/sprite_core.c index 3c65487e..998351d1 100644 --- a/src/sprite/sprite_core.c +++ b/src/sprite/sprite_core.c @@ -40,11 +40,9 @@ S_StartupReceipt S_Startup(void) g->cache.arena = AllocArena(Gibi(64)); g->cache.bins = PushStructs(g->cache.arena, S_CacheEntryBin, S_CacheBinsCount); - g->cmds_arena = AllocArena(Gibi(64)); - g->scopes_arena = AllocArena(Gibi(64)); - P_Run(1, S_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->shutdown_counter); + RunJob(1, S_EvictorJob, 0, PoolKind_Background, PriorityKind_Low, &g->shutdown_counter); P_OnExit(&S_Shutdown); #if RESOURCE_RELOADING @@ -63,13 +61,13 @@ P_ExitFuncDef(S_Shutdown) S_SharedState *g = &S_shared_state; /* Signal evictor shutdown */ { - P_Lock lock = P_LockE(&g->evictor_scheduler_mutex); + Lock lock = LockE(&g->evictor_scheduler_mutex); g->evictor_scheduler_shutdown = 1; - P_SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max); - P_Unlock(&lock); + SignalCv(&g->evictor_scheduler_shutdown_cv, I32Max); + Unlock(&lock); } /* Wait for evictor shutdown */ - P_WaitOnCounter(&g->shutdown_counter); + WaitOnCounter(&g->shutdown_counter); } //////////////////////////////// @@ -421,69 +419,35 @@ S_Sheet S_SheetFromAseResult(Arena *arena, ASE_DecodedSheet ase) //////////////////////////////// //~ Load job -//- Job def -JobDef(S_LoadSpriteJob, job) +JobDef(S_LoadSpriteJob, sig, UNUSED id) { __prof; - S_SharedState *g = &S_shared_state; - S_Cmd *cmd = job.sig; - S_CacheEntryRef ref = cmd->ref; - + S_CacheEntryRef ref = sig->ref; + S_Tag tag = sig->tag; + S_Scope *scope = sig->scope; switch (ref.e->kind) { case S_CacheEntryKind_Texture: { - S_LoadCacheEntryTexture(ref, cmd->tag); + S_LoadCacheEntryTexture(ref, tag); } break; case S_CacheEntryKind_Sheet: { - S_LoadCacheEntrySheet(ref, cmd->tag); + S_LoadCacheEntrySheet(ref, tag); } break; default: { P_Panic(Lit("Unknown sprite cache node kind")); } break; } - - /* Free cmd */ - P_Lock lock = P_LockE(&g->cmds_mutex); - { - S_EndScope(cmd->scope); - cmd->next_free = g->first_free_cmd; - g->first_free_cmd = cmd; - } - P_Unlock(&lock); + S_EndScope(scope); } -//- Push void S_PushLoadJob(S_CacheEntryRef ref, S_Tag tag) { - S_SharedState *g = &S_shared_state; - S_Cmd *cmd = 0; - { - P_Lock lock = P_LockE(&g->cmds_mutex); - if (g->first_free_cmd) - { - cmd = g->first_free_cmd; - g->first_free_cmd = cmd->next_free; - } - else - { - cmd = PushStructNoZero(g->cmds_arena, S_Cmd); - } - P_Unlock(&lock); - } - ZeroStruct(cmd); - - /* Initialize cmd */ - cmd->scope = S_BeginScope(); - cmd->ref = S_EnsureRefFromRef(cmd->scope, ref)->ref; - cmd->tag = tag; - { - u64 copy_len = MinU64(tag.path.len, countof(cmd->tag_path_buff)); - cmd->tag.path.text = cmd->tag_path_buff; - CopyBytes(cmd->tag.path.text, tag.path.text, copy_len); - } - - /* PushStruct work */ - P_Run(1, S_LoadSpriteJob, cmd, PoolKind_Background, PriorityKind_Inherit, 0); + S_LoadSpriteJob_Desc *desc = PushJobDesc(S_LoadSpriteJob, .pool = PoolKind_Background, .priority = PriorityKind_Inherit); + desc->sig->scope = S_BeginScope(); /* Scope ended by job */ + desc->sig->ref = S_EnsureRefFromRef(desc->sig->scope, ref)->ref; + desc->sig->tag = tag; + tag.path = PushString(desc->arena, tag.path); + RunJobEx((GenericJobDesc *)desc); } //////////////////////////////// @@ -501,7 +465,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag) P_LogInfoF("Loading sprite texture [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path)); b32 success = 0; - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); Assert(StringEndsWith(path, Lit(".ase"))); Assert(e->kind == S_CacheEntryKind_Texture); @@ -549,7 +513,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag) P_LogSuccessF("Loaded sprite texture [%F] \"%F\" in %F seconds (cache size: %F bytes).", FmtHex(e->hash.v), FmtString(path), - FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)), + FmtFloat(SecondsFromNs(TimeNs() - start_ns)), FmtUint(e->memory_usage)); } @@ -557,7 +521,7 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag) #if RESOURCE_RELOADING S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount]; - P_Lock bin_lock = P_LockE(&bin->mutex); + Lock bin_lock = LockE(&bin->mutex); { for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin) { @@ -566,9 +530,9 @@ void S_LoadCacheEntryTexture(S_CacheEntryRef ref, S_Tag tag) Atomic32FetchSet(&old_entry->out_of_date, 1); } } - e->load_time_ns = P_TimeNs(); + e->load_time_ns = TimeNs(); } - P_Unlock(&bin_lock); + Unlock(&bin_lock); #endif EndScratch(scratch); @@ -586,7 +550,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag) P_LogInfoF("Loading sprite sheet [%F] \"%F\"", FmtHex(e->hash.v), FmtString(path)); b32 success = 0; - i64 start_ns = P_TimeNs(); + i64 start_ns = TimeNs(); Assert(e->kind == S_CacheEntryKind_Sheet); @@ -632,7 +596,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag) P_LogSuccessF("Loaded sprite sheet [%F] \"%F\" in %F seconds (cache size: %F bytes).", FmtHex(e->hash.v), FmtString(path), - FmtFloat(SecondsFromNs(P_TimeNs() - start_ns)), + FmtFloat(SecondsFromNs(TimeNs() - start_ns)), FmtUint(e->memory_usage)); } @@ -640,7 +604,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag) #if RESOURCE_RELOADING S_CacheEntryBin *bin = &g->cache.bins[e->hash.v % S_CacheBinsCount]; - P_Lock bin_lock = P_LockE(&bin->mutex); + Lock bin_lock = LockE(&bin->mutex); { for (S_CacheEntry *old_entry = bin->first; old_entry; old_entry = old_entry->next_in_bin) { @@ -649,9 +613,9 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag) Atomic32FetchSet(&old_entry->out_of_date, 1); } } - e->load_time_ns = P_TimeNs(); + e->load_time_ns = TimeNs(); } - P_Unlock(&bin_lock); + Unlock(&bin_lock); #endif EndScratch(scratch); @@ -720,11 +684,11 @@ S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e) return *slot; } -S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, P_Lock *bin_lock) +S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, Lock *bin_lock) { S_SharedState *g = &S_shared_state; /* Guaranteed safe if caller has lock on entry's bin, since entry may not have an existing reference and could otherwise be evicted while ensuring this reference */ - P_AssertLockedES(bin_lock, &g->cache.bins[e->hash.v % S_CacheBinsCount].mutex); + AssertLockedES(bin_lock, &g->cache.bins[e->hash.v % S_CacheBinsCount].mutex); return S_EnsureRefUnsafely(scope, e); } @@ -745,7 +709,7 @@ S_Scope *S_BeginScope(void) S_ScopeCacheEntryRef **bins = 0; S_ScopeCacheEntryRef *pool = 0; { - P_Lock lock = P_LockE(&g->scopes_mutex); + Lock lock = LockE(&g->scopes_mutex); { if (g->first_free_scope) { @@ -761,7 +725,7 @@ S_Scope *S_BeginScope(void) pool = PushStructsNoZero(g->scopes_arena, S_ScopeCacheEntryRef, S_MaxScopeReferences); } } - P_Unlock(&lock); + Unlock(&lock); } ZeroStruct(result); ZeroBytes(bins, sizeof(*bins) * S_CacheBinsCount); @@ -782,12 +746,12 @@ void S_EndScope(S_Scope *scope) } /* Release scope */ - P_Lock lock = P_LockE(&g->scopes_mutex); + Lock lock = LockE(&g->scopes_mutex); { scope->next_free = g->first_free_scope; g->first_free_scope = scope; } - P_Unlock(&lock); + Unlock(&lock); } //////////////////////////////// @@ -795,13 +759,13 @@ void S_EndScope(S_Scope *scope) //- Locked lookup -S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, P_Lock *bin_lock) +S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *bin_lock) { S_SharedState *g = &S_shared_state; S_ScopeCacheEntryRef *scope_ref = 0; S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount]; - P_AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */ + AssertLockedES(bin_lock, &bin->mutex); /* Lock required for iterating bin */ #if RESOURCE_RELOADING /* If resource reloading is enabled, then we want to find the @@ -870,17 +834,17 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind /* Search in cache */ if (!force_new) { - P_Lock bin_lock = P_LockS(&bin->mutex); + Lock bin_lock = LockS(&bin->mutex); { scope_ref = S_EntryFromHashLocked(scope, hash, &bin_lock); } - P_Unlock(&bin_lock); + Unlock(&bin_lock); } /* If not in cache, allocate new entry */ if (!scope_ref) { - P_Lock bin_lock = P_LockE(&bin->mutex); + Lock bin_lock = LockE(&bin->mutex); { /* Search cache one more time in case an entry was allocated between locks */ if (!force_new) @@ -893,7 +857,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind /* Cache entry still absent, allocate new entry */ S_CacheEntry *entry = 0; { - P_Lock pool_lock = P_LockE(&g->cache.entry_pool_mutex); + Lock pool_lock = LockE(&g->cache.entry_pool_mutex); if (g->cache.entry_pool_first_free) { entry = g->cache.entry_pool_first_free; @@ -903,7 +867,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind { entry = PushStructNoZero(g->cache.arena, S_CacheEntry); } - P_Unlock(&pool_lock); + Unlock(&pool_lock); } ZeroStruct(entry); @@ -928,7 +892,7 @@ S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind scope_ref = S_EnsureRefFromEntryLocked(scope, entry, &bin_lock); } } - P_Unlock(&bin_lock); + Unlock(&bin_lock); } } @@ -1132,11 +1096,11 @@ void S_ReloadSpriteFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind) S_Hash hash = S_CacheEntryFromTagHash(tag.hash, kind); S_CacheEntryBin *bin = &g->cache.bins[hash.v % S_CacheBinsCount]; S_ScopeCacheEntryRef *existing_ref = 0; - P_Lock bin_lock = P_LockS(&bin->mutex); + Lock bin_lock = LockS(&bin->mutex); { existing_ref = S_EntryFromHashLocked(scope, hash, &bin_lock); } - P_Unlock(&bin_lock); + Unlock(&bin_lock); if (existing_ref) { @@ -1189,7 +1153,7 @@ MergesortCompareFuncDef(S_EvictorSortCmp, arg_a, arg_b, _) * - The cache is over its memory budget and the node's last reference is longer ago than the grace period * - Resource reloading is enabled and the node is out of date due to a change to its original resource file */ -JobDef(S_EvictorJob, _) +JobDef(S_EvictorJob, UNUSED sig, UNUSED job_id) { S_SharedState *g = &S_shared_state; b32 shutdown = 0; @@ -1211,7 +1175,7 @@ JobDef(S_EvictorJob, _) for (u64 i = 0; i < S_CacheBinsCount; ++i) { S_CacheEntryBin *bin = &g->cache.bins[i]; - P_Lock bin_lock = P_LockS(&bin->mutex); + Lock bin_lock = LockS(&bin->mutex); { S_CacheEntry *n = bin->first; while (n) @@ -1244,7 +1208,7 @@ JobDef(S_EvictorJob, _) n = n->next_in_bin; } } - P_Unlock(&bin_lock); + Unlock(&bin_lock); } } @@ -1269,7 +1233,7 @@ JobDef(S_EvictorJob, _) S_CacheEntry *entry = en->cache_entry; i32 last_ref_cycle = en->last_ref_cycle; b32 cache_over_budget_target = Atomic64Fetch(&g->cache.memory_usage.v) > (i64)S_CacheMemoryBudgetTarget; - P_Lock bin_lock = P_LockE(&bin->mutex); + Lock bin_lock = LockE(&bin->mutex); { u64 refcount_uncast = Atomic64Fetch(&entry->refcount_struct.v); S_Refcount refcount = *(S_Refcount *)&refcount_uncast; @@ -1311,7 +1275,7 @@ JobDef(S_EvictorJob, _) stop_evicting = 1; } } - P_Unlock(&bin_lock); + Unlock(&bin_lock); } } @@ -1334,14 +1298,14 @@ JobDef(S_EvictorJob, _) /* Add evicted nodes to free list */ { __profn("Evictor free list append"); - P_Lock pool_lock = P_LockE(&g->cache.entry_pool_mutex); + Lock pool_lock = LockE(&g->cache.entry_pool_mutex); for (S_EvictorNode *en = first_evicted; en; en = en->next_evicted) { S_CacheEntry *n = en->cache_entry; n->next_free = g->cache.entry_pool_first_free; g->cache.entry_pool_first_free = n; } - P_Unlock(&pool_lock); + Unlock(&pool_lock); } } } @@ -1351,15 +1315,15 @@ JobDef(S_EvictorJob, _) /* Evictor sleep */ { - P_Lock lock = P_LockE(&g->evictor_scheduler_mutex); + Lock lock = LockE(&g->evictor_scheduler_mutex); { if (!g->evictor_scheduler_shutdown) { - P_WaitOnCvTime(&g->evictor_scheduler_shutdown_cv, &lock, S_EvictorCycleIntervalNs); + WaitOnCvTime(&g->evictor_scheduler_shutdown_cv, &lock, S_EvictorCycleIntervalNs); } shutdown = g->evictor_scheduler_shutdown; } - P_Unlock(&lock); + Unlock(&lock); } } } diff --git a/src/sprite/sprite_core.h b/src/sprite/sprite_core.h index 6803ce6e..2a9c4e52 100644 --- a/src/sprite/sprite_core.h +++ b/src/sprite/sprite_core.h @@ -150,7 +150,7 @@ Struct(S_CacheEntry) Struct(S_CacheEntryBin) { - P_Mutex mutex; + Mutex mutex; S_CacheEntry *first; S_CacheEntry *last; }; @@ -160,7 +160,7 @@ Struct(S_Cache) Atomic64Padded memory_usage; Arena *arena; S_CacheEntryBin *bins; - P_Mutex entry_pool_mutex; + Mutex entry_pool_mutex; S_CacheEntry *entry_pool_first_free; }; @@ -238,7 +238,7 @@ Struct(S_SharedState) S_Cache cache; /* Scopes */ - P_Mutex scopes_mutex; + Mutex scopes_mutex; Arena *scopes_arena; S_Scope *first_free_scope; @@ -246,8 +246,8 @@ Struct(S_SharedState) Atomic32Padded evictor_cycle; Counter shutdown_counter; b32 evictor_scheduler_shutdown; - P_Mutex evictor_scheduler_mutex; - P_Cv evictor_scheduler_shutdown_cv; + Mutex evictor_scheduler_mutex; + Cv evictor_scheduler_shutdown_cv; }; extern S_SharedState S_shared_state; @@ -298,7 +298,7 @@ void S_LoadCacheEntrySheet(S_CacheEntryRef ref, S_Tag tag); void S_AddRef(S_CacheEntry *e, i32 amount); S_ScopeCacheEntryRef *S_EnsureRefUnsafely(S_Scope *scope, S_CacheEntry *e); -S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, P_Lock *bin_lock); +S_ScopeCacheEntryRef *S_EnsureRefFromEntryLocked(S_Scope *scope, S_CacheEntry *e, Lock *bin_lock); S_ScopeCacheEntryRef *S_EnsureRefFromRef(S_Scope *scope, S_CacheEntryRef ref); //////////////////////////////// @@ -310,7 +310,7 @@ void S_EndScope(S_Scope *scope); //////////////////////////////// //~ Cache lookup operations -S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, P_Lock *bin_lock); +S_ScopeCacheEntryRef *S_EntryFromHashLocked(S_Scope *scope, S_Hash hash, Lock *bin_lock); S_ScopeCacheEntryRef *S_EntryFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 force_new); void *S_DataFromTag(S_Scope *scope, S_Tag tag, S_CacheEntryKind kind, b32 await); diff --git a/src/watch/watch_core.c b/src/watch/watch_core.c index 2186ff9e..44236f29 100644 --- a/src/watch/watch_core.c +++ b/src/watch/watch_core.c @@ -10,8 +10,8 @@ void W_Startup(void) g->watch_events_arena = AllocArena(Gibi(64)); - P_Run(1, W_MonitorJob, 0, PoolKind_Floating, PriorityKind_Low, &g->watch_jobs_counter); - P_Run(1, W_DispatcherJob, 0, PoolKind_Background, PriorityKind_Low, &g->watch_jobs_counter); + RunJob(1, W_MonitorJob, 0, PoolKind_Floating, PriorityKind_Low, &g->watch_jobs_counter); + RunJob(1, W_DispatcherJob, 0, PoolKind_Background, PriorityKind_Low, &g->watch_jobs_counter); P_OnExit(&W_Shutdown); } @@ -21,12 +21,12 @@ P_ExitFuncDef(W_Shutdown) W_SharedState *g = &W_shared_state; Atomic32FetchSet(&g->W_Shutdown, 1); { - P_Lock lock = P_LockE(&g->watch_dispatcher_mutex); - P_SignalCv(&g->watch_dispatcher_cv, I32Max); + Lock lock = LockE(&g->watch_dispatcher_mutex); + SignalCv(&g->watch_dispatcher_cv, I32Max); P_WakeWatch(g->watch); - P_Unlock(&lock); + Unlock(&lock); } - P_WaitOnCounter(&g->watch_jobs_counter); + WaitOnCounter(&g->watch_jobs_counter); } //////////////////////////////// @@ -35,7 +35,7 @@ P_ExitFuncDef(W_Shutdown) void W_RegisterCallback(W_CallbackFunc *callback) { W_SharedState *g = &W_shared_state; - P_Lock lock = P_LockE(&g->watch_callbacks_mutex); + Lock lock = LockE(&g->watch_callbacks_mutex); { if (g->num_watch_callbacks < countof(g->watch_callbacks)) { @@ -46,15 +46,14 @@ void W_RegisterCallback(W_CallbackFunc *callback) P_Panic(Lit("Max resource watch callbacks reached")); } } - P_Unlock(&lock); + Unlock(&lock); } -JobDef(W_RunCallbackJob, job) +JobDef(W_RunCallbacksJob , sig, id) { __prof; - W_RunCallbackJobSig *sig = job.sig; String name = sig->name; - W_CallbackFunc *callback = sig->callbacks[job.id]; + W_CallbackFunc *callback = sig->callbacks[id]; callback(name); } @@ -65,7 +64,7 @@ JobDef(W_RunCallbackJob, job) * & dispatching watch callbacks into two separate jobs so that we can delay * the dispatch, allowing for deduplication of file modification notifications. */ -JobDef(W_MonitorJob, _) +JobDef(W_MonitorJob, UNUSED sig, UNUSED job_id) { TempArena scratch = BeginScratchNoConflict(); W_SharedState *g = &W_shared_state; @@ -81,7 +80,7 @@ JobDef(W_MonitorJob, _) P_WatchInfoList info_list = P_ReadWatchWait(temp.arena, g->watch); if (info_list.first && !Atomic32Fetch(&g->W_Shutdown)) { - P_Lock lock = P_LockE(&g->watch_dispatcher_mutex); + Lock lock = LockE(&g->watch_dispatcher_mutex); { for (P_WatchInfo *info = info_list.first; info; info = info->next) { @@ -111,8 +110,8 @@ JobDef(W_MonitorJob, _) } } } - P_SignalCv(&g->watch_dispatcher_cv, I32Max); - P_Unlock(&lock); + SignalCv(&g->watch_dispatcher_cv, I32Max); + Unlock(&lock); } EndTempArena(temp); } @@ -123,7 +122,7 @@ JobDef(W_MonitorJob, _) //////////////////////////////// //~ Dispatcher job -JobDef(W_DispatcherJob, _) +JobDef(W_DispatcherJob, UNUSED sig, UNUSED job_id) { W_SharedState *g = &W_shared_state; @@ -138,12 +137,12 @@ JobDef(W_DispatcherJob, _) /* Delay so that duplicate events pile up */ { __profn("Delay"); - P_Wait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds)); + FutexWait(0, 0, 0, NsFromSeconds(W_DispatcherDelaySeconds)); } /* Pull watch events from queue */ { - P_Lock lock = P_LockE(&g->watch_dispatcher_mutex); + Lock lock = LockE(&g->watch_dispatcher_mutex); for (W_Event *src_event = g->first_watch_event; src_event; src_event = src_event->next) { W_Event *e = PushStruct(scratch.arena, W_Event); @@ -161,13 +160,13 @@ JobDef(W_DispatcherJob, _) g->first_watch_event = 0; g->last_watch_event = 0; ResetArena(g->watch_events_arena); - P_Unlock(&lock); + Unlock(&lock); } /* Build callbacks array */ u64 num_callbacks = 0; W_CallbackFunc **callbacks = 0; - P_Lock callbacks_lock = P_LockS(&g->watch_callbacks_mutex); + Lock callbacks_lock = LockS(&g->watch_callbacks_mutex); { num_callbacks = g->num_watch_callbacks; callbacks = PushStructsNoZero(scratch.arena, W_CallbackFunc *, num_callbacks); @@ -176,7 +175,7 @@ JobDef(W_DispatcherJob, _) callbacks[i] = g->watch_callbacks[i]; } } - P_Unlock(&callbacks_lock); + Unlock(&callbacks_lock); /* Run callbacks */ { @@ -197,12 +196,9 @@ JobDef(W_DispatcherJob, _) } if (!skip) { - W_RunCallbackJobSig sig = ZI; - sig.name = e->name; - sig.callbacks = callbacks; Counter counter = ZI; - P_Run(num_callbacks, W_RunCallbackJob, &sig, PoolKind_Background, PriorityKind_Low, &counter); - P_WaitOnCounter(&counter); + RunJob(num_callbacks, W_RunCallbacksJob, PoolKind_Background, PriorityKind_Low, &counter, .name = e->name, .callbacks = callbacks); + WaitOnCounter(&counter); } } } @@ -211,15 +207,15 @@ JobDef(W_DispatcherJob, _) } /* Wait for event */ - P_Lock lock = P_LockS(&g->watch_dispatcher_mutex); + Lock lock = LockS(&g->watch_dispatcher_mutex); { shutdown = Atomic32Fetch(&g->W_Shutdown); while (!shutdown && !g->first_watch_event) { - P_WaitOnCv(&g->watch_dispatcher_cv, &lock); + WaitOnCv(&g->watch_dispatcher_cv, &lock); shutdown = Atomic32Fetch(&g->W_Shutdown); } } - P_Unlock(&lock); + Unlock(&lock); } } diff --git a/src/watch/watch_core.h b/src/watch/watch_core.h index 6aadb871..f3ec6cc3 100644 --- a/src/watch/watch_core.h +++ b/src/watch/watch_core.h @@ -4,12 +4,6 @@ #define W_CallbackFuncDef(func_name, arg_name) void func_name(String arg_name) typedef W_CallbackFuncDef(W_CallbackFunc, name); -Struct(W_RunCallbackJobSig) -{ - String name; - W_CallbackFunc **callbacks; -}; - //////////////////////////////// //~ Event types @@ -31,13 +25,13 @@ Struct(W_SharedState) Atomic32 W_Shutdown; Counter watch_jobs_counter; - P_Mutex watch_dispatcher_mutex; + Mutex watch_dispatcher_mutex; Arena *watch_events_arena; W_Event *first_watch_event; W_Event *last_watch_event; - P_Cv watch_dispatcher_cv; + Cv watch_dispatcher_cv; - P_Mutex watch_callbacks_mutex; + Mutex watch_callbacks_mutex; W_CallbackFunc *watch_callbacks[64]; u64 num_watch_callbacks; }; @@ -58,7 +52,7 @@ void W_RegisterCallback(W_CallbackFunc *callback); //////////////////////////////// //~ Callback job -JobDecl(W_RunCallbackJob, EmptySig); +JobDecl(W_RunCallbacksJob, { String name; W_CallbackFunc **callbacks; }); //////////////////////////////// //~ Long running jobs