diff --git a/src/base/base.cgh b/src/base/base.cgh index a3210695..d243024b 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -748,6 +748,7 @@ i64 TimeNs(void); void TrueRand(String buffer); CpuTopologyInfo GetCpuTopologyInfo(void); + void SleepSeconds(f64 seconds); #endif //////////////////////////////////////////////////////////// diff --git a/src/base/base_arena.c b/src/base/base_arena.c index 30b9270f..f6f566ff 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -1,5 +1,3 @@ -ThreadLocal ThreadArenasCtx t_arena_ctx = ZI; - //////////////////////////////////////////////////////////// //~ Arena management @@ -20,7 +18,7 @@ Arena *AcquireArena(u64 reserve) Panic(Lit("Failed to reserve memory")); } u64 reserved = reserve; - AddGstat(GSTAT_MEMORY_RESERVED, reserve); + AddGstat(MemoryReserved, reserve); /* Commit initial block */ base = CommitMemory(base, ArenaBlockSize); @@ -34,8 +32,8 @@ Arena *AcquireArena(u64 reserve) StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); - AddGstat(GSTAT_MEMORY_COMMITTED, ArenaBlockSize); - AddGstat(GSTAT_NUM_ARENAS, 1); + AddGstat(MemoryCommitted, ArenaBlockSize); + AddGstat(NumArenas, 1); /* Create & return arena header at beginning of block */ Arena *arena = (Arena *)base; @@ -48,9 +46,9 @@ Arena *AcquireArena(u64 reserve) void ReleaseArena(Arena *arena) { AsanUnpoison(arena, arena->committed + ArenaHeaderSize); - AddGstat(GSTAT_MEMORY_COMMITTED, -(i64)(arena->committed - ArenaHeaderSize)); - AddGstat(GSTAT_MEMORY_RESERVED, -(i64)(arena->reserved)); - AddGstat(GSTAT_NUM_ARENAS, -1); + AddGstat(MemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize)); + AddGstat(MemoryReserved, -(i64)(arena->reserved)); + AddGstat(NumArenas, -1); ReleaseMemory(arena); } @@ -117,7 +115,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align) Panic(Lit("Failed to commit new memory block: System may be out of memory")); } arena->committed += commit_bytes; - AddGstat(GSTAT_MEMORY_COMMITTED, commit_bytes); + AddGstat(MemoryCommitted, commit_bytes); AsanPoison(commit_address, commit_bytes); } @@ -200,15 +198,15 @@ void EndTempArena(TempArena temp) TempArena BeginScratch(Arena *potential_conflict) { /* This function is currently hard-coded for 2 thread-local scratch arenas */ - StaticAssert(ScratchArenasPerCtx == 2); + StaticAssert(countof(Base_tl.arenas.scratch) == 2); /* Use `BeginScratchNoConflict` if no conflicts are present */ Assert(potential_conflict != 0); - Arena *scratch_arena = t_arena_ctx.scratch_arenas[0]; + Arena *scratch_arena = Base_tl.arenas.scratch[0]; if (scratch_arena == potential_conflict) { - scratch_arena = t_arena_ctx.scratch_arenas[1]; + scratch_arena = Base_tl.arenas.scratch[1]; } TempArena temp = BeginTempArena(scratch_arena); return temp; @@ -216,12 +214,11 @@ TempArena BeginScratch(Arena *potential_conflict) TempArena BeginScratchNoConflict_(void) { - Arena *scratch_arena = t_arena_ctx.scratch_arenas[0]; + Arena *scratch_arena = Base_tl.arenas.scratch[0]; TempArena temp = BeginTempArena(scratch_arena); return temp; } - void EndScratch(TempArena scratch_temp) { EndTempArena(scratch_temp); diff --git a/src/base/base_arena.h b/src/base/base_arena.h index f0b486ac..4dafaaab 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -4,19 +4,6 @@ #define ArenaHeaderSize 256 #define ArenaBlockSize 16384 -//////////////////////////////////////////////////////////// -//~ State types - -#define ScratchArenasPerCtx 2 - -Struct(ThreadArenasCtx) -{ - Arena *perm_arena; - Arena *scratch_arenas[ScratchArenasPerCtx]; -}; - -extern ThreadLocal ThreadArenasCtx t_arena_ctx; - //////////////////////////////////////////////////////////// //~ Arena management @@ -65,7 +52,7 @@ void *ArenaFirst_(Arena *arena, u64 align); TempArena BeginTempArena(Arena *arena); void EndTempArena(TempArena temp); -#define PermArena() (t_arena_ctx.perm_arena) +#define PermArena() (Base_tl.arenas.perm) //////////////////////////////////////////////////////////// //~ Scratch arena helpers @@ -74,12 +61,12 @@ TempArena BeginScratch(Arena *potential_conflict); TempArena BeginScratchNoConflict_(void); void EndScratch(TempArena scratch_temp); -/* This macro declares an unused "arena" variable that will error if an existing "arena" - * variable is present (due to shadowing). This is for catching obvious cases of - * `BeginScratchNoConflict` getting called when an `arena` variable already - * exists in the caller's scope. */ +/* This macro declares an unused "arena" variable that will produce a shadowing + * warning variable is present (due to shadowing). This is for catching obvious + * cases of `BeginScratchNoConflict` getting called when an `arena` variable + * already exists in the caller's scope. */ #define BeginScratchNoConflict() \ - BeginScratchNoConflict_(); \ - do { \ - u8 arena = 0; \ + BeginScratchNoConflict_(); \ + do { \ + u8 arena = 0; \ } while (0) diff --git a/src/base/base_async.c b/src/base/base_async.c index 46cbe09a..6eb2f76d 100644 --- a/src/base/base_async.c +++ b/src/base/base_async.c @@ -4,19 +4,75 @@ void BootstrapAsync(void) { /* TODO: Dynamic lane counts */ - DispatchWave(Lit("Async"), 4, AsyncEntryPoint, 0); + DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0); } //////////////////////////////////////////////////////////// //~ Async ops -void OnAsyncTick(AsyncFunc *func) +void OnAsyncTick(AsyncTickCallbackFunc *func) { + Arena *perm = PermArena(); + + AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode); + n->callback.func = func; + + Lock lock = LockE(&Base.async.mutex); + { + SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n); + Base.async.callback_nodes_count += 1; + } + Unlock(&lock); } //////////////////////////////////////////////////////////// //~ Async worker -void AsyncEntryPoint(WaveLaneCtx *lane) +void AsyncWorkerEntryPoint(WaveLaneCtx *lane) { + /* Tick forever */ + for (;;) + { + TempArena scratch = BeginScratchNoConflict(); + AsyncWorkerState *w = &Base.async.worker; + + /* FIXME: Remove this */ + SleepSeconds(0.100); + + ////////////////////////////// + //- Grab async functions + + if (lane->idx == 0) + { + Lock lock = LockE(&Base.async.mutex); + { + w->callbacks_count = Base.async.callback_nodes_count; + w->callbacks = PushStructsNoZero(scratch.arena, AsyncTickCallback, w->callbacks_count); + u64 callback_idx = 0; + for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next) + { + w->callbacks[callback_idx] = n->callback; + ++callback_idx; + } + } + Unlock(&lock); + } + + WaveSync(lane); + + ////////////////////////////// + //- Run tick funcs + + for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx) + { + AsyncTickCallback *callback = &w->callbacks[callback_idx]; + callback->func(lane); + } + + ////////////////////////////// + //- End tick + + WaveSync(lane); + EndScratch(scratch); + } } diff --git a/src/base/base_async.h b/src/base/base_async.h index f6d60553..a565d000 100644 --- a/src/base/base_async.h +++ b/src/base/base_async.h @@ -1,7 +1,24 @@ //////////////////////////////////////////////////////////// //~ Async types -typedef void AsyncFunc(WaveLaneCtx *lane); +typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane); + +Struct(AsyncTickCallback) +{ + AsyncTickCallbackFunc *func; +}; + +Struct(AsyncTickCallbackNode) +{ + AsyncTickCallbackNode *next; + AsyncTickCallback callback; +}; + +Struct(AsyncWorkerState) +{ + u64 callbacks_count; + AsyncTickCallback *callbacks; +}; //////////////////////////////////////////////////////////// //~ Bootstrap @@ -11,9 +28,9 @@ void BootstrapAsync(void); //////////////////////////////////////////////////////////// //~ Async ops -void OnAsyncTick(AsyncFunc *func); +void OnAsyncTick(AsyncTickCallbackFunc *func); //////////////////////////////////////////////////////////// //~ Async worker -void AsyncEntryPoint(WaveLaneCtx *lane); +void AsyncWorkerEntryPoint(WaveLaneCtx *lane); diff --git a/src/base/base_cmdline.c b/src/base/base_cmdline.c index fc6b2571..fa682e58 100644 --- a/src/base/base_cmdline.c +++ b/src/base/base_cmdline.c @@ -1,11 +1,8 @@ -SharedCmdlineState shared_cmdline_state = ZI; - //////////////////////////////////////////////////////////// //~ Bootstrap void BootstrapCmdline(void) { - SharedCmdlineState *g = &shared_cmdline_state; TempArena scratch = BeginScratchNoConflict(); { StringList raw = GetRawCommandline(); @@ -54,19 +51,19 @@ void BootstrapCmdline(void) } Arena *perm = PermArena(); - g->positional_args_count = tmp_positionals_count; - g->positional_args = PushStructsNoZero(perm, String, tmp_positionals_count); - CopyStructs(g->positional_args, tmp_positionals, tmp_positionals_count); + Base.cmdline.positional_args_count = tmp_positionals_count; + Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count); + CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count); for (u64 i = 0; i < tmp_args_count; ++i) { CommandlineArg arg = tmp_args[i]; CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode); u64 hash = HashFnv64(Fnv64Basis, arg.name); - u64 bin_idx = hash % CommandlineArgBinsCount; + u64 bin_idx = hash % countof(Base.cmdline.arg_bins); n->arg = arg; n->hash = hash; - n->next = g->arg_bins[bin_idx]; - g->arg_bins[bin_idx] = n; + n->next = Base.cmdline.arg_bins[bin_idx]; + Base.cmdline.arg_bins[bin_idx] = n; } } EndScratch(scratch); @@ -77,21 +74,19 @@ void BootstrapCmdline(void) String StringFromCommandlineIdx(i32 idx) { - SharedCmdlineState *g = &shared_cmdline_state; String result = ZI; - if (idx < g->positional_args_count) + if (idx < Base.cmdline.positional_args_count) { - result = g->positional_args[idx]; + result = Base.cmdline.positional_args[idx]; } return result; } CommandlineArg CommandlineArgFromName(String name) { - SharedCmdlineState *g = &shared_cmdline_state; CommandlineArg result = ZI; u64 hash = HashFnv64(Fnv64Basis, name); - for (CommandlineArgNode *n = g->arg_bins[hash % CommandlineArgBinsCount]; n; n = n->next) + for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next) { if (n->hash == hash && MatchString(n->arg.name, name)) { diff --git a/src/base/base_cmdline.h b/src/base/base_cmdline.h index 4bb39eea..189a3f50 100644 --- a/src/base/base_cmdline.h +++ b/src/base/base_cmdline.h @@ -18,18 +18,6 @@ Struct(CommandlineArgNode) CommandlineArg arg; }; -//////////////////////////////////////////////////////////// -//~ State types - -#define CommandlineArgBinsCount 1024 - -Struct(SharedCmdlineState) -{ - String *positional_args; - u64 positional_args_count; - CommandlineArgNode *arg_bins[CommandlineArgBinsCount]; -} extern shared_cmdline_state; - //////////////////////////////////////////////////////////// //~ Bootstrap diff --git a/src/base/base_gstat.c b/src/base/base_gstat.c deleted file mode 100644 index b057bb1e..00000000 --- a/src/base/base_gstat.c +++ /dev/null @@ -1,3 +0,0 @@ -#if GstatIsEnabled -SharedGstatCtx _shared_gstat_ctx = ZI; -#endif diff --git a/src/base/base_gstat.h b/src/base/base_gstat.h index 4b553a7d..93d491f8 100644 --- a/src/base/base_gstat.h +++ b/src/base/base_gstat.h @@ -2,21 +2,9 @@ #if GstatIsEnabled -Struct(SharedGstatCtx) -{ - Atomic64Padded GSTAT_SOCK_BYTES_SENT; - Atomic64Padded GSTAT_SOCK_BYTES_RECEIVED; - Atomic64Padded GSTAT_MEMORY_COMMITTED; - Atomic64Padded GSTAT_MEMORY_RESERVED; - Atomic64Padded GSTAT_NUM_ARENAS; - Atomic64Padded GSTAT_DEBUG_STEPS; -}; - -extern SharedGstatCtx _shared_gstat_ctx; - -#define SetGstat(name, value) Atomic64Set(&_shared_gstat_ctx.name.v, (value)) -#define AddGstat(name, value) Atomic64FetchAdd(&_shared_gstat_ctx.name.v, (value)) -#define GetGstat(name) Atomic64Fetch(&_shared_gstat_ctx.name.v) +#define SetGstat(name, value) Atomic64Set(&Base.gstat.name.v, (value)) +#define AddGstat(name, value) Atomic64FetchAdd(&Base.gstat.name.v, (value)) +#define GetGstat(name) Atomic64Fetch(&Base.gstat.name.v) #else diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 21e78bdd..afbb256a 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -26,6 +26,7 @@ # include "base_resource.h" # include "base_controller.h" # include "base_async.h" +# include "base_state.h" #elif IsLanguageG # include "base_shader.gh" #endif @@ -40,7 +41,6 @@ # include "base_string.c" # include "base_cmdline.c" # include "base_uni.c" -# include "base_gstat.c" # include "base_buddy.c" # include "base_math.c" # include "base_rand.c" @@ -48,6 +48,7 @@ # include "base_resource.c" # include "base_controller.c" # include "base_async.c" +# include "base_state.c" #endif //- Include base_win32 diff --git a/src/base/base_log.h b/src/base/base_log.h index 0b8ee8f7..f43a1f13 100644 --- a/src/base/base_log.h +++ b/src/base/base_log.h @@ -129,11 +129,6 @@ Global Readonly LogLevelSettings log_settings[LogLevel_Count] = { # define LogDebugF(...) #endif -//////////////////////////////////////////////////////////// -//~ @hookdecl Bootstrap - -void BootstrapLogs(String logfile_path); - //////////////////////////////////////////////////////////// //~ @hookdecl Log diff --git a/src/base/base_resource.c b/src/base/base_resource.c index 6ddfe1e1..745bb7fa 100644 --- a/src/base/base_resource.c +++ b/src/base/base_resource.c @@ -1,11 +1,8 @@ -SharedResourceState shared_resource_state = ZI; - //////////////////////////////////////////////////////////// //~ Bootstrap void BootstrapResources(u64 archive_strings_count, String *archive_strings) { - SharedResourceState *g = &shared_resource_state; Arena *perm = PermArena(); for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index) { @@ -32,11 +29,11 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings) entry->data = STRING(data_len, archive.text + data_start); entry->hash = HashFnv64(Fnv64Basis, entry->name); - ResourceEntryBin *bin = &g->bins[entry->hash % NumResourceEntryBins]; + ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)]; SllQueuePushN(bin->first, bin->last, entry, next_in_bin); - SllQueuePushN(g->first_entry, g->last_entry, entry, next); + SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next); } - g->entries_count += num_entries; + Base.resource.entries_count += num_entries; } } } @@ -60,8 +57,7 @@ ResourceKey ResourceKeyFromStore(ResourceStore *store, String name) ResourceEntry *ResourceEntryFromHash(u64 hash) { ResourceEntry *result = 0; - SharedResourceState *g = &shared_resource_state; - ResourceEntryBin *bin = &g->bins[hash % NumResourceEntryBins]; + ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)]; for (ResourceEntry *e = bin->first; e; e = e->next_in_bin) { if (e->hash == hash) diff --git a/src/base/base_resource.h b/src/base/base_resource.h index 9dbeb0d9..ef92eead 100644 --- a/src/base/base_resource.h +++ b/src/base/base_resource.h @@ -17,19 +17,6 @@ Struct(ResourceEntryBin) ResourceEntry *last; }; -//////////////////////////////////////////////////////////// -//~ State types - -#define NumResourceEntryBins 4096 - -Struct(SharedResourceState) -{ - ResourceEntry *first_entry; - ResourceEntry *last_entry; - u64 entries_count; - ResourceEntryBin bins[NumResourceEntryBins]; -} extern shared_resource_state; - //////////////////////////////////////////////////////////// //~ Bootstrap diff --git a/src/base/base_state.c b/src/base/base_state.c new file mode 100644 index 00000000..a48d2b1c --- /dev/null +++ b/src/base/base_state.c @@ -0,0 +1,2 @@ +BaseState Base = ZI; +ThreadLocal BaseThreadLocalState Base_tl = ZI; diff --git a/src/base/base_state.h b/src/base/base_state.h new file mode 100644 index 00000000..7e5db902 --- /dev/null +++ b/src/base/base_state.h @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////// +//~ Global state + +Struct(BaseState) +{ + /* Command line */ + struct + { + String *positional_args; + u64 positional_args_count; + CommandlineArgNode *arg_bins[1024]; + } cmdline; + + /* Resources */ + struct + { + u64 entries_count; + ResourceEntry *first_entry; + ResourceEntry *last_entry; + ResourceEntryBin bins[4096]; + } resource; + + /* Stats */ + struct + { + Atomic64Padded SockBytesSent; + Atomic64Padded SockBytesReceived; + Atomic64Padded MemoryCommitted; + Atomic64Padded MemoryReserved; + Atomic64Padded NumArenas; + Atomic64Padded DebugSteps; + } gstat; + + /* Async */ + struct + { + Mutex mutex; + u64 callback_nodes_count; + AsyncTickCallbackNode *first_callback_node; + AsyncTickCallbackNode *last_callback_node; + AsyncWorkerState worker; + } async; +}; + +extern BaseState Base; + +//////////////////////////////////////////////////////////// +//~ Thread-local state + +Struct(BaseThreadLocalState) +{ + struct + { + Arena *perm; + Arena *scratch[2]; + } arenas; +}; + +extern ThreadLocal BaseThreadLocalState Base_tl; diff --git a/src/base/base_wave.c b/src/base/base_wave.c index 7093f230..dd8d2389 100644 --- a/src/base/base_wave.c +++ b/src/base/base_wave.c @@ -12,7 +12,7 @@ void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count) if (blocked_count == lanes_count) { Atomic32Set(&wave->sync_count.v, 0); - Atomic64FetchAdd(&wave->sync_gen.v, sync_gen + 1); + Atomic64Set(&wave->sync_gen.v, sync_gen + 1); FutexWakeNeq(&wave->sync_gen.v); } else diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index 514b3309..431a2679 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -1,4 +1,4 @@ -W32_SharedState W32_shared_state = ZI; +W32_State W32 = ZI; //////////////////////////////////////////////////////////// //~ Win32 embedded data @@ -40,7 +40,7 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name StringList GetRawCommandline(void) { - return W32_shared_state.raw_command_line; + return W32.raw_command_line; } void Echo(String msg) @@ -92,10 +92,9 @@ b32 IsRunningInDebugger(void) i64 TimeNs(void) { - struct W32_SharedState *g = &W32_shared_state; LARGE_INTEGER qpc; QueryPerformanceCounter(&qpc); - i64 result = (qpc.QuadPart - g->timer_start_qpc) * g->ns_per_qpc; + i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc; return result; } @@ -165,6 +164,11 @@ CpuTopologyInfo GetCpuTopologyInfo(void) return res; } +void SleepSeconds(f64 seconds) +{ + Sleep(seconds / 1000.0); +} + //////////////////////////////////////////////////////////// //~ @hookimpl Swap @@ -231,20 +235,18 @@ void WriteSwappedState(String name, String data) void OnExit(ExitFunc *func) { - W32_SharedState *g = &W32_shared_state; - i32 index = Atomic32FetchAdd(&g->num_exit_funcs, 1); - if (index >= W32_MaxOnExitFuncs) + i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1); + if (index >= countof(W32.exit_funcs)) { Panic(Lit("Maximum on exit functions registered")); } - g->exit_funcs[index] = func; + W32.exit_funcs[index] = func; } void SignalExit(i32 code) { - W32_SharedState *g = &W32_shared_state; - Atomic32Set(&g->exit_code, code); - SetEvent(g->exit_event); + Atomic32Set(&W32.exit_code, code); + SetEvent(W32.exit_event); } void ExitNow(i32 code) @@ -252,34 +254,168 @@ void ExitNow(i32 code) ExitProcess(code); } +//////////////////////////////////////////////////////////// +//~ Log + +void W32_BootstrapLogs(String logfile_path) +{ + W32.logs_arena = AcquireArena(Gibi(64)); + W32.log_msgs_arena = AcquireArena(Gibi(64)); + W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); + if (logfile_path.len > 0) + { + TempArena scratch = BeginScratchNoConflict(); + { + wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path); + W32.logfile = CreateFileW(path_wstr, + FILE_APPEND_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0); + } + EndScratch(scratch); + } + Atomic32Set(&W32.logs_initialized, 1); +} + +void W32_Log(i32 level, String msg) +{ + TempArena scratch = BeginScratchNoConflict(); + if (Atomic32Fetch(&W32.logs_initialized)) + { + LogLevelSettings settings = log_settings[level]; + if (level < 0 || level >= LogLevel_Count) + { + Panic(Lit("Invalid log level")); + } + + DateTime datetime = LocalDateTime(); + i64 now_ns = TimeNs(); + i32 thread_id = GetCurrentThreadId(); + + //- Log message to file + /* TODO: Log asynchronously */ + { + String shorthand = settings.shorthand; + String msg_formatted = StringF( + scratch.arena, + "[%F:%F:%F.%F] <%F> [%F] %F\n", + + /* Time */ + FmtUint(datetime.hour, .z = 2), + FmtUint(datetime.minute, .z = 2), + FmtUint(datetime.second, .z = 2), + FmtUint(datetime.milliseconds, .z = 3), + + /* Thread id */ + FmtUint(thread_id, .z = 5), + + /* Level */ + FmtString(shorthand), + + /* Message */ + FmtString(msg) + ); + WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0); + } + + //- Log message to queue + /* TODO: Log asynchronously */ + LockTicketMutex(&W32.logs_tm); + { + /* Get staged data */ + LogEvent *ev = PushStruct(W32.logs_arena, LogEvent); + ev->msg = PushString(W32.log_msgs_arena, msg); + ev->datetime = datetime; + ev->time_ns = now_ns; + ev->level = level; + ev->thread_id = thread_id; + ev->id = W32.logs_count++; + ev->level_id = W32.log_level_counts[level]++; + Atomic64Set(&W32.readable_logs_count, W32.logs_count); + } + UnlockTicketMutex(&W32.logs_tm); + } + EndScratch(scratch); +} + +//////////////////////////////////////////////////////////// +//~ @hookimpl Log + +/* Panic log function is separate to enforce zero side effects other than + * immediately writing to log file. */ +void LogPanic(String msg) +{ + if (Atomic32Fetch(&W32.logs_initialized)) + { + String beg = Lit("******** PANICKING ********\n"); + String end = Lit("\n***************************\n"); + WriteFile(W32.logfile, beg.text, beg.len, 0, 0); + WriteFile(W32.logfile, msg.text, msg.len, 0, 0); + WriteFile(W32.logfile, end.text, end.len, 0, 0); + } +} + +void Log_(i32 level, String msg) +{ + W32_Log(level, msg); +} + +void LogF_(i32 level, String fmt, ...) +{ + if (Atomic32Fetch(&W32.logs_initialized)) + { + TempArena scratch = BeginScratchNoConflict(); + va_list args; + va_start(args, fmt); + { + String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); + W32_Log(level, msg); + } + va_end(args); + EndScratch(scratch); + } +} + +LogEventsArray GetLogEvents(void) +{ + LogEventsArray result = ZI; + result.count = Atomic64Fetch(&W32.readable_logs_count); + if (result.count > 0) + { + result.logs = W32.readable_log_events; + } + return result; +} + //////////////////////////////////////////////////////////// //~ Main i32 W32_Main(void) { - W32_SharedState *g = &W32_shared_state; - /* Init time */ { LARGE_INTEGER qpf; QueryPerformanceFrequency(&qpf); - g->ns_per_qpc = 1000000000 / qpf.QuadPart; + W32.ns_per_qpc = 1000000000 / qpf.QuadPart; } { LARGE_INTEGER qpc; QueryPerformanceCounter(&qpc); - g->timer_start_qpc = qpc.QuadPart; + W32.timer_start_qpc = qpc.QuadPart; } /* Setup events */ - g->panic_event = CreateEventW(0, 1, 0, 0); - g->exit_event = CreateEventW(0, 1, 0, 0); + W32.panic_event = CreateEventW(0, 1, 0, 0); + W32.exit_event = CreateEventW(0, 1, 0, 0); - g->main_thread_id = GetCurrentThreadId(); + W32.main_thread_id = GetCurrentThreadId(); SetThreadDescription(GetCurrentThread(), L"Main thread"); /* Query system info */ - GetSystemInfo(&g->info); + GetSystemInfo(&W32.info); /* Init main thread */ W32_InitCurrentThread(Lit("Main")); @@ -299,7 +435,7 @@ i32 W32_Main(void) PushStringToList(perm, &args_list, arg); } } - g->raw_command_line = args_list; + W32.raw_command_line = args_list; } ////////////////////////////// @@ -310,7 +446,7 @@ i32 W32_Main(void) /* Bootstrap log system */ /* FIXME: Remove hardcoded log path */ - BootstrapLogs(Lit("log.log")); + W32_BootstrapLogs(Lit("log.log")); LogInfoF("Main thread ID: %F", FmtUint(ThreadId())); /* Bootstrap resource system */ @@ -324,7 +460,7 @@ i32 W32_Main(void) BootstrapAsync(); /* Bootstrap layers */ - if (!Atomic32Fetch(&g->panicking)) + if (!Atomic32Fetch(&W32.panicking)) { BootstrapLayers(); } @@ -333,11 +469,11 @@ i32 W32_Main(void) //- Wait for exit signal /* Wait for exit start or panic */ - if (!Atomic32Fetch(&g->panicking)) + if (!Atomic32Fetch(&W32.panicking)) { HANDLE handles[] = { - g->exit_event, - g->panic_event, + W32.exit_event, + W32.panic_event, }; DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); } @@ -346,24 +482,24 @@ i32 W32_Main(void) //- Shutdown /* Run exit callbacks */ - if (!Atomic32Fetch(&g->panicking)) + if (!Atomic32Fetch(&W32.panicking)) { - i32 num_funcs = Atomic32Fetch(&g->num_exit_funcs); + i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs); for (i32 idx = num_funcs - 1; idx >= 0; --idx) { - ExitFunc *func = g->exit_funcs[idx]; + ExitFunc *func = W32.exit_funcs[idx]; func(); } } /* Exit */ - if (Atomic32Fetch(&g->panicking)) + if (Atomic32Fetch(&W32.panicking)) { - WaitForSingleObject(g->panic_event, INFINITE); - MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - Atomic32FetchTestSet(&g->exit_code, 0, 1); + WaitForSingleObject(W32.panic_event, INFINITE); + MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); + Atomic32FetchTestSet(&W32.exit_code, 0, 1); } - return Atomic32Fetch(&g->exit_code); + return Atomic32Fetch(&W32.exit_code); } //////////////////////////////////////////////////////////// diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 6b3b86e3..df80180a 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -56,9 +56,7 @@ Struct(W32_FindEmbeddedDataCtx) //////////////////////////////////////////////////////////// //~ State types -#define W32_MaxOnExitFuncs 4096 - -Struct(W32_SharedState) +Struct(W32_State) { SYSTEM_INFO info; u32 main_thread_id; @@ -71,15 +69,33 @@ Struct(W32_SharedState) StringList raw_command_line; //- Application control flow + Atomic32 panicking; wchar_t panic_wstr[4096]; HANDLE panic_event; HANDLE exit_event; //- Exit funcs + Atomic32 num_exit_funcs; - ExitFunc *exit_funcs[W32_MaxOnExitFuncs]; -} extern W32_shared_state; + ExitFunc *exit_funcs[4096]; + + //- Logs + + HANDLE logfile; + Atomic32 logs_initialized; + + TicketMutex logs_tm; + Arena *log_msgs_arena; + Arena *logs_arena; + + u64 logs_count; + u64 log_level_counts[LogLevel_Count]; + LogEvent *readable_log_events; + Atomic64 readable_logs_count; +}; + +extern W32_State W32; //////////////////////////////////////////////////////////// //~ Embedded data initialization @@ -87,6 +103,12 @@ Struct(W32_SharedState) #define W32_EmbeddedDataPrefix EMBEDDED_RESOURCE_DATA__ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata); +//////////////////////////////////////////////////////////// +//~ Log + +void W32_BootstrapLogs(String logfile_path); +void W32_Log(i32 level, String msg); + //////////////////////////////////////////////////////////// //~ Main diff --git a/src/base/base_win32/base_win32_inc.h b/src/base/base_win32/base_win32_inc.h index 587d8e9a..eb13db20 100644 --- a/src/base/base_win32/base_win32_inc.h +++ b/src/base/base_win32/base_win32_inc.h @@ -1,7 +1,6 @@ //- Api #include "base_win32.h" #include "base_win32_wave.h" -#include "base_win32_log.h" //- Impl #include "base_win32.c" @@ -9,4 +8,3 @@ #include "base_win32_memory.c" #include "base_win32_wave.c" #include "base_win32_time.c" -#include "base_win32_log.c" diff --git a/src/base/base_win32/base_win32_log.c b/src/base/base_win32/base_win32_log.c deleted file mode 100644 index 291fa2af..00000000 --- a/src/base/base_win32/base_win32_log.c +++ /dev/null @@ -1,145 +0,0 @@ -W32_SharedLogState W32_shared_log_state = ZI; - -//////////////////////////////////////////////////////////// -//~ @hookimpl Bootstrap - -void BootstrapLogs(String logfile_path) -{ - W32_SharedLogState *g = &W32_shared_log_state; - g->logs_arena = AcquireArena(Gibi(64)); - g->log_msgs_arena = AcquireArena(Gibi(64)); - g->readable_log_events = ArenaNext(g->logs_arena, LogEvent); - if (logfile_path.len > 0) - { - TempArena scratch = BeginScratchNoConflict(); - { - wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path); - g->logfile = CreateFileW(path_wstr, - FILE_APPEND_DATA, - FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - 0); - } - EndScratch(scratch); - } - Atomic32Set(&g->initialized, 1); -} - -//////////////////////////////////////////////////////////// -//~ Log - -void W32_Log(i32 level, String msg) -{ - W32_SharedLogState *g = &W32_shared_log_state; - TempArena scratch = BeginScratchNoConflict(); - if (Atomic32Fetch(&g->initialized)) - { - LogLevelSettings settings = log_settings[level]; - if (level < 0 || level >= LogLevel_Count) - { - Panic(Lit("Invalid log level")); - } - - DateTime datetime = LocalDateTime(); - i64 now_ns = TimeNs(); - i32 thread_id = GetCurrentThreadId(); - - //- Log message to file - /* TODO: Log asynchronously */ - { - String shorthand = settings.shorthand; - String msg_formatted = StringF( - scratch.arena, - "[%F:%F:%F.%F] <%F> [%F] %F\n", - - /* Time */ - FmtUint(datetime.hour, .z = 2), - FmtUint(datetime.minute, .z = 2), - FmtUint(datetime.second, .z = 2), - FmtUint(datetime.milliseconds, .z = 3), - - /* Thread id */ - FmtUint(thread_id, .z = 5), - - /* Level */ - FmtString(shorthand), - - /* Message */ - FmtString(msg) - ); - WriteFile(g->logfile, msg_formatted.text, msg_formatted.len, 0, 0); - } - - //- Log message to queue - /* TODO: Log asynchronously */ - LockTicketMutex(&g->logs_tm); - { - /* Get staged data */ - LogEvent *ev = PushStruct(g->logs_arena, LogEvent); - ev->msg = PushString(g->log_msgs_arena, msg); - ev->datetime = datetime; - ev->time_ns = now_ns; - ev->level = level; - ev->thread_id = thread_id; - ev->id = g->logs_count++; - ev->level_id = g->log_level_counts[level]++; - Atomic64Set(&g->readable_logs_count, g->logs_count); - } - UnlockTicketMutex(&g->logs_tm); - } - EndScratch(scratch); -} - -//////////////////////////////////////////////////////////// -//~ @hookimpl Log - -/* Panic log function is separate to enforce zero side effects other than - * immediately writing to log file. */ -void LogPanic(String msg) -{ - W32_SharedLogState *g = &W32_shared_log_state; - if (Atomic32Fetch(&g->initialized)) - { - String beg = Lit("******** PANICKING ********\n"); - String end = Lit("\n***************************\n"); - WriteFile(g->logfile, beg.text, beg.len, 0, 0); - WriteFile(g->logfile, msg.text, msg.len, 0, 0); - WriteFile(g->logfile, end.text, end.len, 0, 0); - } -} - -void Log_(i32 level, String msg) -{ - W32_Log(level, msg); -} - -void LogF_(i32 level, String fmt, ...) -{ - W32_SharedLogState *g = &W32_shared_log_state; - if (Atomic32Fetch(&g->initialized)) - { - TempArena scratch = BeginScratchNoConflict(); - va_list args; - va_start(args, fmt); - { - String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args)); - W32_Log(level, msg); - } - va_end(args); - EndScratch(scratch); - } -} - -LogEventsArray GetLogEvents(void) -{ - W32_SharedLogState *g = &W32_shared_log_state; - LogEventsArray result = ZI; - result.count = Atomic64Fetch(&g->readable_logs_count); - if (result.count > 0) - { - result.logs = g->readable_log_events; - } - return result; -} diff --git a/src/base/base_win32/base_win32_log.h b/src/base/base_win32/base_win32_log.h deleted file mode 100644 index ece434b9..00000000 --- a/src/base/base_win32/base_win32_log.h +++ /dev/null @@ -1,21 +0,0 @@ -//////////////////////////////////////////////////////////// -//~ State types - -Struct(W32_SharedLogState) -{ - HANDLE logfile; - Atomic32 initialized; - - TicketMutex logs_tm; - Arena *log_msgs_arena; - Arena *logs_arena; - u64 logs_count; - u64 log_level_counts[LogLevel_Count]; - LogEvent *readable_log_events; - Atomic64 readable_logs_count; -} extern W32_shared_log_state; - -//////////////////////////////////////////////////////////// -//~ Log - -void W32_Log(i32 level, String msg); diff --git a/src/base/base_win32/base_win32_wave.c b/src/base/base_win32/base_win32_wave.c index a0dbc757..42edfb6b 100644 --- a/src/base/base_win32/base_win32_wave.c +++ b/src/base/base_win32/base_win32_wave.c @@ -5,16 +5,15 @@ void W32_InitCurrentThread(String name) { /* Init thread arenas */ { - ThreadArenasCtx *tctx = &t_arena_ctx; - tctx->perm_arena = AcquireArena(Gibi(64)); - for (i32 i = 0; i < (i32)countof(tctx->scratch_arenas); ++i) + Base_tl.arenas.perm = AcquireArena(Gibi(64)); + for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i) { - tctx->scratch_arenas[i] = AcquireArena(Gibi(64)); + Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64)); } } - Arena *perm = PermArena(); + /* Set thread name */ wchar_t *thread_name_wstr = WstrFromString(perm, name); SetThreadDescription(GetCurrentThread(), thread_name_wstr); diff --git a/src/collider/collider.h b/src/collider/collider.h index 088b49de..3b9fb395 100644 --- a/src/collider/collider.h +++ b/src/collider/collider.h @@ -138,15 +138,15 @@ Struct(CLD_EpaData) #if COLLIDER_DEBUG void CLD_DebugBreakable(void); -#define CLD_DBGSTEP \ - dbg_step++; \ - if (dbg_step >= GetGstat(GSTAT_DEBUG_STEPS)) \ - { \ - goto abort; \ - } \ - else if (dbg_step >= GetGstat(GSTAT_DEBUG_STEPS) - 1) \ - { \ - CLD_DebugBreakable(); \ +#define CLD_DBGSTEP \ + dbg_step++; \ + if (dbg_step >= GetGstat(DebugSteps)) \ + { \ + goto abort; \ + } \ + else if (dbg_step >= GetGstat(DebugSteps) - 1) \ + { \ + CLD_DebugBreakable(); \ } (void)0 #else #define CLD_DBGSTEP diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index 8ba0d2a5..ad3eb503 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -3,7 +3,7 @@ GC_State GC = ZI; //////////////////////////////////////////////////////////// //~ Bootstrap -void GC_BootStrap(void) +void GC_Bootstrap(void) { OnAsyncTick(GC_AsyncTick); } diff --git a/src/glyph_cache/glyph_cache.lay b/src/glyph_cache/glyph_cache.lay index 2f625b90..14a9c1e5 100644 --- a/src/glyph_cache/glyph_cache.lay +++ b/src/glyph_cache/glyph_cache.lay @@ -11,6 +11,8 @@ @IncludeC glyph_cache.h +@Bootstrap GC_Bootstrap + ////////////////////////////// //- Impl diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index 1c1ae1d6..0a04a386 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -2848,8 +2848,6 @@ void G_D12_CollectionWorkerEntryPoint(WaveLaneCtx *lane) { for (;;) { - P_SleepSeconds(0.100); - /* Copy print-buffers to readback */ for (G_QueueKind queue_kind = 0; queue_kind < G_NumQueues; ++queue_kind) { diff --git a/src/platform/platform.h b/src/platform/platform.h index 4610d06c..380f791f 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -137,6 +137,5 @@ i64 P_GetCurrentTimerPeriodNs(void); //////////////////////////////////////////////////////////// //~ @hookdecl Sleep -void P_SleepSeconds(f64 seconds); void P_SleepPrecise(i64 sleep_time_ns); void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns); diff --git a/src/platform/platform_win32/platform_win32.c b/src/platform/platform_win32/platform_win32.c index 99998fee..4fbf9711 100644 --- a/src/platform/platform_win32/platform_win32.c +++ b/src/platform/platform_win32/platform_win32.c @@ -838,7 +838,7 @@ P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock) result.address = P_W32_PlatformAddressFromWin32Address(ws_addr); if (size >= 0) { - AddGstat(GSTAT_SOCK_BYTES_RECEIVED, size); + AddGstat(SockBytesReceived, size); result.data.text = read_buff.text; result.data.len = size; result.valid = 1; @@ -867,7 +867,7 @@ void P_WriteSock(P_Sock *sock, P_Address address, String data) i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); if (size > 0) { - AddGstat(GSTAT_SOCK_BYTES_SENT, size); + AddGstat(SockBytesSent, size); } #if IsRtcEnabled if (size != (i32)data.len) @@ -978,11 +978,6 @@ i64 P_GetCurrentTimerPeriodNs(void) //////////////////////////////////////////////////////////// //~ @hookimpl Sleep -void P_SleepSeconds(f64 seconds) -{ - Sleep(seconds / 1000.0); -} - void P_SleepPrecise(i64 sleep_time_ns) { i64 now_ns = TimeNs();