aggregate base layer state

This commit is contained in:
jacob 2025-12-12 13:40:22 -06:00
parent ac8a4cf6c2
commit 476d154beb
28 changed files with 393 additions and 344 deletions

View File

@ -748,6 +748,7 @@
i64 TimeNs(void);
void TrueRand(String buffer);
CpuTopologyInfo GetCpuTopologyInfo(void);
void SleepSeconds(f64 seconds);
#endif
////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -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,10 +61,10 @@ 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 { \

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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))
{

View File

@ -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

View File

@ -1,3 +0,0 @@
#if GstatIsEnabled
SharedGstatCtx _shared_gstat_ctx = ZI;
#endif

View File

@ -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

View File

@ -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

View File

@ -129,11 +129,6 @@ Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
# define LogDebugF(...)
#endif
////////////////////////////////////////////////////////////
//~ @hookdecl Bootstrap
void BootstrapLogs(String logfile_path);
////////////////////////////////////////////////////////////
//~ @hookdecl Log

View File

@ -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)

View File

@ -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

2
src/base/base_state.c Normal file
View File

@ -0,0 +1,2 @@
BaseState Base = ZI;
ThreadLocal BaseThreadLocalState Base_tl = ZI;

59
src/base/base_state.h Normal file
View File

@ -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;

View File

@ -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

View File

@ -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);
}
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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"

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -140,11 +140,11 @@ void CLD_DebugBreakable(void);
#define CLD_DBGSTEP \
dbg_step++; \
if (dbg_step >= GetGstat(GSTAT_DEBUG_STEPS)) \
if (dbg_step >= GetGstat(DebugSteps)) \
{ \
goto abort; \
} \
else if (dbg_step >= GetGstat(GSTAT_DEBUG_STEPS) - 1) \
else if (dbg_step >= GetGstat(DebugSteps) - 1) \
{ \
CLD_DebugBreakable(); \
} (void)0

View File

@ -3,7 +3,7 @@ GC_State GC = ZI;
////////////////////////////////////////////////////////////
//~ Bootstrap
void GC_BootStrap(void)
void GC_Bootstrap(void)
{
OnAsyncTick(GC_AsyncTick);
}

View File

@ -11,6 +11,8 @@
@IncludeC glyph_cache.h
@Bootstrap GC_Bootstrap
//////////////////////////////
//- Impl

View File

@ -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)
{

View File

@ -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);

View File

@ -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();