simplification pass over os core layer; simplification pass over base arena; set up build.sh; stub out new spot for linux os core

This commit is contained in:
Ryan Fleury
2024-07-15 17:23:01 -07:00
parent 6447a2a993
commit 1b74fb0760
58 changed files with 66001 additions and 66756 deletions
+137 -137
View File
@@ -1,137 +1,137 @@
@echo off @echo off
setlocal setlocal
cd /D "%~dp0" cd /D "%~dp0"
:: --- Usage Notes (2024/1/10) ------------------------------------------------ :: --- Usage Notes (2024/1/10) ------------------------------------------------
:: ::
:: This is a central build script for the RAD Debugger project. It takes a list :: This is a central build script for the RAD Debugger project, for use in
:: of simple alphanumeric-only arguments which control (a) what is built, (b) :: Windows development environments. It takes a list of simple alphanumeric-
:: which compiler & linker are used, and (c) extra high-level build options. By :: only arguments which control (a) what is built, (b) which compiler & linker
:: default, if no options are passed, then the main "raddbg" graphical debugger :: are used, and (c) extra high-level build options. By default, if no options
:: is built. :: are passed, then the main "raddbg" graphical debugger is built.
:: ::
:: Below is a non-exhaustive list of possible ways to use the script: :: Below is a non-exhaustive list of possible ways to use the script:
:: `build raddbg` :: `build raddbg`
:: `build raddbg clang` :: `build raddbg clang`
:: `build raddbg release` :: `build raddbg release`
:: `build raddbg asan telemetry` :: `build raddbg asan telemetry`
:: `build rdi_from_pdb` :: `build rdi_from_pdb`
:: ::
:: For a full list of possible build targets and their build command lines, :: For a full list of possible build targets and their build command lines,
:: search for @build_targets in this file. :: search for @build_targets in this file.
:: ::
:: Below is a list of all possible non-target command line options: :: Below is a list of all possible non-target command line options:
:: ::
:: - `asan`: enable address sanitizer :: - `asan`: enable address sanitizer
:: - `telemetry`: enable RAD telemetry profiling support :: - `telemetry`: enable RAD telemetry profiling support
:: --- Unpack Arguments ------------------------------------------------------- :: --- Unpack Arguments -------------------------------------------------------
for %%a in (%*) do set "%%a=1" for %%a in (%*) do set "%%a=1"
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1 if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
if not "%release%"=="1" set debug=1 if not "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug mode] if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode] if "%release%"=="1" set debug=0 && echo [release mode]
if "%msvc%"=="1" set clang=0 && echo [msvc compile] if "%msvc%"=="1" set clang=0 && echo [msvc compile]
if "%clang%"=="1" set msvc=0 && echo [clang compile] if "%clang%"=="1" set msvc=0 && echo [clang compile]
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1 if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1 if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
:: --- Unpack Command Line Build Arguments ------------------------------------ :: --- Unpack Command Line Build Arguments ------------------------------------
set auto_compile_flags= set auto_compile_flags=
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
:: --- Compile/Link Line Definitions ------------------------------------------ :: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags% set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
set cl_out= /out: set cl_out= /out:
set clang_out= -o set clang_out= -o
:: --- Per-Build Settings ----------------------------------------------------- :: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL set link_dll=-DLL
if "%msvc%"=="1" set only_compile=/c if "%msvc%"=="1" set only_compile=/c
if "%clang%"=="1" set only_compile=-c if "%clang%"=="1" set only_compile=-c
if "%msvc%"=="1" set EHsc=/EHsc if "%msvc%"=="1" set EHsc=/EHsc
if "%clang%"=="1" set EHsc= if "%clang%"=="1" set EHsc=
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc if "%clang%"=="1" set rc=call llvm-rc
:: --- Choose Compile/Link Lines ---------------------------------------------- :: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug% if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release% if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link% if "%msvc%"=="1" set compile_link=%cl_link%
if "%msvc%"=="1" set out=%cl_out% if "%msvc%"=="1" set out=%cl_out%
if "%clang%"=="1" set compile_debug=%clang_debug% if "%clang%"=="1" set compile_debug=%clang_debug%
if "%clang%"=="1" set compile_release=%clang_release% if "%clang%"=="1" set compile_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link% if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out% if "%clang%"=="1" set out=%clang_out%
if "%debug%"=="1" set compile=%compile_debug% if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release% if "%release%"=="1" set compile=%compile_release%
:: --- Prep Directories ------------------------------------------------------- :: --- Prep Directories -------------------------------------------------------
if not exist build mkdir build if not exist build mkdir build
if not exist local mkdir local if not exist local mkdir local
:: --- Produce Logo Icon File ------------------------------------------------- :: --- Produce Logo Icon File -------------------------------------------------
pushd build pushd build
%rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1 %rc% /nologo /fo logo.res ..\data\logo.rc || exit /b 1
popd popd
:: --- Get Current Git Commit Id ---------------------------------------------- :: --- Get Current Git Commit Id ----------------------------------------------
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\" for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
:: --- Build & Run Metaprogram ------------------------------------------------ :: --- Build & Run Metaprogram ------------------------------------------------
if "%no_meta%"=="1" echo [skipping metagen] if "%no_meta%"=="1" echo [skipping metagen]
if not "%no_meta%"=="1" ( if not "%no_meta%"=="1" (
pushd build pushd build
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1 %compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
metagen.exe || exit /b 1 metagen.exe || exit /b 1
popd popd
) )
:: --- Build Everything (@build_targets) -------------------------------------- :: --- Build Everything (@build_targets) --------------------------------------
pushd build pushd build
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %out%raddbg.exe || exit /b 1 if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %out%raddbg.exe || exit /b 1
if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1 if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1
if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1
if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1 if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1
if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1 if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
if "%cpp_tests%"=="1" set didbuild=1 && %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 if "%cpp_tests%"=="1" set didbuild=1 && %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
if "%look_at_raddbg%"=="1" set didbuild=1 && %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 if "%look_at_raddbg%"=="1" set didbuild=1 && %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
if "%mule_peb_trample%"=="1" ( if "%mule_peb_trample%"=="1" (
set didbuild=1 set didbuild=1
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1 %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
move mule_peb_trample_new.exe mule_peb_trample.exe move mule_peb_trample_new.exe mule_peb_trample.exe
) )
popd popd
:: --- Unset ------------------------------------------------------------------ :: --- Unset ------------------------------------------------------------------
for %%a in (%*) do set "%%a=0" for %%a in (%*) do set "%%a=0"
set raddbg= set raddbg=
set compile= set compile=
set compile_link= set compile_link=
set out= set out=
set msvc= set msvc=
set debug= set debug=
set release= set release=
:: --- Warn On No Builds ------------------------------------------------------ :: --- Warn On No Builds ------------------------------------------------------
if "%didbuild%"=="" ( if "%didbuild%"=="" (
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`. echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
exit /b 1 exit /b 1
) )
+57
View File
@@ -0,0 +1,57 @@
#!/bin/bash
# --- Unpack Arguments --------------------------------------------------------
for arg in "$@"; do declare $arg='1'; done
if [ ! "$gcc" = "1" ]; then clang=1; fi
if [ ! "$release" = "1" ]; then debug=1; fi
if [ "$debug" = "1" ]; then release=0 && echo "[debug mode]"; fi
if [ "$release" = "1" ]; then debug=0 && echo "[release mode]"; fi
if [ "$clang" = "1" ]; then gcc=0 && echo "[clang compile]"; fi
if [ "$gcc" = "1" ]; then clang=0 && echo "[gcc compile]"; fi
# --- Unpack Command Line Build Arguments -------------------------------------
auto_compile_flags=''
# --- Compile/Link Line Definitions -------------------------------------------
clang_common='-I../src/ -I../local/ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf'
clang_debug="clang -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="clang -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link=""
clang_out="-o"
# --- Per-Build Settings ------------------------------------------------------
link_dll="-fPIC"
# --- Choose Compile/Link Lines -----------------------------------------------
if [ "$clang" = "1" ]; then compile_debug="$clang_debug"; fi
if [ "$clang" = "1" ]; then compile_release="$clang_release"; fi
if [ "$clang" = "1" ]; then compile_link="$clang_link"; fi
if [ "$clang" = "1" ]; then out="$clang_out"; fi
if [ "$debug" = "1" ]; then compile="$compile_debug"; fi
if [ "$release" = "1" ]; then compile="$compile_release"; fi
# --- Prep Directories --------------------------------------------------------
if [ ! -d build ]; then mkdir build; fi
if [ ! -d local ]; then mkdir local; fi
# --- Build & Run Metaprogram -------------------------------------------------
if [ "$no_meta" = "1" ]; then echo "[skipping metagen]"; fi
if [ "$no_meta" = "" ]
then
cd build
$compile_debug ../src/metagen/metagen_main.c $compile_link $out metagen || exit 1
metagen || exit 1
cd ..
fi
# --- Build Everything (@build_targets) ---------------------------------------
cd build
if [ "$raddbg" = "1" ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $out raddbg || exit 1; fi
cd ..
# --- Warn On No Builds -------------------------------------------------------
#if [ "$didbuild" = "" ]
#then
# echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like `./build.sh raddbg` or `./build.sh rdi_from_pdb`."
# exit 1
#fi
+195 -302
View File
@@ -1,302 +1,195 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
// Implementation //~ rjf: Arena Functions
internal Arena * //- rjf: arena creation/destruction
arena_alloc__sized(U64 init_res, U64 init_cmt)
{ internal Arena *
ProfBeginFunction(); arena_alloc_(ArenaParams *params)
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res); {
// rjf: round up reserve/commit sizes
void *memory = 0; U64 reserve_size = params->reserve_size;
U64 res = 0; U64 commit_size = params->commit_size;
U64 cmt = 0; if(params->flags & ArenaFlag_LargePages)
B32 large_pages = os_large_pages_enabled(); {
if(large_pages) reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
{ commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
U64 page_size = os_large_page_size(); }
res = AlignPow2(init_res, page_size); else
#if OS_WINDOWS {
cmt = res; reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
#else commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
cmt = AlignPow2(init_cmt, page_size); }
#endif
memory = os_reserve_large(res); // rjf: reserve/commit initial block
if(!os_commit_large(memory, cmt)) void *base = params->optional_backing_buffer;
{ if(base == 0)
memory = 0; {
os_release(memory, res); if(params->flags & ArenaFlag_LargePages)
} {
} base = os_reserve_large(reserve_size);
else os_commit_large(base, commit_size);
{ }
U64 page_size = os_page_size(); else
res = AlignPow2(init_res, page_size); {
cmt = AlignPow2(init_cmt, page_size); base = os_reserve(reserve_size);
memory = os_reserve(res); os_commit(base, commit_size);
if(!os_commit(memory, cmt)) }
{ }
memory = 0;
os_release(memory, res); // rjf: panic on arena creation failure
} #if OS_FEATURE_GRAPHICAL
} if(Unlikely(base == 0))
{
Arena *arena = (Arena*)memory; os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
if(arena) os_abort(1);
{ }
AsanPoisonMemoryRegion(memory, cmt); #endif
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
arena->prev = 0; // rjf: extract arena header & fill
arena->current = arena; Arena *arena = (Arena *)base;
arena->base_pos = 0; arena->current = arena;
arena->pos = ARENA_HEADER_SIZE; arena->flags = params->flags;
arena->cmt = cmt; arena->cmt_size = (U32)params->commit_size;
arena->res = res; arena->res_size = params->reserve_size;
arena->align = 8; arena->base_pos = 0;
arena->grow = 1; arena->pos = ARENA_HEADER_SIZE;
arena->large_pages = large_pages; arena->cmt = commit_size;
} arena->res = reserve_size;
AsanPoisonMemoryRegion(base, commit_size);
ProfEnd(); AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
return arena; return arena;
} }
internal Arena * internal void
arena_alloc(void) arena_release(Arena *arena)
{ {
ProfBeginFunction(); for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
{
U64 init_res, init_cmt; prev = n->prev;
if (os_large_pages_enabled()) { os_release(n, n->res);
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES; }
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES; }
} else {
init_res = ARENA_RESERVE_SIZE; //- rjf: arena push/pop core functions
init_cmt = ARENA_COMMIT_SIZE;
} internal void *
arena_push(Arena *arena, U64 size, U64 align)
Arena *arena = arena_alloc__sized(init_res, init_cmt); {
Arena *current = arena->current;
ProfEnd(); U64 pos_pre = AlignPow2(current->pos, align);
return arena; U64 pos_pst = pos_pre + size;
}
// rjf: chain, if needed
internal void if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
arena_release(Arena *arena) {
{ U64 res_size = current->res_size;
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) { U64 cmt_size = current->cmt_size;
prev = node->prev; if(size > cmt_size)
os_release(node, node->res); {
} res_size = size + ARENA_HEADER_SIZE;
} cmt_size = size + ARENA_HEADER_SIZE;
}
internal U64 Arena *new_block = arena_alloc(.reserve_size = res_size,
arena_huge_push_threshold(void) .commit_size = cmt_size,
{ .flags = current->flags);
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE; new_block->base_pos = current->base_pos + current->res;
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1; SLLStackPush_N(arena->current, new_block, prev);
return threshold; current = new_block;
} pos_pre = AlignPow2(current->pos, align);
pos_pst = pos_pst + size;
internal void * }
arena_push__impl(Arena *arena, U64 size)
{ // rjf: commit new pages, if needed
Arena *current = arena->current; if(current->cmt < pos_pst && !(current->flags & ArenaFlag_LargePages))
U64 pos_mem = AlignPow2(current->pos, arena->align); {
U64 pos_new = pos_mem + size; U64 cmt_pst_aligned = AlignPow2(pos_pst, current->cmt_size);
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
if (current->res < pos_new && arena->grow) { U64 cmt_size = cmt_pst_clamped - current->cmt;
Arena *new_block; os_commit((U8 *)current + current->cmt, cmt_size);
current->cmt = cmt_pst_clamped;
// normal growth path }
if (size < arena_huge_push_threshold()) {
new_block = arena_alloc(); // rjf: push onto current block
} void *result = 0;
// huge growth path if(current->cmt >= pos_pst)
else { {
U64 new_block_size = size + ARENA_HEADER_SIZE; result = (U8 *)current+pos_pre;
new_block = arena_alloc__sized(new_block_size, new_block_size); current->pos = pos_pst;
} AsanUnpoisonMemoryRegion(result, size);
}
if (new_block) {
new_block->base_pos = current->base_pos + current->res; // rjf: panic on failure
SLLStackPush_N(arena->current, new_block, prev); #if OS_FEATURE_GRAPHICAL
if(Unlikely(result == 0))
current = new_block; {
pos_mem = AlignPow2(current->pos, current->align); os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
pos_new = pos_mem + size; os_abort(1);
} }
} #endif
if (current->cmt < pos_new) { return result;
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size; }
B32 is_cmt_ok;
internal U64
if (current->large_pages) { arena_pos(Arena *arena)
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES); {
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); Arena *current = arena->current;
cmt_new_size = cmt_new_clamped - current->cmt; U64 pos = current->base_pos + current->pos;
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size); return pos;
} else { }
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res); internal void
cmt_new_size = cmt_new_clamped - current->cmt; arena_pop_to(Arena *arena, U64 pos)
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size); {
} U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
Arena *current = arena->current;
if (is_cmt_ok) { for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
current->cmt = cmt_new_clamped; {
} prev = current->prev;
} os_release(current, current->res);
}
void *memory = 0; arena->current = current;
U64 new_pos = big_pos - current->base_pos;
if (current->cmt >= pos_new) { AssertAlways(new_pos <= current->pos);
memory = (U8*)current + pos_mem; AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
current->pos = pos_new; current->pos = new_pos;
AsanUnpoisonMemoryRegion(memory, size); }
}
//- rjf: arena push/pop helpers
#if OS_FEATURE_GRAPHICAL
if(Unlikely(memory == 0)) internal void
{ arena_clear(Arena *arena)
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure.")); {
os_exit_process(1); arena_pop_to(arena, 0);
} }
#endif
internal void
return memory; arena_pop(Arena *arena, U64 amt)
} {
U64 pos_old = arena_pos(arena);
internal U64 U64 pos_new = pos_old;
arena_pos(Arena *arena) if(amt < pos_old)
{ {
Arena *current = arena->current; pos_new = pos_old - amt;
U64 pos = current->base_pos + current->pos; }
return pos; arena_pop_to(arena, pos_new);
} }
internal void //- rjf: temporary arena scopes
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
{ internal Temp
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped); temp_begin(Arena *arena)
{
// unroll the chain U64 pos = arena_pos(arena);
Arena *current = arena->current; Temp temp = {arena, pos};
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) { return temp;
prev = current->prev; }
os_release(current, current->res);
} internal void
AssertAlways(current); temp_end(Temp temp)
arena->current = current; {
arena_pop_to(temp.arena, temp.pos);
// compute arena-relative position }
U64 new_pos = big_pos - current->base_pos;
AssertAlways(new_pos <= current->pos);
// poison popped memory block
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
// update position
current->pos = new_pos;
}
internal void
arena_absorb(Arena *arena, Arena *sub)
{
// base adjustment
Arena *current = arena->current;
U64 base_adjust = current->base_pos + current->res;
for (Arena *node = sub->current; node != 0; node = node->prev) {
node->base_pos += base_adjust;
}
// attach sub to arena
sub->prev = arena->current;
arena->current = sub->current;
sub->current = sub;
}
////////////////////////////////
// Wrappers
internal void *
arena_push(Arena *arena, U64 size)
{
void *memory = arena_push__impl(arena, size);
return memory;
}
internal void *
arena_push_contiguous(Arena *arena, U64 size)
{
B32 restore = arena->grow;
arena->grow = 0;
void *memory = arena_push(arena, size);
arena->grow = restore;
return memory;
}
internal void
arena_push_align(Arena *arena, U64 align)
{
Assert(IsPow2(align));
U64 amt = AlignPadPow2(arena->pos, align);
void *ptr = arena_push(arena, amt);
MemoryZero(ptr, amt);
}
internal void
arena_put_back(Arena *arena, U64 amt)
{
U64 pos_old = arena_pos(arena);
U64 pos_new = pos_old;
if (amt < pos_old) {
pos_new = pos_old - amt;
}
arena_pop_to(arena, pos_new);
}
internal void
arena_clear(Arena *arena)
{
arena_pop_to(arena, 0);
}
internal Temp
temp_begin(Arena *arena)
{
U64 pos = arena_pos(arena);
Temp temp = {arena, pos};
return temp;
}
internal void
temp_end(Temp temp)
{
arena_pop_to(temp.arena, temp.pos);
}
////////////////////////////////
//~ NOTE(allen): "Mini-Arena" Helper
internal B32
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
B32 result = 0;
U8 *cmt = (U8*)*cmtptr;
if (cmt < (U8*)pos){
U64 cmt_size_raw = (U8*)pos - cmt;
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
if (os_commit(cmt, cmt_size)){
*cmtptr = cmt + cmt_size;
result = 1;
}
}
else{
result = 1;
}
return(result);
}
+80 -87
View File
@@ -1,87 +1,80 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_ARENA_H #ifndef BASE_ARENA_H
#define BASE_ARENA_H #define BASE_ARENA_H
//////////////////////////////// ////////////////////////////////
//~ rjf: Constants //~ rjf: Constants
#define ARENA_HEADER_SIZE 128 #define ARENA_HEADER_SIZE 64
#ifndef ARENA_RESERVE_SIZE ////////////////////////////////
# define ARENA_RESERVE_SIZE MB(64) //~ rjf: Types
#endif
#ifndef ARENA_COMMIT_SIZE typedef U32 ArenaFlags;
# define ARENA_COMMIT_SIZE KB(64) enum
#endif {
ArenaFlag_NoChain = (1<<0),
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES ArenaFlag_LargePages = (1<<1),
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8) };
#endif
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES typedef struct ArenaParams ArenaParams;
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2) struct ArenaParams
#endif {
ArenaFlags flags;
//////////////////////////////// U64 reserve_size;
//~ rjf: Arena Types U64 commit_size;
void *optional_backing_buffer;
typedef struct Arena Arena; };
struct Arena
{ typedef struct Arena Arena;
struct Arena *prev; struct Arena
struct Arena *current; {
U64 base_pos; Arena *prev; // previous arena in chain
U64 pos; Arena *current; // current arena in chain
U64 cmt; ArenaFlags flags;
U64 res; U32 cmt_size;
U64 align; U64 res_size;
B8 grow; U64 base_pos;
B8 large_pages; U64 pos;
}; U64 cmt;
U64 res;
typedef struct Temp Temp; };
struct Temp StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
{
Arena *arena; typedef struct Temp Temp;
U64 pos; struct Temp
}; {
Arena *arena;
//////////////////////////////// U64 pos;
// Implementation };
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt); ////////////////////////////////
//~ rjf: Arena Functions
internal Arena* arena_alloc(void);
internal void arena_release(Arena *arena); //- rjf: arena creation/destruction
internal Arena *arena_alloc_(ArenaParams *params);
internal void* arena_push__impl(Arena *arena, U64 size); #define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = MB(64), .commit_size = KB(64), __VA_ARGS__})
internal U64 arena_pos(Arena *arena); internal void arena_release(Arena *arena);
internal void arena_pop_to(Arena *arena, U64 pos);
//- rjf: arena push/pop/pos core functions
internal void arena_absorb(Arena *arena, Arena *sub); internal void *arena_push(Arena *arena, U64 size, U64 align);
internal U64 arena_pos(Arena *arena);
//////////////////////////////// internal void arena_pop_to(Arena *arena, U64 pos);
// Wrappers
//- rjf: arena push/pop helpers
internal void* arena_push(Arena *arena, U64 size); internal void arena_clear(Arena *arena);
internal void* arena_push_contiguous(Arena *arena, U64 size); internal void arena_pop(Arena *arena, U64 amt);
internal void arena_clear(Arena *arena);
internal void arena_push_align(Arena *arena, U64 align); //- rjf: temporary arena scopes
internal void arena_put_back(Arena *arena, U64 amt); internal Temp temp_begin(Arena *arena);
internal void temp_end(Temp temp);
internal Temp temp_begin(Arena *arena);
internal void temp_end(Temp temp); //- rjf: push helper macros
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align))
//////////////////////////////// #define push_array_aligned(a, T, c, align) (T *)MemoryZero(push_array_no_zero_aligned(a, T, c, align), sizeof(T)*(c))
//~ NOTE(allen): "Mini-Arena" Helper #define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
#endif // BASE_ARENA_H
////////////////////////////////
//~ NOTE(allen): Main API Macros
#define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c))
#endif // BASE_ARENA_H
+801 -787
View File
File diff suppressed because it is too large Load Diff
+92 -95
View File
@@ -1,95 +1,92 @@
internal void // Copyright (c) 2024 Epic Games Tools
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count) // Licensed under the MIT license (https://opensource.org/license/mit/)
{
#if PROFILE_TELEMETRY internal void
local_persist U8 tm_data[MB(64)]; main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
tmLoadLibrary(TM_RELEASE); {
tmSetMaxThreadCount(256); #if PROFILE_TELEMETRY
tmInitialize(sizeof(tm_data), (char *)tm_data); local_persist U8 tm_data[MB(64)];
#endif tmLoadLibrary(TM_RELEASE);
TCTX tctx; tmSetMaxThreadCount(256);
tctx_init_and_equip(&tctx); tmInitialize(sizeof(tm_data), (char *)tm_data);
ThreadNameF("[main thread]"); #endif
Temp scratch = scratch_begin(0, 0); ThreadNameF("[main thread]");
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments); Temp scratch = scratch_begin(0, 0);
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings); String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture")); CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
if(capture) B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
{ if(capture)
ProfBeginCapture(arguments[0]); {
} ProfBeginCapture(arguments[0]);
#if defined(OS_CORE_H) && !defined(OS_INIT_MANUAL) }
os_init(); #if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
#endif ts_init();
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL) #endif
ts_init(); #if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL)
#endif hs_init();
#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) #endif
hs_init(); #if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
#endif fs_init();
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) #endif
fs_init(); #if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL)
#endif txt_init();
#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL) #endif
txt_init(); #if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
#endif mtx_init();
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL) #endif
mtx_init(); #if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL)
#endif dasm_init();
#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) #endif
dasm_init(); #if defined(DI_H) && !defined(DI_INIT_MANUAL)
#endif di_init();
#if defined(DI_H) && !defined(DI_INIT_MANUAL) #endif
di_init(); #if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL)
#endif fzy_init();
#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL) #endif
fzy_init(); #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
#endif dmn_init();
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) #endif
dmn_init(); #if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL)
#endif ctrl_init();
#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) #endif
ctrl_init(); #if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL)
#endif os_gfx_init();
#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL) #endif
os_graphical_init(); #if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
#endif fp_init();
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) #endif
fp_init(); #if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
#endif r_init(&cmdline);
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) #endif
r_init(&cmdline); #if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL)
#endif tex_init();
#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL) #endif
tex_init(); #if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL)
#endif geo_init();
#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) #endif
geo_init(); #if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL)
#endif f_init();
#if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL) #endif
f_init(); #if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL)
#endif DF_StateDeltaHistory *hist = df_state_delta_history_alloc();
#if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL) df_core_init(&cmdline, hist);
DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); #endif
df_core_init(&cmdline, hist); #if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL)
#endif df_gfx_init(update_and_render, df_state_delta_history());
#if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL) #endif
df_gfx_init(update_and_render, df_state_delta_history()); entry_point(&cmdline);
#endif if(capture)
entry_point(&cmdline); {
if(capture) ProfEndCapture();
{ }
ProfEndCapture(); scratch_end(scratch);
} }
scratch_end(scratch);
tctx_release(); internal void
} supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
{
internal void TCTX tctx;
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params) tctx_init_and_equip(&tctx);
{ entry_point(params);
TCTX tctx; tctx_release();
tctx_init_and_equip(&tctx); }
entry_point(params);
tctx_release();
}
+1975 -1975
View File
File diff suppressed because it is too large Load Diff
+41 -41
View File
@@ -1,41 +1,41 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef BASE_THREAD_CONTEXT_H #ifndef BASE_THREAD_CONTEXT_H
#define BASE_THREAD_CONTEXT_H #define BASE_THREAD_CONTEXT_H
//////////////////////////////// ////////////////////////////////
// NOTE(allen): Thread Context // NOTE(allen): Thread Context
typedef struct TCTX TCTX; typedef struct TCTX TCTX;
struct TCTX struct TCTX
{ {
Arena *arenas[2]; Arena *arenas[2];
U8 thread_name[32]; U8 thread_name[32];
U64 thread_name_size; U64 thread_name_size;
char *file_name; char *file_name;
U64 line_number; U64 line_number;
}; };
//////////////////////////////// ////////////////////////////////
// NOTE(allen): Thread Context Functions // NOTE(allen): Thread Context Functions
internal void tctx_init_and_equip(TCTX *tctx); internal void tctx_init_and_equip(TCTX *tctx);
internal void tctx_release(void); internal void tctx_release(void);
internal TCTX* tctx_get_equipped(void); internal TCTX* tctx_get_equipped(void);
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
internal void tctx_set_thread_name(String8 name); internal void tctx_set_thread_name(String8 name);
internal String8 tctx_get_thread_name(void); internal String8 tctx_get_thread_name(void);
internal void tctx_write_srcloc(char *file_name, U64 line_number); internal void tctx_write_srcloc(char *file_name, U64 line_number);
internal void tctx_read_srcloc(char **file_name, U64 *line_number); internal void tctx_read_srcloc(char **file_name, U64 *line_number);
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__) #define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count))) #define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
#define scratch_end(scratch) temp_end(scratch) #define scratch_end(scratch) temp_end(scratch)
#endif //BASE_THREAD_CONTEXT_H #endif // BASE_THREAD_CONTEXT_H
+637 -638
View File
File diff suppressed because it is too large Load Diff
+3017 -3017
View File
File diff suppressed because it is too large Load Diff
+1119 -1119
View File
File diff suppressed because it is too large Load Diff
+5296 -5296
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+883 -883
View File
File diff suppressed because it is too large Load Diff
+242 -242
View File
@@ -1,242 +1,242 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DEMON_CORE_H #ifndef DEMON_CORE_H
#define DEMON_CORE_H #define DEMON_CORE_H
//////////////////////////////// ////////////////////////////////
//~ rjf: Control-Thread-Only Context //~ rjf: Control-Thread-Only Context
// //
// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only // An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only
// used by the thread which called it. All APIs which can ONLY run on the // used by the thread which called it. All APIs which can ONLY run on the
// control thread, which blocks to control & receive events, will take this // control thread, which blocks to control & receive events, will take this
// parameter. All other APIs can be called from any thread. // parameter. All other APIs can be called from any thread.
typedef struct DMN_CtrlCtx DMN_CtrlCtx; typedef struct DMN_CtrlCtx DMN_CtrlCtx;
struct DMN_CtrlCtx struct DMN_CtrlCtx
{ {
U64 u64[1]; U64 u64[1];
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Handle Types //~ rjf: Handle Types
typedef union DMN_Handle DMN_Handle; typedef union DMN_Handle DMN_Handle;
union DMN_Handle union DMN_Handle
{ {
U32 u32[2]; U32 u32[2];
U64 u64[1]; U64 u64[1];
}; };
typedef struct DMN_HandleNode DMN_HandleNode; typedef struct DMN_HandleNode DMN_HandleNode;
struct DMN_HandleNode struct DMN_HandleNode
{ {
DMN_HandleNode *next; DMN_HandleNode *next;
DMN_Handle v; DMN_Handle v;
}; };
typedef struct DMN_HandleList DMN_HandleList; typedef struct DMN_HandleList DMN_HandleList;
struct DMN_HandleList struct DMN_HandleList
{ {
DMN_HandleNode *first; DMN_HandleNode *first;
DMN_HandleNode *last; DMN_HandleNode *last;
U64 count; U64 count;
}; };
typedef struct DMN_HandleArray DMN_HandleArray; typedef struct DMN_HandleArray DMN_HandleArray;
struct DMN_HandleArray struct DMN_HandleArray
{ {
DMN_Handle *handles; DMN_Handle *handles;
U64 count; U64 count;
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Generated Code //~ rjf: Generated Code
#include "generated/demon.meta.h" #include "generated/demon.meta.h"
//////////////////////////////// ////////////////////////////////
//~ rjf: Event Types //~ rjf: Event Types
typedef struct DMN_Event DMN_Event; typedef struct DMN_Event DMN_Event;
struct DMN_Event struct DMN_Event
{ {
DMN_EventKind kind; DMN_EventKind kind;
DMN_ErrorKind error_kind; DMN_ErrorKind error_kind;
DMN_MemoryEventKind memory_kind; DMN_MemoryEventKind memory_kind;
DMN_ExceptionKind exception_kind; DMN_ExceptionKind exception_kind;
DMN_Handle process; DMN_Handle process;
DMN_Handle thread; DMN_Handle thread;
DMN_Handle module; DMN_Handle module;
Architecture arch; Architecture arch;
U64 address; U64 address;
U64 size; U64 size;
String8 string; String8 string;
U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully) U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully)
U32 flags; U32 flags;
S32 signo; S32 signo;
S32 sigcode; S32 sigcode;
U64 instruction_pointer; U64 instruction_pointer;
U64 stack_pointer; U64 stack_pointer;
U64 user_data; U64 user_data;
B32 exception_repeated; B32 exception_repeated;
}; };
typedef struct DMN_EventNode DMN_EventNode; typedef struct DMN_EventNode DMN_EventNode;
struct DMN_EventNode struct DMN_EventNode
{ {
DMN_EventNode *next; DMN_EventNode *next;
DMN_Event v; DMN_Event v;
}; };
typedef struct DMN_EventList DMN_EventList; typedef struct DMN_EventList DMN_EventList;
struct DMN_EventList struct DMN_EventList
{ {
DMN_EventNode *first; DMN_EventNode *first;
DMN_EventNode *last; DMN_EventNode *last;
U64 count; U64 count;
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Run Control Types //~ rjf: Run Control Types
typedef struct DMN_Trap DMN_Trap; typedef struct DMN_Trap DMN_Trap;
struct DMN_Trap struct DMN_Trap
{ {
DMN_Handle process; DMN_Handle process;
U64 vaddr; U64 vaddr;
U64 id; U64 id;
}; };
typedef struct DMN_TrapChunkNode DMN_TrapChunkNode; typedef struct DMN_TrapChunkNode DMN_TrapChunkNode;
struct DMN_TrapChunkNode struct DMN_TrapChunkNode
{ {
DMN_TrapChunkNode *next; DMN_TrapChunkNode *next;
DMN_Trap *v; DMN_Trap *v;
U64 cap; U64 cap;
U64 count; U64 count;
}; };
typedef struct DMN_TrapChunkList DMN_TrapChunkList; typedef struct DMN_TrapChunkList DMN_TrapChunkList;
struct DMN_TrapChunkList struct DMN_TrapChunkList
{ {
DMN_TrapChunkNode *first; DMN_TrapChunkNode *first;
DMN_TrapChunkNode *last; DMN_TrapChunkNode *last;
U64 node_count; U64 node_count;
U64 trap_count; U64 trap_count;
}; };
typedef struct DMN_RunCtrls DMN_RunCtrls; typedef struct DMN_RunCtrls DMN_RunCtrls;
struct DMN_RunCtrls struct DMN_RunCtrls
{ {
DMN_Handle single_step_thread; DMN_Handle single_step_thread;
B8 ignore_previous_exception; B8 ignore_previous_exception;
B8 run_entities_are_unfrozen; B8 run_entities_are_unfrozen;
B8 run_entities_are_processes; B8 run_entities_are_processes;
DMN_Handle *run_entities; DMN_Handle *run_entities;
U64 run_entity_count; U64 run_entity_count;
DMN_TrapChunkList traps; DMN_TrapChunkList traps;
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: System Process Listing Types //~ rjf: System Process Listing Types
typedef struct DMN_ProcessIter DMN_ProcessIter; typedef struct DMN_ProcessIter DMN_ProcessIter;
struct DMN_ProcessIter struct DMN_ProcessIter
{ {
U64 v[2]; U64 v[2];
}; };
typedef struct DMN_ProcessInfo DMN_ProcessInfo; typedef struct DMN_ProcessInfo DMN_ProcessInfo;
struct DMN_ProcessInfo struct DMN_ProcessInfo
{ {
String8 name; String8 name;
U32 pid; U32 pid;
}; };
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Type Functions (Helpers, Implemented Once) //~ rjf: Basic Type Functions (Helpers, Implemented Once)
//- rjf: handles //- rjf: handles
internal DMN_Handle dmn_handle_zero(void); internal DMN_Handle dmn_handle_zero(void);
internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b); internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b);
//- rjf: trap chunk lists //- rjf: trap chunk lists
internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap); internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap);
internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push); internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push); internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push);
//- rjf: handle lists //- rjf: handle lists
internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle); internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle);
internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list); internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list);
internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src); internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src);
//- rjf: event list building //- rjf: event list building
internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list); internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list);
//////////////////////////////// ////////////////////////////////
//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once) //~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once)
internal U64 dmn_rip_from_thread(DMN_Handle thread); internal U64 dmn_rip_from_thread(DMN_Handle thread);
internal U64 dmn_rsp_from_thread(DMN_Handle thread); internal U64 dmn_rsp_from_thread(DMN_Handle thread);
//////////////////////////////// ////////////////////////////////
//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) //~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS)
internal void dmn_init(void); internal void dmn_init(void);
//////////////////////////////// ////////////////////////////////
//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS)
internal DMN_CtrlCtx *dmn_ctrl_begin(void); internal DMN_CtrlCtx *dmn_ctrl_begin(void);
internal void dmn_ctrl_exclusive_access_begin(void); internal void dmn_ctrl_exclusive_access_begin(void);
internal void dmn_ctrl_exclusive_access_end(void); internal void dmn_ctrl_exclusive_access_end(void);
#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end()) #define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end())
internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options); internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params);
internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid); internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid);
internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code); internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code);
internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process); internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process);
internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls); internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls);
//////////////////////////////// ////////////////////////////////
//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) //~ rjf: @dmn_os_hooks Halting (Implemented Per-OS)
internal void dmn_halt(U64 code, U64 user_data); internal void dmn_halt(U64 code, U64 user_data);
//////////////////////////////// ////////////////////////////////
//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) //~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS)
//- rjf: run/memory/register counters //- rjf: run/memory/register counters
internal U64 dmn_run_gen(void); internal U64 dmn_run_gen(void);
internal U64 dmn_mem_gen(void); internal U64 dmn_mem_gen(void);
internal U64 dmn_reg_gen(void); internal U64 dmn_reg_gen(void);
//- rjf: non-blocking-control-thread access barriers //- rjf: non-blocking-control-thread access barriers
internal B32 dmn_access_open(void); internal B32 dmn_access_open(void);
internal void dmn_access_close(void); internal void dmn_access_close(void);
#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close()) #define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close())
//- rjf: processes //- rjf: processes
internal U64 dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size); internal U64 dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size);
internal void dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_commit(DMN_Handle process, U64 vaddr, U64 size);
internal void dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_decommit(DMN_Handle process, U64 vaddr, U64 size);
internal void dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size); internal void dmn_process_memory_release(DMN_Handle process, U64 vaddr, U64 size);
internal void dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFlags flags); internal void dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFlags flags);
internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
//- rjf: threads //- rjf: threads
internal Architecture dmn_arch_from_thread(DMN_Handle handle); internal Architecture dmn_arch_from_thread(DMN_Handle handle);
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
//- rjf: system process listing //- rjf: system process listing
internal void dmn_process_iter_begin(DMN_ProcessIter *iter); internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out); internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out);
internal void dmn_process_iter_end(DMN_ProcessIter *iter); internal void dmn_process_iter_end(DMN_ProcessIter *iter);
#endif // DEMON_CORE_H #endif // DEMON_CORE_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+9312 -9357
View File
File diff suppressed because it is too large Load Diff
+1829 -1834
View File
File diff suppressed because it is too large Load Diff
+9461 -9461
View File
File diff suppressed because it is too large Load Diff
+641 -641
View File
File diff suppressed because it is too large Load Diff
+310 -310
View File
@@ -1,310 +1,310 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Top-Level API //~ rjf: Top-Level API
internal void internal void
fs_init(void) fs_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
fs_shared = push_array(arena, FS_Shared, 1); fs_shared = push_array(arena, FS_Shared, 1);
fs_shared->arena = arena; fs_shared->arena = arena;
fs_shared->change_gen = 1; fs_shared->change_gen = 1;
fs_shared->slots_count = 1024; fs_shared->slots_count = 1024;
fs_shared->stripes_count = os_logical_core_count(); fs_shared->stripes_count = os_get_system_info()->logical_processor_count;
fs_shared->slots = push_array(arena, FS_Slot, fs_shared->slots_count); fs_shared->slots = push_array(arena, FS_Slot, fs_shared->slots_count);
fs_shared->stripes = push_array(arena, FS_Stripe, fs_shared->stripes_count); fs_shared->stripes = push_array(arena, FS_Stripe, fs_shared->stripes_count);
for(U64 idx = 0; idx < fs_shared->stripes_count; idx += 1) for(U64 idx = 0; idx < fs_shared->stripes_count; idx += 1)
{ {
fs_shared->stripes[idx].arena = arena_alloc(); fs_shared->stripes[idx].arena = arena_alloc();
fs_shared->stripes[idx].cv = os_condition_variable_alloc(); fs_shared->stripes[idx].cv = os_condition_variable_alloc();
fs_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); fs_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
} }
fs_shared->u2s_ring_size = KB(64); fs_shared->u2s_ring_size = KB(64);
fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size); fs_shared->u2s_ring_base = push_array_no_zero(arena, U8, fs_shared->u2s_ring_size);
fs_shared->u2s_ring_cv = os_condition_variable_alloc(); fs_shared->u2s_ring_cv = os_condition_variable_alloc();
fs_shared->u2s_ring_mutex = os_mutex_alloc(); fs_shared->u2s_ring_mutex = os_mutex_alloc();
fs_shared->streamer_count = Clamp(1, os_logical_core_count()-1, 4); fs_shared->streamer_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
fs_shared->streamers = push_array(arena, OS_Handle, 1); fs_shared->streamers = push_array(arena, OS_Handle, 1);
for(U64 idx = 0; idx < fs_shared->streamer_count; idx += 1) for(U64 idx = 0; idx < fs_shared->streamer_count; idx += 1)
{ {
fs_shared->streamers[idx] = os_launch_thread(fs_streamer_thread__entry_point, (void *)idx, 0); fs_shared->streamers[idx] = os_thread_launch(fs_streamer_thread__entry_point, (void *)idx, 0);
} }
fs_shared->detector_thread = os_launch_thread(fs_detector_thread__entry_point, 0, 0); fs_shared->detector_thread = os_thread_launch(fs_detector_thread__entry_point, 0, 0);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Change Generation //~ rjf: Change Generation
internal U64 internal U64
fs_change_gen(void) fs_change_gen(void)
{ {
return ins_atomic_u64_eval(&fs_shared->change_gen); return ins_atomic_u64_eval(&fs_shared->change_gen);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Interaction //~ rjf: Cache Interaction
internal U128 internal U128
fs_hash_from_path(String8 path, U64 endt_us) fs_hash_from_path(String8 path, U64 endt_us)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
U128 result = {0}; U128 result = {0};
path = path_normalized_from_string(scratch.arena, path); path = path_normalized_from_string(scratch.arena, path);
U128 path_key = hs_hash_from_data(path); U128 path_key = hs_hash_from_data(path);
for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1)
{ {
result = hs_hash_from_key(path_key, rewind_idx); result = hs_hash_from_key(path_key, rewind_idx);
if(!u128_match(result, u128_zero())) if(!u128_match(result, u128_zero()))
{ {
break; break;
} }
else if(u128_match(result, u128_zero()) && rewind_idx == 0) else if(u128_match(result, u128_zero()) && rewind_idx == 0)
{ {
U64 slot_idx = path_key.u64[0]%fs_shared->slots_count; U64 slot_idx = path_key.u64[0]%fs_shared->slots_count;
U64 stripe_idx = slot_idx%fs_shared->stripes_count; U64 stripe_idx = slot_idx%fs_shared->stripes_count;
FS_Slot *slot = &fs_shared->slots[slot_idx]; FS_Slot *slot = &fs_shared->slots[slot_idx];
FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; FS_Stripe *stripe = &fs_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) for(;;) OS_MutexScopeR(stripe->rw_mutex) for(;;)
{ {
FS_Node *node = 0; FS_Node *node = 0;
for(FS_Node *n = slot->first; n != 0; n = n->next) for(FS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(str8_match(path, n->path, 0)) if(str8_match(path, n->path, 0))
{ {
node = n; node = n;
break; break;
} }
} }
if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex)
{ {
node = push_array(stripe->arena, FS_Node, 1); node = push_array(stripe->arena, FS_Node, 1);
SLLQueuePush(slot->first, slot->last, node); SLLQueuePush(slot->first, slot->last, node);
node->path = push_str8_copy(stripe->arena, path); node->path = push_str8_copy(stripe->arena, path);
} }
if(!ins_atomic_u32_eval_cond_assign(&node->is_working, 1, 0) && if(!ins_atomic_u32_eval_cond_assign(&node->is_working, 1, 0) &&
!fs_u2s_enqueue_path(path, endt_us)) !fs_u2s_enqueue_path(path, endt_us))
{ {
ins_atomic_u32_eval_assign(&node->is_working, 0); ins_atomic_u32_eval_assign(&node->is_working, 0);
} }
result = hs_hash_from_key(path_key, 0); result = hs_hash_from_key(path_key, 0);
if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us)
{ {
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
} }
else else
{ {
break; break;
} }
} }
} }
} }
scratch_end(scratch); scratch_end(scratch);
return result; return result;
} }
internal U128 internal U128
fs_key_from_path(String8 path) fs_key_from_path(String8 path)
{ {
U128 key = hs_hash_from_data(path); U128 key = hs_hash_from_data(path);
fs_hash_from_path(path, 0); fs_hash_from_path(path, 0);
return key; return key;
} }
internal U64 internal U64
fs_timestamp_from_path(String8 path) fs_timestamp_from_path(String8 path)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
U64 result = 0; U64 result = 0;
path = path_normalized_from_string(scratch.arena, path); path = path_normalized_from_string(scratch.arena, path);
U128 path_key = hs_hash_from_data(path); U128 path_key = hs_hash_from_data(path);
U64 slot_idx = path_key.u64[0]%fs_shared->slots_count; U64 slot_idx = path_key.u64[0]%fs_shared->slots_count;
U64 stripe_idx = slot_idx%fs_shared->stripes_count; U64 stripe_idx = slot_idx%fs_shared->stripes_count;
FS_Slot *slot = &fs_shared->slots[slot_idx]; FS_Slot *slot = &fs_shared->slots[slot_idx];
FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; FS_Stripe *stripe = &fs_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(FS_Node *n = slot->first; n != 0; n = n->next) for(FS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(str8_match(path, n->path, 0)) if(str8_match(path, n->path, 0))
{ {
result = n->timestamp; result = n->timestamp;
break; break;
} }
} }
} }
scratch_end(scratch); scratch_end(scratch);
return result; return result;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Streamer Threads //~ rjf: Streamer Threads
internal B32 internal B32
fs_u2s_enqueue_path(String8 path, U64 endt_us) fs_u2s_enqueue_path(String8 path, U64 endt_us)
{ {
B32 result = 0; B32 result = 0;
path.size = Min(path.size, fs_shared->u2s_ring_size); path.size = Min(path.size, fs_shared->u2s_ring_size);
OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;) OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;)
{ {
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
U64 available_size = fs_shared->u2s_ring_size - unconsumed_size; U64 available_size = fs_shared->u2s_ring_size - unconsumed_size;
if(available_size >= sizeof(U64) + path.size) if(available_size >= sizeof(U64) + path.size)
{ {
result = 1; result = 1;
fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size); fs_shared->u2s_ring_write_pos += ring_write_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, &path.size);
fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size); fs_shared->u2s_ring_write_pos += ring_write(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_write_pos, path.str, path.size);
fs_shared->u2s_ring_write_pos += 7; fs_shared->u2s_ring_write_pos += 7;
fs_shared->u2s_ring_write_pos -= fs_shared->u2s_ring_write_pos%8; fs_shared->u2s_ring_write_pos -= fs_shared->u2s_ring_write_pos%8;
break; break;
} }
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us); os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, endt_us);
} }
if(result) if(result)
{ {
os_condition_variable_broadcast(fs_shared->u2s_ring_cv); os_condition_variable_broadcast(fs_shared->u2s_ring_cv);
} }
return result; return result;
} }
internal String8 internal String8
fs_u2s_dequeue_path(Arena *arena) fs_u2s_dequeue_path(Arena *arena)
{ {
String8 path = {0}; String8 path = {0};
OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;) OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;)
{ {
U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos;
if(unconsumed_size >= sizeof(U64)) if(unconsumed_size >= sizeof(U64))
{ {
fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path.size); fs_shared->u2s_ring_read_pos += ring_read_struct(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, &path.size);
path.str = push_array(arena, U8, path.size); path.str = push_array(arena, U8, path.size);
fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path.str, path.size); fs_shared->u2s_ring_read_pos += ring_read(fs_shared->u2s_ring_base, fs_shared->u2s_ring_size, fs_shared->u2s_ring_read_pos, path.str, path.size);
fs_shared->u2s_ring_read_pos += 7; fs_shared->u2s_ring_read_pos += 7;
fs_shared->u2s_ring_read_pos -= fs_shared->u2s_ring_read_pos%8; fs_shared->u2s_ring_read_pos -= fs_shared->u2s_ring_read_pos%8;
break; break;
} }
os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64); os_condition_variable_wait(fs_shared->u2s_ring_cv, fs_shared->u2s_ring_mutex, max_U64);
} }
os_condition_variable_broadcast(fs_shared->u2s_ring_cv); os_condition_variable_broadcast(fs_shared->u2s_ring_cv);
return path; return path;
} }
internal void internal void
fs_streamer_thread__entry_point(void *p) fs_streamer_thread__entry_point(void *p)
{ {
ThreadNameF("[fs] streamer #%I64u", (U64)p); ThreadNameF("[fs] streamer #%I64u", (U64)p);
for(;;) for(;;)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
//- rjf: unpack path //- rjf: unpack path
String8 path = fs_u2s_dequeue_path(scratch.arena); String8 path = fs_u2s_dequeue_path(scratch.arena);
U128 key = hs_hash_from_data(path); U128 key = hs_hash_from_data(path);
U64 slot_idx = key.u64[0]%fs_shared->slots_count; U64 slot_idx = key.u64[0]%fs_shared->slots_count;
U64 stripe_idx = slot_idx%fs_shared->stripes_count; U64 stripe_idx = slot_idx%fs_shared->stripes_count;
FS_Slot *slot = &fs_shared->slots[slot_idx]; FS_Slot *slot = &fs_shared->slots[slot_idx];
FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; FS_Stripe *stripe = &fs_shared->stripes[stripe_idx];
//- rjf: load //- rjf: load
ProfBegin("load \"%.*s\"", str8_varg(path)); ProfBegin("load \"%.*s\"", str8_varg(path));
FileProperties pre_props = os_properties_from_file_path(path); FileProperties pre_props = os_properties_from_file_path(path);
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path);
U64 data_arena_size = pre_props.size+ARENA_HEADER_SIZE; U64 data_arena_size = pre_props.size+ARENA_HEADER_SIZE;
data_arena_size += KB(4)-1; data_arena_size += KB(4)-1;
data_arena_size -= data_arena_size%KB(4); data_arena_size -= data_arena_size%KB(4);
ProfBegin("allocate"); ProfBegin("allocate");
Arena *data_arena = arena_alloc__sized(data_arena_size, data_arena_size); Arena *data_arena = arena_alloc(.reserve_size = data_arena_size, .commit_size = data_arena_size);
ProfEnd(); ProfEnd();
ProfBegin("read"); ProfBegin("read");
String8 data = os_string_from_file_range(data_arena, file, r1u64(0, pre_props.size)); String8 data = os_string_from_file_range(data_arena, file, r1u64(0, pre_props.size));
ProfEnd(); ProfEnd();
os_file_close(file); os_file_close(file);
FileProperties post_props = os_properties_from_file_path(path); FileProperties post_props = os_properties_from_file_path(path);
//- rjf: abort if modification timestamps differ - we did not successfully read the file //- rjf: abort if modification timestamps differ - we did not successfully read the file
if(pre_props.modified != post_props.modified) if(pre_props.modified != post_props.modified)
{ {
ProfScope("abort") ProfScope("abort")
{ {
arena_release(data_arena); arena_release(data_arena);
MemoryZeroStruct(&data); MemoryZeroStruct(&data);
data_arena = 0; data_arena = 0;
} }
} }
//- rjf: submit //- rjf: submit
else else
{ {
ProfScope("submit") ProfScope("submit")
{ {
hs_submit_data(key, &data_arena, data); hs_submit_data(key, &data_arena, data);
} }
} }
//- rjf: commit info to cache //- rjf: commit info to cache
ProfScope("commit to cache") OS_MutexScopeW(stripe->rw_mutex) ProfScope("commit to cache") OS_MutexScopeW(stripe->rw_mutex)
{ {
FS_Node *node = 0; FS_Node *node = 0;
for(FS_Node *n = slot->first; n != 0; n = n->next) for(FS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(str8_match(n->path, path, 0)) if(str8_match(n->path, path, 0))
{ {
node = n; node = n;
break; break;
} }
} }
if(node != 0) if(node != 0)
{ {
if(node->timestamp != 0) if(node->timestamp != 0)
{ {
ins_atomic_u64_inc_eval(&fs_shared->change_gen); ins_atomic_u64_inc_eval(&fs_shared->change_gen);
} }
if(post_props.modified == pre_props.modified) if(post_props.modified == pre_props.modified)
{ {
node->timestamp = post_props.modified; node->timestamp = post_props.modified;
} }
ins_atomic_u32_eval_assign(&node->is_working, 0); ins_atomic_u32_eval_assign(&node->is_working, 0);
} }
} }
os_condition_variable_broadcast(stripe->cv); os_condition_variable_broadcast(stripe->cv);
ProfEnd(); ProfEnd();
scratch_end(scratch); scratch_end(scratch);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Change Detector Thread //~ rjf: Change Detector Thread
internal void internal void
fs_detector_thread__entry_point(void *p) fs_detector_thread__entry_point(void *p)
{ {
ThreadNameF("[fs] detector"); ThreadNameF("[fs] detector");
for(;;) for(;;)
{ {
U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count;
for(U64 stripe_idx = 0; stripe_idx < fs_shared->stripes_count; stripe_idx += 1) for(U64 stripe_idx = 0; stripe_idx < fs_shared->stripes_count; stripe_idx += 1)
{ {
FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; FS_Stripe *stripe = &fs_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1)
{ {
U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx;
FS_Slot *slot = &fs_shared->slots[slot_idx]; FS_Slot *slot = &fs_shared->slots[slot_idx];
for(FS_Node *n = slot->first; n != 0; n = n->next) for(FS_Node *n = slot->first; n != 0; n = n->next)
{ {
FileProperties props = os_properties_from_file_path(n->path); FileProperties props = os_properties_from_file_path(n->path);
if(props.modified != n->timestamp) if(props.modified != n->timestamp)
{ {
if(!ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0) && if(!ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0) &&
!fs_u2s_enqueue_path(n->path, os_now_microseconds()+100000)) !fs_u2s_enqueue_path(n->path, os_now_microseconds()+100000))
{ {
ins_atomic_u32_eval_assign(&n->is_working, 0); ins_atomic_u32_eval_assign(&n->is_working, 0);
} }
} }
} }
} }
} }
os_sleep_milliseconds(100); os_sleep_milliseconds(100);
} }
} }
File diff suppressed because it is too large Load Diff
+383 -383
View File
@@ -1,383 +1,383 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Layer Initialization //~ rjf: Main Layer Initialization
internal void internal void
geo_init(void) geo_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
geo_shared = push_array(arena, GEO_Shared, 1); geo_shared = push_array(arena, GEO_Shared, 1);
geo_shared->arena = arena; geo_shared->arena = arena;
geo_shared->slots_count = 1024; geo_shared->slots_count = 1024;
geo_shared->stripes_count = Min(geo_shared->slots_count, os_logical_core_count()); geo_shared->stripes_count = Min(geo_shared->slots_count, os_get_system_info()->logical_processor_count);
geo_shared->slots = push_array(arena, GEO_Slot, geo_shared->slots_count); geo_shared->slots = push_array(arena, GEO_Slot, geo_shared->slots_count);
geo_shared->stripes = push_array(arena, GEO_Stripe, geo_shared->stripes_count); geo_shared->stripes = push_array(arena, GEO_Stripe, geo_shared->stripes_count);
geo_shared->stripes_free_nodes = push_array(arena, GEO_Node *, geo_shared->stripes_count); geo_shared->stripes_free_nodes = push_array(arena, GEO_Node *, geo_shared->stripes_count);
for(U64 idx = 0; idx < geo_shared->stripes_count; idx += 1) for(U64 idx = 0; idx < geo_shared->stripes_count; idx += 1)
{ {
geo_shared->stripes[idx].arena = arena_alloc(); geo_shared->stripes[idx].arena = arena_alloc();
geo_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); geo_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
geo_shared->stripes[idx].cv = os_condition_variable_alloc(); geo_shared->stripes[idx].cv = os_condition_variable_alloc();
} }
geo_shared->u2x_ring_size = KB(64); geo_shared->u2x_ring_size = KB(64);
geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size);
geo_shared->u2x_ring_cv = os_condition_variable_alloc(); geo_shared->u2x_ring_cv = os_condition_variable_alloc();
geo_shared->u2x_ring_mutex = os_mutex_alloc(); geo_shared->u2x_ring_mutex = os_mutex_alloc();
geo_shared->xfer_thread_count = Clamp(1, os_logical_core_count()-1, 4); geo_shared->xfer_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count); geo_shared->xfer_threads = push_array(arena, OS_Handle, geo_shared->xfer_thread_count);
for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1) for(U64 idx = 0; idx < geo_shared->xfer_thread_count; idx += 1)
{ {
geo_shared->xfer_threads[idx] = os_launch_thread(geo_xfer_thread__entry_point, (void *)idx, 0); geo_shared->xfer_threads[idx] = os_thread_launch(geo_xfer_thread__entry_point, (void *)idx, 0);
} }
geo_shared->evictor_thread = os_launch_thread(geo_evictor_thread__entry_point, 0, 0); geo_shared->evictor_thread = os_thread_launch(geo_evictor_thread__entry_point, 0, 0);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Thread Context Initialization //~ rjf: Thread Context Initialization
internal void internal void
geo_tctx_ensure_inited(void) geo_tctx_ensure_inited(void)
{ {
if(geo_tctx == 0) if(geo_tctx == 0)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
geo_tctx = push_array(arena, GEO_TCTX, 1); geo_tctx = push_array(arena, GEO_TCTX, 1);
geo_tctx->arena = arena; geo_tctx->arena = arena;
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: User Clock //~ rjf: User Clock
internal void internal void
geo_user_clock_tick(void) geo_user_clock_tick(void)
{ {
ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx); ins_atomic_u64_inc_eval(&geo_shared->user_clock_idx);
} }
internal U64 internal U64
geo_user_clock_idx(void) geo_user_clock_idx(void)
{ {
return ins_atomic_u64_eval(&geo_shared->user_clock_idx); return ins_atomic_u64_eval(&geo_shared->user_clock_idx);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access //~ rjf: Scoped Access
internal GEO_Scope * internal GEO_Scope *
geo_scope_open(void) geo_scope_open(void)
{ {
geo_tctx_ensure_inited(); geo_tctx_ensure_inited();
GEO_Scope *scope = geo_tctx->free_scope; GEO_Scope *scope = geo_tctx->free_scope;
if(scope) if(scope)
{ {
SLLStackPop(geo_tctx->free_scope); SLLStackPop(geo_tctx->free_scope);
} }
else else
{ {
scope = push_array_no_zero(geo_tctx->arena, GEO_Scope, 1); scope = push_array_no_zero(geo_tctx->arena, GEO_Scope, 1);
} }
MemoryZeroStruct(scope); MemoryZeroStruct(scope);
return scope; return scope;
} }
internal void internal void
geo_scope_close(GEO_Scope *scope) geo_scope_close(GEO_Scope *scope)
{ {
for(GEO_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) for(GEO_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next)
{ {
U128 hash = touch->hash; U128 hash = touch->hash;
next = touch->next; next = touch->next;
U64 slot_idx = hash.u64[1]%geo_shared->slots_count; U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
U64 stripe_idx = slot_idx%geo_shared->stripes_count; U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash)) if(u128_match(hash, n->hash))
{ {
ins_atomic_u64_dec_eval(&n->scope_ref_count); ins_atomic_u64_dec_eval(&n->scope_ref_count);
break; break;
} }
} }
} }
SLLStackPush(geo_tctx->free_touch, touch); SLLStackPush(geo_tctx->free_touch, touch);
} }
SLLStackPush(geo_tctx->free_scope, scope); SLLStackPush(geo_tctx->free_scope, scope);
} }
internal void internal void
geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node) geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node)
{ {
GEO_Touch *touch = geo_tctx->free_touch; GEO_Touch *touch = geo_tctx->free_touch;
ins_atomic_u64_inc_eval(&node->scope_ref_count); ins_atomic_u64_inc_eval(&node->scope_ref_count);
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx()); ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, geo_user_clock_idx());
if(touch != 0) if(touch != 0)
{ {
SLLStackPop(geo_tctx->free_touch); SLLStackPop(geo_tctx->free_touch);
} }
else else
{ {
touch = push_array_no_zero(geo_tctx->arena, GEO_Touch, 1); touch = push_array_no_zero(geo_tctx->arena, GEO_Touch, 1);
} }
MemoryZeroStruct(touch); MemoryZeroStruct(touch);
touch->hash = node->hash; touch->hash = node->hash;
SLLStackPush(scope->top_touch, touch); SLLStackPush(scope->top_touch, touch);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Lookups //~ rjf: Cache Lookups
internal R_Handle internal R_Handle
geo_buffer_from_hash(GEO_Scope *scope, U128 hash) geo_buffer_from_hash(GEO_Scope *scope, U128 hash)
{ {
R_Handle handle = {0}; R_Handle handle = {0};
if(!u128_match(hash, u128_zero())) if(!u128_match(hash, u128_zero()))
{ {
U64 slot_idx = hash.u64[1]%geo_shared->slots_count; U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
U64 stripe_idx = slot_idx%geo_shared->stripes_count; U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
B32 found = 0; B32 found = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash)) if(u128_match(hash, n->hash))
{ {
handle = n->buffer; handle = n->buffer;
found = !r_handle_match(r_handle_zero(), handle); found = !r_handle_match(r_handle_zero(), handle);
geo_scope_touch_node__stripe_r_guarded(scope, n); geo_scope_touch_node__stripe_r_guarded(scope, n);
break; break;
} }
} }
} }
B32 node_is_new = 0; B32 node_is_new = 0;
if(!found) if(!found)
{ {
OS_MutexScopeW(stripe->rw_mutex) OS_MutexScopeW(stripe->rw_mutex)
{ {
GEO_Node *node = 0; GEO_Node *node = 0;
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash)) if(u128_match(hash, n->hash))
{ {
node = n; node = n;
break; break;
} }
} }
if(node == 0) if(node == 0)
{ {
node = geo_shared->stripes_free_nodes[stripe_idx]; node = geo_shared->stripes_free_nodes[stripe_idx];
if(node) if(node)
{ {
SLLStackPop(geo_shared->stripes_free_nodes[stripe_idx]); SLLStackPop(geo_shared->stripes_free_nodes[stripe_idx]);
} }
else else
{ {
node = push_array_no_zero(stripe->arena, GEO_Node, 1); node = push_array_no_zero(stripe->arena, GEO_Node, 1);
} }
MemoryZeroStruct(node); MemoryZeroStruct(node);
DLLPushBack(slot->first, slot->last, node); DLLPushBack(slot->first, slot->last, node);
node->hash = hash; node->hash = hash;
node_is_new = 1; node_is_new = 1;
} }
} }
} }
if(node_is_new) if(node_is_new)
{ {
geo_u2x_enqueue_req(hash, max_U64); geo_u2x_enqueue_req(hash, max_U64);
} }
} }
return handle; return handle;
} }
internal R_Handle internal R_Handle
geo_buffer_from_key(GEO_Scope *scope, U128 key) geo_buffer_from_key(GEO_Scope *scope, U128 key)
{ {
R_Handle handle = {0}; R_Handle handle = {0};
for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1)
{ {
U128 hash = hs_hash_from_key(key, rewind_idx); U128 hash = hs_hash_from_key(key, rewind_idx);
handle = geo_buffer_from_hash(scope, hash); handle = geo_buffer_from_hash(scope, hash);
if(!r_handle_match(handle, r_handle_zero())) if(!r_handle_match(handle, r_handle_zero()))
{ {
break; break;
} }
} }
return handle; return handle;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Transfer Threads //~ rjf: Transfer Threads
internal B32 internal B32
geo_u2x_enqueue_req(U128 hash, U64 endt_us) geo_u2x_enqueue_req(U128 hash, U64 endt_us)
{ {
B32 good = 0; B32 good = 0;
OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;)
{ {
U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos;
U64 available_size = geo_shared->u2x_ring_size-unconsumed_size; U64 available_size = geo_shared->u2x_ring_size-unconsumed_size;
if(available_size >= sizeof(hash)) if(available_size >= sizeof(hash))
{ {
good = 1; good = 1;
geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &hash); geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &hash);
break; break;
} }
if(os_now_microseconds() >= endt_us) if(os_now_microseconds() >= endt_us)
{ {
break; break;
} }
os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us); os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, endt_us);
} }
if(good) if(good)
{ {
os_condition_variable_broadcast(geo_shared->u2x_ring_cv); os_condition_variable_broadcast(geo_shared->u2x_ring_cv);
} }
return good; return good;
} }
internal void internal void
geo_u2x_dequeue_req(U128 *hash_out) geo_u2x_dequeue_req(U128 *hash_out)
{ {
OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;)
{ {
U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos;
if(unconsumed_size >= sizeof(*hash_out)) if(unconsumed_size >= sizeof(*hash_out))
{ {
geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out); geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out);
break; break;
} }
os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64); os_condition_variable_wait(geo_shared->u2x_ring_cv, geo_shared->u2x_ring_mutex, max_U64);
} }
os_condition_variable_broadcast(geo_shared->u2x_ring_cv); os_condition_variable_broadcast(geo_shared->u2x_ring_cv);
} }
internal void internal void
geo_xfer_thread__entry_point(void *p) geo_xfer_thread__entry_point(void *p)
{ {
for(;;) for(;;)
{ {
HS_Scope *scope = hs_scope_open(); HS_Scope *scope = hs_scope_open();
//- rjf: decode //- rjf: decode
U128 hash = {0}; U128 hash = {0};
geo_u2x_dequeue_req(&hash); geo_u2x_dequeue_req(&hash);
//- rjf: unpack hash //- rjf: unpack hash
U64 slot_idx = hash.u64[1]%geo_shared->slots_count; U64 slot_idx = hash.u64[1]%geo_shared->slots_count;
U64 stripe_idx = slot_idx%geo_shared->stripes_count; U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
//- rjf: take task //- rjf: take task
B32 got_task = 0; B32 got_task = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash)) if(u128_match(n->hash, hash))
{ {
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
break; break;
} }
} }
} }
//- rjf: hash -> data //- rjf: hash -> data
String8 data = {0}; String8 data = {0};
if(got_task) if(got_task)
{ {
data = hs_data_from_hash(scope, hash); data = hs_data_from_hash(scope, hash);
} }
//- rjf: data -> buffer //- rjf: data -> buffer
R_Handle buffer = {0}; R_Handle buffer = {0};
if(got_task && data.size != 0) if(got_task && data.size != 0)
{ {
buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str); buffer = r_buffer_alloc(R_ResourceKind_Static, data.size, data.str);
} }
//- rjf: commit results to cache //- rjf: commit results to cache
if(got_task) OS_MutexScopeW(stripe->rw_mutex) if(got_task) OS_MutexScopeW(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash)) if(u128_match(n->hash, hash))
{ {
n->buffer = buffer; n->buffer = buffer;
ins_atomic_u32_eval_assign(&n->is_working, 0); ins_atomic_u32_eval_assign(&n->is_working, 0);
ins_atomic_u64_inc_eval(&n->load_count); ins_atomic_u64_inc_eval(&n->load_count);
break; break;
} }
} }
} }
hs_scope_close(scope); hs_scope_close(scope);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Evictor Threads //~ rjf: Evictor Threads
internal void internal void
geo_evictor_thread__entry_point(void *p) geo_evictor_thread__entry_point(void *p)
{ {
for(;;) for(;;)
{ {
U64 check_time_us = os_now_microseconds(); U64 check_time_us = os_now_microseconds();
U64 check_time_user_clocks = geo_user_clock_idx(); U64 check_time_user_clocks = geo_user_clock_idx();
U64 evict_threshold_us = 10*1000000; U64 evict_threshold_us = 10*1000000;
U64 evict_threshold_user_clocks = 10; U64 evict_threshold_user_clocks = 10;
for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1) for(U64 slot_idx = 0; slot_idx < geo_shared->slots_count; slot_idx += 1)
{ {
U64 stripe_idx = slot_idx%geo_shared->stripes_count; U64 stripe_idx = slot_idx%geo_shared->stripes_count;
GEO_Slot *slot = &geo_shared->slots[slot_idx]; GEO_Slot *slot = &geo_shared->slots[slot_idx];
GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx]; GEO_Stripe *stripe = &geo_shared->stripes[stripe_idx];
B32 slot_has_work = 0; B32 slot_has_work = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first; n != 0; n = n->next) for(GEO_Node *n = slot->first; n != 0; n = n->next)
{ {
if(n->scope_ref_count == 0 && if(n->scope_ref_count == 0 &&
n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_time_touched_us+evict_threshold_us <= check_time_us &&
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
n->load_count != 0 && n->load_count != 0 &&
n->is_working == 0) n->is_working == 0)
{ {
slot_has_work = 1; slot_has_work = 1;
break; break;
} }
} }
} }
if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex)
{ {
for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next) for(GEO_Node *n = slot->first, *next = 0; n != 0; n = next)
{ {
next = n->next; next = n->next;
if(n->scope_ref_count == 0 && if(n->scope_ref_count == 0 &&
n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_time_touched_us+evict_threshold_us <= check_time_us &&
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
n->load_count != 0 && n->load_count != 0 &&
n->is_working == 0) n->is_working == 0)
{ {
DLLRemove(slot->first, slot->last, n); DLLRemove(slot->first, slot->last, n);
if(!r_handle_match(n->buffer, r_handle_zero())) if(!r_handle_match(n->buffer, r_handle_zero()))
{ {
r_buffer_release(n->buffer); r_buffer_release(n->buffer);
} }
SLLStackPush(geo_shared->stripes_free_nodes[stripe_idx], n); SLLStackPush(geo_shared->stripes_free_nodes[stripe_idx], n);
} }
} }
} }
os_sleep_milliseconds(5); os_sleep_milliseconds(5);
} }
os_sleep_milliseconds(1000); os_sleep_milliseconds(1000);
} }
} }
+339 -339
View File
@@ -1,339 +1,339 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Helpers //~ rjf: Basic Helpers
#if !defined(BLAKE2_H) #if !defined(BLAKE2_H)
#define HAVE_SSE2 #define HAVE_SSE2
#include "third_party/blake2/blake2.h" #include "third_party/blake2/blake2.h"
#include "third_party/blake2/blake2b.c" #include "third_party/blake2/blake2b.c"
#endif #endif
internal U128 internal U128
hs_hash_from_data(String8 data) hs_hash_from_data(String8 data)
{ {
U128 u128 = {0}; U128 u128 = {0};
if(data.size != 0) if(data.size != 0)
{ {
blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0); blake2b((U8 *)&u128.u64[0], sizeof(u128), data.str, data.size, 0, 0);
} }
return u128; return u128;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Layer Initialization //~ rjf: Main Layer Initialization
internal void internal void
hs_init(void) hs_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
hs_shared = push_array(arena, HS_Shared, 1); hs_shared = push_array(arena, HS_Shared, 1);
hs_shared->arena = arena; hs_shared->arena = arena;
hs_shared->slots_count = 4096; hs_shared->slots_count = 4096;
hs_shared->stripes_count = Min(hs_shared->slots_count, os_logical_core_count()); hs_shared->stripes_count = Min(hs_shared->slots_count, os_get_system_info()->logical_processor_count);
hs_shared->slots = push_array(arena, HS_Slot, hs_shared->slots_count); hs_shared->slots = push_array(arena, HS_Slot, hs_shared->slots_count);
hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count); hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count);
hs_shared->stripes_free_nodes = push_array(arena, HS_Node *, hs_shared->stripes_count); hs_shared->stripes_free_nodes = push_array(arena, HS_Node *, hs_shared->stripes_count);
for(U64 idx = 0; idx < hs_shared->stripes_count; idx += 1) for(U64 idx = 0; idx < hs_shared->stripes_count; idx += 1)
{ {
HS_Stripe *stripe = &hs_shared->stripes[idx]; HS_Stripe *stripe = &hs_shared->stripes[idx];
stripe->arena = arena_alloc(); stripe->arena = arena_alloc();
stripe->rw_mutex = os_rw_mutex_alloc(); stripe->rw_mutex = os_rw_mutex_alloc();
stripe->cv = os_condition_variable_alloc(); stripe->cv = os_condition_variable_alloc();
} }
hs_shared->key_slots_count = 4096; hs_shared->key_slots_count = 4096;
hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_logical_core_count()); hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_get_system_info()->logical_processor_count);
hs_shared->key_slots = push_array(arena, HS_KeySlot, hs_shared->key_slots_count); hs_shared->key_slots = push_array(arena, HS_KeySlot, hs_shared->key_slots_count);
hs_shared->key_stripes = push_array(arena, HS_Stripe, hs_shared->key_stripes_count); hs_shared->key_stripes = push_array(arena, HS_Stripe, hs_shared->key_stripes_count);
for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1) for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1)
{ {
HS_Stripe *stripe = &hs_shared->key_stripes[idx]; HS_Stripe *stripe = &hs_shared->key_stripes[idx];
stripe->arena = arena_alloc(); stripe->arena = arena_alloc();
stripe->rw_mutex = os_rw_mutex_alloc(); stripe->rw_mutex = os_rw_mutex_alloc();
stripe->cv = os_condition_variable_alloc(); stripe->cv = os_condition_variable_alloc();
} }
hs_shared->evictor_thread = os_launch_thread(hs_evictor_thread__entry_point, 0, 0); hs_shared->evictor_thread = os_thread_launch(hs_evictor_thread__entry_point, 0, 0);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Thread Context Initialization //~ rjf: Thread Context Initialization
internal void internal void
hs_tctx_ensure_inited(void) hs_tctx_ensure_inited(void)
{ {
if(hs_tctx == 0) if(hs_tctx == 0)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
hs_tctx = push_array(arena, HS_TCTX, 1); hs_tctx = push_array(arena, HS_TCTX, 1);
hs_tctx->arena = arena; hs_tctx->arena = arena;
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Submission //~ rjf: Cache Submission
internal U128 internal U128
hs_submit_data(U128 key, Arena **data_arena, String8 data) hs_submit_data(U128 key, Arena **data_arena, String8 data)
{ {
U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count;
U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count;
HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx];
HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx];
U128 hash = hs_hash_from_data(data); U128 hash = hs_hash_from_data(data);
U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 slot_idx = hash.u64[1]%hs_shared->slots_count;
U64 stripe_idx = slot_idx%hs_shared->stripes_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count;
HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Slot *slot = &hs_shared->slots[slot_idx];
HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx];
//- rjf: commit data to cache - if already there, just bump key refcount //- rjf: commit data to cache - if already there, just bump key refcount
ProfScope("commit data to cache - if already there, just bump key refcount") OS_MutexScopeW(stripe->rw_mutex) ProfScope("commit data to cache - if already there, just bump key refcount") OS_MutexScopeW(stripe->rw_mutex)
{ {
HS_Node *existing_node = 0; HS_Node *existing_node = 0;
for(HS_Node *n = slot->first; n != 0; n = n->next) for(HS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash)) if(u128_match(n->hash, hash))
{ {
existing_node = n; existing_node = n;
break; break;
} }
} }
if(existing_node == 0) if(existing_node == 0)
{ {
HS_Node *node = hs_shared->stripes_free_nodes[stripe_idx]; HS_Node *node = hs_shared->stripes_free_nodes[stripe_idx];
if(node) if(node)
{ {
SLLStackPop(hs_shared->stripes_free_nodes[stripe_idx]); SLLStackPop(hs_shared->stripes_free_nodes[stripe_idx]);
} }
else else
{ {
node = push_array(stripe->arena, HS_Node, 1); node = push_array(stripe->arena, HS_Node, 1);
} }
node->hash = hash; node->hash = hash;
node->arena = *data_arena; node->arena = *data_arena;
node->data = data; node->data = data;
node->scope_ref_count = 0; node->scope_ref_count = 0;
node->key_ref_count = 1; node->key_ref_count = 1;
DLLPushBack(slot->first, slot->last, node); DLLPushBack(slot->first, slot->last, node);
} }
else else
{ {
existing_node->key_ref_count += 1; existing_node->key_ref_count += 1;
arena_release(*data_arena); arena_release(*data_arena);
} }
*data_arena = 0; *data_arena = 0;
} }
//- rjf: commit this hash to key cache //- rjf: commit this hash to key cache
U128 key_expired_hash = {0}; U128 key_expired_hash = {0};
ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex) ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex)
{ {
HS_KeyNode *key_node = 0; HS_KeyNode *key_node = 0;
for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->key, key)) if(u128_match(n->key, key))
{ {
key_node = n; key_node = n;
break; break;
} }
} }
if(!key_node) if(!key_node)
{ {
key_node = push_array(key_stripe->arena, HS_KeyNode, 1); key_node = push_array(key_stripe->arena, HS_KeyNode, 1);
key_node->key = key; key_node->key = key;
SLLQueuePush(key_slot->first, key_slot->last, key_node); SLLQueuePush(key_slot->first, key_slot->last, key_node);
} }
if(key_node) if(key_node)
{ {
if(key_node->hash_history_gen >= ArrayCount(key_node->hash_history)) if(key_node->hash_history_gen >= ArrayCount(key_node->hash_history))
{ {
key_expired_hash = key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)]; key_expired_hash = key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)];
} }
key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash;
key_node->hash_history_gen += 1; key_node->hash_history_gen += 1;
} }
} }
//- rjf: if this key's history cache was full, dec key ref count of oldest hash //- rjf: if this key's history cache was full, dec key ref count of oldest hash
ProfScope("if this key's history cache was full, dec key ref count of oldest hash") ProfScope("if this key's history cache was full, dec key ref count of oldest hash")
if(!u128_match(key_expired_hash, u128_zero())) if(!u128_match(key_expired_hash, u128_zero()))
{ {
U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count; U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count;
U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count;
HS_Slot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx]; HS_Slot *old_hash_slot = &hs_shared->slots[old_hash_slot_idx];
HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx]; HS_Stripe *old_hash_stripe = &hs_shared->stripes[old_hash_stripe_idx];
OS_MutexScopeR(old_hash_stripe->rw_mutex) OS_MutexScopeR(old_hash_stripe->rw_mutex)
{ {
for(HS_Node *n = old_hash_slot->first; n != 0; n = n->next) for(HS_Node *n = old_hash_slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, key_expired_hash)) if(u128_match(n->hash, key_expired_hash))
{ {
ins_atomic_u64_dec_eval(&n->key_ref_count); ins_atomic_u64_dec_eval(&n->key_ref_count);
break; break;
} }
} }
} }
} }
return hash; return hash;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access //~ rjf: Scoped Access
internal HS_Scope * internal HS_Scope *
hs_scope_open(void) hs_scope_open(void)
{ {
hs_tctx_ensure_inited(); hs_tctx_ensure_inited();
HS_Scope *scope = hs_tctx->free_scope; HS_Scope *scope = hs_tctx->free_scope;
if(scope) if(scope)
{ {
SLLStackPop(hs_tctx->free_scope); SLLStackPop(hs_tctx->free_scope);
} }
else else
{ {
scope = push_array_no_zero(hs_tctx->arena, HS_Scope, 1); scope = push_array_no_zero(hs_tctx->arena, HS_Scope, 1);
} }
MemoryZeroStruct(scope); MemoryZeroStruct(scope);
return scope; return scope;
} }
internal void internal void
hs_scope_close(HS_Scope *scope) hs_scope_close(HS_Scope *scope)
{ {
for(HS_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) for(HS_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next)
{ {
U128 hash = touch->hash; U128 hash = touch->hash;
next = touch->next; next = touch->next;
U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 slot_idx = hash.u64[1]%hs_shared->slots_count;
U64 stripe_idx = slot_idx%hs_shared->stripes_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count;
HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Slot *slot = &hs_shared->slots[slot_idx];
HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(HS_Node *n = slot->first; n != 0; n = n->next) for(HS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash)) if(u128_match(hash, n->hash))
{ {
ins_atomic_u64_dec_eval(&n->scope_ref_count); ins_atomic_u64_dec_eval(&n->scope_ref_count);
break; break;
} }
} }
} }
SLLStackPush(hs_tctx->free_touch, touch); SLLStackPush(hs_tctx->free_touch, touch);
} }
SLLStackPush(hs_tctx->free_scope, scope); SLLStackPush(hs_tctx->free_scope, scope);
} }
internal void internal void
hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node) hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node)
{ {
HS_Touch *touch = hs_tctx->free_touch; HS_Touch *touch = hs_tctx->free_touch;
ins_atomic_u64_inc_eval(&node->scope_ref_count); ins_atomic_u64_inc_eval(&node->scope_ref_count);
if(touch != 0) if(touch != 0)
{ {
SLLStackPop(hs_tctx->free_touch); SLLStackPop(hs_tctx->free_touch);
} }
else else
{ {
touch = push_array_no_zero(hs_tctx->arena, HS_Touch, 1); touch = push_array_no_zero(hs_tctx->arena, HS_Touch, 1);
} }
MemoryZeroStruct(touch); MemoryZeroStruct(touch);
touch->hash = node->hash; touch->hash = node->hash;
SLLStackPush(scope->top_touch, touch); SLLStackPush(scope->top_touch, touch);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Lookup //~ rjf: Cache Lookup
internal U128 internal U128
hs_hash_from_key(U128 key, U64 rewind_count) hs_hash_from_key(U128 key, U64 rewind_count)
{ {
U128 result = {0}; U128 result = {0};
U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count;
U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count;
HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx];
HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx];
OS_MutexScopeR(key_stripe->rw_mutex) OS_MutexScopeR(key_stripe->rw_mutex)
{ {
for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count) if(u128_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count)
{ {
result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)]; result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)];
break; break;
} }
} }
} }
return result; return result;
} }
internal String8 internal String8
hs_data_from_hash(HS_Scope *scope, U128 hash) hs_data_from_hash(HS_Scope *scope, U128 hash)
{ {
String8 result = {0}; String8 result = {0};
U64 slot_idx = hash.u64[1]%hs_shared->slots_count; U64 slot_idx = hash.u64[1]%hs_shared->slots_count;
U64 stripe_idx = slot_idx%hs_shared->stripes_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count;
HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Slot *slot = &hs_shared->slots[slot_idx];
HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(HS_Node *n = slot->first; n != 0; n = n->next) for(HS_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash)) if(u128_match(n->hash, hash))
{ {
result = n->data; result = n->data;
hs_scope_touch_node__stripe_r_guarded(scope, n); hs_scope_touch_node__stripe_r_guarded(scope, n);
break; break;
} }
} }
} }
return result; return result;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Evictor Thread //~ rjf: Evictor Thread
internal void internal void
hs_evictor_thread__entry_point(void *p) hs_evictor_thread__entry_point(void *p)
{ {
for(;;) for(;;)
{ {
for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1) for(U64 slot_idx = 0; slot_idx < hs_shared->slots_count; slot_idx += 1)
{ {
U64 stripe_idx = slot_idx%hs_shared->stripes_count; U64 stripe_idx = slot_idx%hs_shared->stripes_count;
HS_Slot *slot = &hs_shared->slots[slot_idx]; HS_Slot *slot = &hs_shared->slots[slot_idx];
HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; HS_Stripe *stripe = &hs_shared->stripes[stripe_idx];
B32 slot_has_work = 0; B32 slot_has_work = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(HS_Node *n = slot->first; n != 0; n = n->next) for(HS_Node *n = slot->first; n != 0; n = n->next)
{ {
U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count);
U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count);
if(key_ref_count == 0 && scope_ref_count == 0) if(key_ref_count == 0 && scope_ref_count == 0)
{ {
slot_has_work = 1; slot_has_work = 1;
break; break;
} }
} }
} }
if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex)
{ {
for(HS_Node *n = slot->first, *next = 0; n != 0; n = next) for(HS_Node *n = slot->first, *next = 0; n != 0; n = next)
{ {
next = n->next; next = n->next;
U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count);
U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count);
if(key_ref_count == 0 && scope_ref_count == 0) if(key_ref_count == 0 && scope_ref_count == 0)
{ {
DLLRemove(slot->first, slot->last, n); DLLRemove(slot->first, slot->last, n);
SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n);
arena_release(n->arena); arena_release(n->arena);
} }
} }
} }
} }
os_sleep_milliseconds(1000); os_sleep_milliseconds(1000);
} }
} }
+1532 -1519
View File
File diff suppressed because it is too large Load Diff
+39 -39
View File
@@ -1,39 +1,39 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_INC_H #ifndef OS_INC_H
#define OS_INC_H #define OS_INC_H
#if !defined(OS_FEATURE_SOCKET) #if !defined(OS_FEATURE_SOCKET)
# define OS_FEATURE_SOCKET 0 # define OS_FEATURE_SOCKET 0
#endif #endif
#if !defined(OS_FEATURE_GRAPHICAL) #if !defined(OS_FEATURE_GRAPHICAL)
# define OS_FEATURE_GRAPHICAL 0 # define OS_FEATURE_GRAPHICAL 0
#endif #endif
#include "core/metagen_os_core.h" #include "core/metagen_os_core.h"
#if OS_FEATURE_SOCKET #if OS_FEATURE_SOCKET
#include "socket/metagen_os_socket.h" #include "socket/metagen_os_socket.h"
#endif #endif
#if OS_FEATURE_GRAPHICAL #if OS_FEATURE_GRAPHICAL
#include "gfx/metagen_os_gfx.h" #include "gfx/metagen_os_gfx.h"
#endif #endif
#if OS_WINDOWS #if OS_WINDOWS
# include "core/win32/metagen_os_core_win32.h" # include "core/win32/metagen_os_core_win32.h"
# if OS_FEATURE_SOCKET # if OS_FEATURE_SOCKET
# include "socket/win32/metagen_os_socket_win32.h" # include "socket/win32/metagen_os_socket_win32.h"
# endif # endif
# if OS_FEATURE_GRAPHICAL # if OS_FEATURE_GRAPHICAL
# include "gfx/win32/metagen_os_gfx_win32.h" # include "gfx/win32/metagen_os_gfx_win32.h"
# endif # endif
#elif OS_LINUX #elif OS_LINUX
# include "core/linux/metagen_os_core_linux.h" # include "core/linux/metagen_os_core_linux.h"
#else #else
# error no OS layer setup # error no OS layer setup
#endif #endif
#endif //OS_SWITCH_H #endif // OS_INC_H
+142 -142
View File
@@ -1,142 +1,142 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Layer Initialization //~ rjf: Main Layer Initialization
internal void internal void
mtx_init(void) mtx_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
mtx_shared = push_array(arena, MTX_Shared, 1); mtx_shared = push_array(arena, MTX_Shared, 1);
mtx_shared->arena = arena; mtx_shared->arena = arena;
mtx_shared->slots_count = 256; mtx_shared->slots_count = 256;
mtx_shared->stripes_count = Min(mtx_shared->slots_count, os_logical_core_count()); mtx_shared->stripes_count = Min(mtx_shared->slots_count, os_get_system_info()->logical_processor_count);
mtx_shared->slots = push_array(arena, MTX_Slot, mtx_shared->slots_count); mtx_shared->slots = push_array(arena, MTX_Slot, mtx_shared->slots_count);
mtx_shared->stripes = push_array(arena, MTX_Stripe, mtx_shared->stripes_count); mtx_shared->stripes = push_array(arena, MTX_Stripe, mtx_shared->stripes_count);
for(U64 idx = 0; idx < mtx_shared->stripes_count; idx += 1) for(U64 idx = 0; idx < mtx_shared->stripes_count; idx += 1)
{ {
mtx_shared->stripes[idx].arena = arena_alloc(); mtx_shared->stripes[idx].arena = arena_alloc();
mtx_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); mtx_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
} }
mtx_shared->mut_threads_count = Min(os_logical_core_count(), 4); mtx_shared->mut_threads_count = Min(os_get_system_info()->logical_processor_count, 4);
mtx_shared->mut_threads = push_array(arena, MTX_MutThread, mtx_shared->mut_threads_count); mtx_shared->mut_threads = push_array(arena, MTX_MutThread, mtx_shared->mut_threads_count);
for(U64 idx = 0; idx < mtx_shared->mut_threads_count; idx += 1) for(U64 idx = 0; idx < mtx_shared->mut_threads_count; idx += 1)
{ {
mtx_shared->mut_threads[idx].ring_size = KB(64); mtx_shared->mut_threads[idx].ring_size = KB(64);
mtx_shared->mut_threads[idx].ring_base = push_array_no_zero(arena, U8, mtx_shared->mut_threads[idx].ring_size); mtx_shared->mut_threads[idx].ring_base = push_array_no_zero(arena, U8, mtx_shared->mut_threads[idx].ring_size);
mtx_shared->mut_threads[idx].cv = os_condition_variable_alloc(); mtx_shared->mut_threads[idx].cv = os_condition_variable_alloc();
mtx_shared->mut_threads[idx].mutex = os_mutex_alloc(); mtx_shared->mut_threads[idx].mutex = os_mutex_alloc();
mtx_shared->mut_threads[idx].thread = os_launch_thread(mtx_mut_thread__entry_point, &mtx_shared->mut_threads[idx], 0); mtx_shared->mut_threads[idx].thread = os_thread_launch(mtx_mut_thread__entry_point, &mtx_shared->mut_threads[idx], 0);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Buffer Operations //~ rjf: Buffer Operations
internal void internal void
mtx_push_op(U128 buffer_key, MTX_Op op) mtx_push_op(U128 buffer_key, MTX_Op op)
{ {
MTX_MutThread *thread = &mtx_shared->mut_threads[buffer_key.u64[1]%mtx_shared->mut_threads_count]; MTX_MutThread *thread = &mtx_shared->mut_threads[buffer_key.u64[1]%mtx_shared->mut_threads_count];
mtx_enqueue_op(thread, buffer_key, op); mtx_enqueue_op(thread, buffer_key, op);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Mutation Threads //~ rjf: Mutation Threads
internal void internal void
mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op) mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op)
{ {
// TODO(rjf): if op.replace is too big, need to split into multiple edits // TODO(rjf): if op.replace is too big, need to split into multiple edits
OS_MutexScope(thread->mutex) for(;;) OS_MutexScope(thread->mutex) for(;;)
{ {
U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos;
U64 available_size = thread->ring_size - unconsumed_size; U64 available_size = thread->ring_size - unconsumed_size;
if(available_size >= sizeof(buffer_key) + sizeof(op.range) + sizeof(op.replace.size) + op.replace.size) if(available_size >= sizeof(buffer_key) + sizeof(op.range) + sizeof(op.replace.size) + op.replace.size)
{ {
thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &buffer_key); thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &buffer_key);
thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &op.range); thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &op.range);
thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &op.replace.size); thread->ring_write_pos += ring_write_struct(thread->ring_base, thread->ring_size, thread->ring_write_pos, &op.replace.size);
thread->ring_write_pos += ring_write(thread->ring_base, thread->ring_size, thread->ring_write_pos, op.replace.str, op.replace.size); thread->ring_write_pos += ring_write(thread->ring_base, thread->ring_size, thread->ring_write_pos, op.replace.str, op.replace.size);
thread->ring_write_pos += 7; thread->ring_write_pos += 7;
thread->ring_write_pos -= thread->ring_write_pos%8; thread->ring_write_pos -= thread->ring_write_pos%8;
break; break;
} }
os_condition_variable_wait(thread->cv, thread->mutex, max_U64); os_condition_variable_wait(thread->cv, thread->mutex, max_U64);
} }
os_condition_variable_broadcast(thread->cv); os_condition_variable_broadcast(thread->cv);
} }
internal void internal void
mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out) mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out)
{ {
OS_MutexScope(thread->mutex) for(;;) OS_MutexScope(thread->mutex) for(;;)
{ {
U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos; U64 unconsumed_size = thread->ring_write_pos - thread->ring_read_pos;
if(unconsumed_size >= sizeof(*buffer_key_out) + sizeof(op_out->range) + sizeof(op_out->replace.size)) if(unconsumed_size >= sizeof(*buffer_key_out) + sizeof(op_out->range) + sizeof(op_out->replace.size))
{ {
thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, buffer_key_out); thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, buffer_key_out);
thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &op_out->range); thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &op_out->range);
thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &op_out->replace.size); thread->ring_read_pos += ring_read_struct(thread->ring_base, thread->ring_size, thread->ring_read_pos, &op_out->replace.size);
op_out->replace.str = push_array_no_zero(arena, U8, op_out->replace.size); op_out->replace.str = push_array_no_zero(arena, U8, op_out->replace.size);
thread->ring_read_pos += ring_read(thread->ring_base, thread->ring_size, thread->ring_read_pos, op_out->replace.str, op_out->replace.size); thread->ring_read_pos += ring_read(thread->ring_base, thread->ring_size, thread->ring_read_pos, op_out->replace.str, op_out->replace.size);
thread->ring_read_pos += 7; thread->ring_read_pos += 7;
thread->ring_read_pos -= thread->ring_read_pos%8; thread->ring_read_pos -= thread->ring_read_pos%8;
break; break;
} }
os_condition_variable_wait(thread->cv, thread->mutex, max_U64); os_condition_variable_wait(thread->cv, thread->mutex, max_U64);
} }
os_condition_variable_broadcast(thread->cv); os_condition_variable_broadcast(thread->cv);
} }
internal void internal void
mtx_mut_thread__entry_point(void *p) mtx_mut_thread__entry_point(void *p)
{ {
MTX_MutThread *mut_thread = (MTX_MutThread *)p; MTX_MutThread *mut_thread = (MTX_MutThread *)p;
ThreadNameF("[mtx] mut thread #%I64u", (U64)(mut_thread - mtx_shared->mut_threads)); ThreadNameF("[mtx] mut thread #%I64u", (U64)(mut_thread - mtx_shared->mut_threads));
for(;;) for(;;)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
HS_Scope *hs_scope = hs_scope_open(); HS_Scope *hs_scope = hs_scope_open();
//- rjf: get next op //- rjf: get next op
U128 buffer_key = {0}; U128 buffer_key = {0};
MTX_Op op = {0}; MTX_Op op = {0};
mtx_dequeue_op(scratch.arena, mut_thread, &buffer_key, &op); mtx_dequeue_op(scratch.arena, mut_thread, &buffer_key, &op);
//- rjf: get buffer's current data //- rjf: get buffer's current data
U128 hash = hs_hash_from_key(buffer_key, 0); U128 hash = hs_hash_from_key(buffer_key, 0);
String8 data = hs_data_from_hash(hs_scope, hash); String8 data = hs_data_from_hash(hs_scope, hash);
//- rjf: clamp op by data //- rjf: clamp op by data
op.range.min = Min(op.range.min, data.size); op.range.min = Min(op.range.min, data.size);
op.range.max = Min(op.range.max, data.size); op.range.max = Min(op.range.max, data.size);
//- rjf: construct new buffer //- rjf: construct new buffer
if(op.range.max != op.range.min || op.replace.size != 0) if(op.range.max != op.range.min || op.replace.size != 0)
{ {
U64 new_data_size = data.size + op.replace.size - dim_1u64(op.range); U64 new_data_size = data.size + op.replace.size - dim_1u64(op.range);
Arena *arena = arena_alloc__sized(new_data_size + ARENA_HEADER_SIZE, new_data_size + ARENA_HEADER_SIZE); Arena *arena = arena_alloc(.commit_size = new_data_size + ARENA_HEADER_SIZE, .reserve_size = new_data_size + ARENA_HEADER_SIZE);
U8 *new_data_base = push_array_no_zero(arena, U8, new_data_size); U8 *new_data_base = push_array_no_zero(arena, U8, new_data_size);
String8 pre_replace_data = str8_substr(data, r1u64(0, op.range.min)); String8 pre_replace_data = str8_substr(data, r1u64(0, op.range.min));
String8 post_replace_data = str8_substr(data, r1u64(op.range.max, data.size)); String8 post_replace_data = str8_substr(data, r1u64(op.range.max, data.size));
if(pre_replace_data.size != 0) if(pre_replace_data.size != 0)
{ {
MemoryCopy(new_data_base+0, pre_replace_data.str, pre_replace_data.size); MemoryCopy(new_data_base+0, pre_replace_data.str, pre_replace_data.size);
} }
if(op.replace.size != 0) if(op.replace.size != 0)
{ {
MemoryCopy(new_data_base+pre_replace_data.size, op.replace.str, op.replace.size); MemoryCopy(new_data_base+pre_replace_data.size, op.replace.str, op.replace.size);
} }
if(post_replace_data.size != 0) if(post_replace_data.size != 0)
{ {
MemoryCopy(new_data_base+pre_replace_data.size+op.replace.size, post_replace_data.str, post_replace_data.size); MemoryCopy(new_data_base+pre_replace_data.size+op.replace.size, post_replace_data.str, post_replace_data.size);
} }
String8 new_data = str8(new_data_base, new_data_size); String8 new_data = str8(new_data_base, new_data_size);
hs_submit_data(buffer_key, &arena, new_data); hs_submit_data(buffer_key, &arena, new_data);
} }
hs_scope_close(hs_scope); hs_scope_close(hs_scope);
scratch_end(scratch); scratch_end(scratch);
} }
} }
File diff suppressed because it is too large Load Diff
+7 -88
View File
@@ -1,88 +1,7 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef LINUX_H #ifndef OS_CORE_LINUX_H
#define LINUX_H #define OS_CORE_LINUX_H
//////////////////////////////// #endif // OS_CORE_LINUX_H
//~ NOTE(allen): Get all these linux includes
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <time.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <signal.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/sysinfo.h>
////////////////////////////////
//~ NOTE(allen): File Iterator
struct LNX_FileIter{
int fd;
DIR *dir;
};
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(LNX_FileIter), file_iter_memory_size);
////////////////////////////////
//~ NOTE(allen): Threading Entities
enum LNX_EntityKind{
LNX_EntityKind_Null,
LNX_EntityKind_Thread,
LNX_EntityKind_Mutex,
LNX_EntityKind_ConditionVariable,
};
struct LNX_Entity{
LNX_Entity *next;
LNX_EntityKind kind;
volatile U32 reference_mask;
union{
struct{
OS_ThreadFunctionType *func;
void *ptr;
pthread_t handle;
} thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
};
////////////////////////////////
//~ NOTE(allen): Safe Call Chain
struct LNX_SafeCallChain{
LNX_SafeCallChain *next;
OS_ThreadFunctionType *fail_handler;
void *ptr;
};
////////////////////////////////
//~ NOTE(allen): Helpers
internal B32 lnx_write_list_to_file_descriptor(int fd, String8List list);
internal void lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec);
internal void lnx_tm_from_date_time(struct tm *out, DateTime *in);
internal void lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in);
internal void lnx_file_properties_from_stat(FileProperties *out, struct stat *in);
internal String8 lnx_string_from_signal(int signum);
internal String8 lnx_string_from_errno(int error_number);
internal LNX_Entity* lnx_alloc_entity(LNX_EntityKind kind);
internal void lnx_free_entity(LNX_Entity *entity);
internal void* lnx_thread_base(void *ptr);
internal void lnx_safe_call_sig_handler(int);
#endif //LINUX_H
File diff suppressed because it is too large Load Diff
+88
View File
@@ -0,0 +1,88 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef LINUX_H
#define LINUX_H
////////////////////////////////
//~ NOTE(allen): Get all these linux includes
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <time.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <signal.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/sysinfo.h>
////////////////////////////////
//~ NOTE(allen): File Iterator
struct LNX_FileIter{
int fd;
DIR *dir;
};
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(LNX_FileIter), file_iter_memory_size);
////////////////////////////////
//~ NOTE(allen): Threading Entities
enum LNX_EntityKind{
LNX_EntityKind_Null,
LNX_EntityKind_Thread,
LNX_EntityKind_Mutex,
LNX_EntityKind_ConditionVariable,
};
struct LNX_Entity{
LNX_Entity *next;
LNX_EntityKind kind;
volatile U32 reference_mask;
union{
struct{
OS_ThreadFunctionType *func;
void *ptr;
pthread_t handle;
} thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
};
////////////////////////////////
//~ NOTE(allen): Safe Call Chain
struct LNX_SafeCallChain{
LNX_SafeCallChain *next;
OS_ThreadFunctionType *fail_handler;
void *ptr;
};
////////////////////////////////
//~ NOTE(allen): Helpers
internal B32 lnx_write_list_to_file_descriptor(int fd, String8List list);
internal void lnx_date_time_from_tm(DateTime *out, struct tm *in, U32 msec);
internal void lnx_tm_from_date_time(struct tm *out, DateTime *in);
internal void lnx_dense_time_from_timespec(DenseTime *out, struct timespec *in);
internal void lnx_file_properties_from_stat(FileProperties *out, struct stat *in);
internal String8 lnx_string_from_signal(int signum);
internal String8 lnx_string_from_errno(int error_number);
internal LNX_Entity* lnx_alloc_entity(LNX_EntityKind kind);
internal void lnx_free_entity(LNX_Entity *entity);
internal void* lnx_thread_base(void *ptr);
internal void lnx_safe_call_sig_handler(int);
#endif //LINUX_H
+173 -243
View File
@@ -1,243 +1,173 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once) //~ rjf: Handle Type Functions (Helpers, Implemented Once)
internal OS_Handle internal OS_Handle
os_handle_zero(void) os_handle_zero(void)
{ {
OS_Handle handle = {0}; OS_Handle handle = {0};
return handle; return handle;
} }
internal B32 internal B32
os_handle_match(OS_Handle a, OS_Handle b) os_handle_match(OS_Handle a, OS_Handle b)
{ {
return a.u64[0] == b.u64[0]; return a.u64[0] == b.u64[0];
} }
internal void internal void
os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle) os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle)
{ {
OS_HandleNode *n = push_array(arena, OS_HandleNode, 1); OS_HandleNode *n = push_array(arena, OS_HandleNode, 1);
n->v = handle; n->v = handle;
SLLQueuePush(handles->first, handles->last, n); SLLQueuePush(handles->first, handles->last, n);
handles->count += 1; handles->count += 1;
} }
internal OS_HandleArray internal OS_HandleArray
os_handle_array_from_list(Arena *arena, OS_HandleList *list) os_handle_array_from_list(Arena *arena, OS_HandleList *list)
{ {
OS_HandleArray result = {0}; OS_HandleArray result = {0};
result.count = list->count; result.count = list->count;
result.v = push_array_no_zero(arena, OS_Handle, result.count); result.v = push_array_no_zero(arena, OS_Handle, result.count);
U64 idx = 0; U64 idx = 0;
for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1)
{ {
result.v[idx] = n->v; result.v[idx] = n->v;
} }
return result; return result;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: System Path Helper (Helper, Implemented Once) //~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal String8 internal String8List
os_string_from_system_path(Arena *arena, OS_SystemPath path) os_string_list_from_argcv(Arena *arena, int argc, char **argv)
{ {
String8List strs = {0}; String8List result = {0};
os_string_list_from_system_path(arena, path, &strs); for(int i = 0; i < argc; i += 1)
String8 result = str8_list_first(&strs); {
return result; String8 str = str8_cstring(argv[i]);
} str8_list_push(arena, &result, str);
}
//////////////////////////////// return result;
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) }
internal String8List ////////////////////////////////
os_string_list_from_argcv(Arena *arena, int argc, char **argv) //~ rjf: Filesystem Helpers (Helpers, Implemented Once)
{
String8List result = {0}; internal String8
for(int i = 0; i < argc; i += 1) os_data_from_file_path(Arena *arena, String8 path)
{ {
String8 str = str8_cstring(argv[i]); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
str8_list_push(arena, &result, str); FileProperties props = os_properties_from_file(file);
} String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size));
return result; os_file_close(file);
} return data;
}
////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once) internal B32
os_write_data_to_file_path(String8 path, String8 data)
internal String8 {
os_data_from_file_path(Arena *arena, String8 path) B32 good = 0;
{ OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); if(!os_handle_match(file, os_handle_zero()))
FileProperties props = os_properties_from_file(file); {
String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size)); good = 1;
os_file_close(file); os_file_write(file, r1u64(0, data.size), data.str);
return data; os_file_close(file);
} }
return good;
internal B32 }
os_write_data_to_file_path(String8 path, String8 data)
{ internal B32
B32 good = 0; os_write_data_list_to_file_path(String8 path, String8List list)
OS_Handle file = os_file_open(OS_AccessFlag_Write, path); {
if(!os_handle_match(file, os_handle_zero())) B32 good = 0;
{ OS_Handle file = os_file_open(OS_AccessFlag_Write, path);
good = 1; if(!os_handle_match(file, os_handle_zero()))
os_file_write(file, r1u64(0, data.size), data.str); {
os_file_close(file); good = 1;
} U64 off = 0;
return good; for(String8Node *n = list.first; n != 0; n = n->next)
} {
os_file_write(file, r1u64(off, off+n->string.size), n->string.str);
internal B32 off += n->string.size;
os_write_data_list_to_file_path(String8 path, String8List list) }
{ os_file_close(file);
B32 good = 0; }
OS_Handle file = os_file_open(OS_AccessFlag_Write, path); return good;
if(!os_handle_match(file, os_handle_zero())) }
{
good = 1; internal B32
U64 off = 0; os_append_data_to_file_path(String8 path, String8 data)
for(String8Node *n = list.first; n != 0; n = n->next) {
{ B32 good = 0;
os_file_write(file, r1u64(off, off+n->string.size), n->string.str); if(data.size != 0)
off += n->string.size; {
} OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append, path);
os_file_close(file); if(!os_handle_match(file, os_handle_zero()))
} {
return good; good = 1;
} U64 pos = os_properties_from_file(file).size;
os_file_write(file, r1u64(pos, pos+data.size), data.str);
internal B32 os_file_close(file);
os_append_data_to_file_path(String8 path, String8 data) }
{ }
B32 good = 0; return good;
if(data.size != 0) }
{
OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append, path); internal OS_FileID
if(!os_handle_match(file, os_handle_zero())) os_id_from_file_path(String8 path)
{ {
good = 1; OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
U64 pos = os_properties_from_file(file).size; OS_FileID id = os_id_from_file(file);
os_file_write(file, r1u64(pos, pos+data.size), data.str); os_file_close(file);
os_file_close(file); return id;
} }
}
return good; internal S64
} os_file_id_compare(OS_FileID a, OS_FileID b)
{
internal OS_FileID S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
os_id_from_file_path(String8 path) return cmp;
{ }
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path);
OS_FileID id = os_id_from_file(file); internal String8
os_file_close(file); os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range)
return id; {
} U64 pre_pos = arena_pos(arena);
String8 result;
internal S64 result.size = dim_1u64(range);
os_file_id_compare(OS_FileID a, OS_FileID b) result.str = push_array_no_zero(arena, U8, result.size);
{ U64 actual_read_size = os_file_read(file, range, result.str);
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v)); if(actual_read_size < result.size)
return cmp; {
} arena_pop_to(arena, pre_pos + actual_read_size);
result.size = actual_read_size;
internal String8 }
os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) return result;
{ }
U64 pre_pos = arena_pos(arena);
String8 result; ////////////////////////////////
result.size = dim_1u64(range); //~ rjf: GUID Helpers (Helpers, Implemented Once)
result.str = push_array_no_zero(arena, U8, result.size);
U64 actual_read_size = os_file_read(file, range, result.str); internal String8
if(actual_read_size < result.size) os_string_from_guid(Arena *arena, OS_Guid guid)
{ {
arena_pop_to(arena, pre_pos + actual_read_size); String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
result.size = actual_read_size; guid.data1,
} guid.data2,
return result; guid.data3,
} guid.data4[0],
guid.data4[1],
//////////////////////////////// guid.data4[2],
//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) guid.data4[3],
guid.data4[4],
internal void guid.data4[5],
os_mutex_take(OS_Handle mutex){ guid.data4[6],
os_mutex_take_(mutex); guid.data4[7]);
} return result;
}
internal void
os_mutex_drop(OS_Handle mutex){
os_mutex_drop_(mutex);
}
internal void
os_rw_mutex_take_r(OS_Handle rw_mutex){
os_rw_mutex_take_r_(rw_mutex);
}
internal void
os_rw_mutex_drop_r(OS_Handle rw_mutex){
os_rw_mutex_drop_r_(rw_mutex);
}
internal void
os_rw_mutex_take_w(OS_Handle rw_mutex){
os_rw_mutex_take_w_(rw_mutex);
}
internal void
os_rw_mutex_drop_w(OS_Handle rw_mutex){
os_rw_mutex_drop_w_(rw_mutex);
}
internal B32
os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us){
B32 result = os_condition_variable_wait_(cv, mutex, endt_us);
return(result);
}
internal B32
os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){
B32 result = os_condition_variable_wait_rw_r_(cv, mutex_rw, endt_us);
return(result);
}
internal B32
os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){
B32 result = os_condition_variable_wait_rw_w_(cv, mutex_rw, endt_us);
return(result);
}
internal void
os_condition_variable_signal(OS_Handle cv){
os_condition_variable_signal_(cv);
}
internal void
os_condition_variable_broadcast(OS_Handle cv){
os_condition_variable_broadcast_(cv);
}
internal String8
os_string_from_guid(Arena *arena, OS_Guid guid)
{
String8 result = push_str8f(arena, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid.data1,
guid.data2,
guid.data3,
guid.data4[0],
guid.data4[1],
guid.data4[2],
guid.data4[3],
guid.data4[4],
guid.data4[5],
guid.data4[6],
guid.data4[7]);
return result;
}
+339 -380
View File
@@ -1,380 +1,339 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_CORE_H #ifndef OS_CORE_H
#define OS_CORE_H #define OS_CORE_H
//////////////////////////////// ////////////////////////////////
//~ rjf: Access Flags //~ rjf: System Info
typedef U32 OS_AccessFlags; typedef struct OS_SystemInfo OS_SystemInfo;
enum struct OS_SystemInfo
{ {
OS_AccessFlag_Read = (1<<0), U32 logical_processor_count;
OS_AccessFlag_Write = (1<<1), U64 page_size;
OS_AccessFlag_Execute = (1<<2), U64 large_page_size;
OS_AccessFlag_Append = (1<<3), U64 allocation_granularity;
OS_AccessFlag_ShareRead = (1<<4), U64 microsecond_resolution;
OS_AccessFlag_ShareWrite = (1<<5), String8 machine_name;
}; };
//////////////////////////////// ////////////////////////////////
//~ allen: Files //~ rjf: Process Info
typedef U32 OS_FileIterFlags; typedef struct OS_ProcessInfo OS_ProcessInfo;
enum struct OS_ProcessInfo
{ {
OS_FileIterFlag_SkipFolders = (1 << 0), U32 pid;
OS_FileIterFlag_SkipFiles = (1 << 1), String8 binary_path;
OS_FileIterFlag_SkipHiddenFiles = (1 << 2), String8 initial_path;
OS_FileIterFlag_Done = (1 << 31), String8 user_program_data_path;
}; String8List module_load_paths;
String8List environment;
typedef struct OS_FileIter OS_FileIter; };
struct OS_FileIter
{ ////////////////////////////////
OS_FileIterFlags flags; //~ rjf: Access Flags
U8 memory[800];
}; typedef U32 OS_AccessFlags;
enum
typedef struct OS_FileInfo OS_FileInfo; {
struct OS_FileInfo OS_AccessFlag_Read = (1<<0),
{ OS_AccessFlag_Write = (1<<1),
String8 name; OS_AccessFlag_Execute = (1<<2),
FileProperties props; OS_AccessFlag_Append = (1<<3),
}; OS_AccessFlag_ShareRead = (1<<4),
OS_AccessFlag_ShareWrite = (1<<5),
// nick: on-disk file identifier };
typedef struct OS_FileID OS_FileID;
struct OS_FileID ////////////////////////////////
{ //~ rjf: Files
U64 v[3];
}; typedef U32 OS_FileIterFlags;
enum
//////////////////////////////// {
//~ rjf: System Paths OS_FileIterFlag_SkipFolders = (1 << 0),
OS_FileIterFlag_SkipFiles = (1 << 1),
typedef enum OS_SystemPath OS_FileIterFlag_SkipHiddenFiles = (1 << 2),
{ OS_FileIterFlag_Done = (1 << 31),
OS_SystemPath_Binary, };
OS_SystemPath_Initial,
OS_SystemPath_Current, typedef struct OS_FileIter OS_FileIter;
OS_SystemPath_UserProgramData, struct OS_FileIter
OS_SystemPath_ModuleLoad, {
} OS_FileIterFlags flags;
OS_SystemPath; U8 memory[800];
};
typedef enum OS_PathFromUserKind
{ typedef struct OS_FileInfo OS_FileInfo;
OS_PathFromUserKind_Save, struct OS_FileInfo
OS_PathFromUserKind_Load, {
} String8 name;
OS_PathFromUserKind; FileProperties props;
};
typedef struct OS_PathFromUser OS_PathFromUser;
struct OS_PathFromUser // nick: on-disk file identifier
{ typedef struct OS_FileID OS_FileID;
OS_PathFromUserKind kind; struct OS_FileID
String8 path; {
U64 filter_count; U64 v[3];
String8 *filter_extensions; };
String8 *filter_names;
}; ////////////////////////////////
//~ rjf: Process Launch Parameters
////////////////////////////////
//~ allen: Launch Input typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams;
struct OS_ProcessLaunchParams
typedef struct OS_LaunchOptions OS_LaunchOptions; {
struct OS_LaunchOptions String8List cmd_line;
{ String8 path;
String8List cmd_line; String8List env;
String8 path; B32 inherit_env;
String8List env; B32 consoleless;
B32 inherit_env; };
B32 consoleless;
}; ////////////////////////////////
//~ rjf: Handle Type
////////////////////////////////
//~ rjf: Handle Type typedef struct OS_Handle OS_Handle;
struct OS_Handle
typedef struct OS_Handle OS_Handle; {
struct OS_Handle U64 u64[1];
{ };
U64 u64[1];
}; typedef struct OS_HandleNode OS_HandleNode;
struct OS_HandleNode
typedef struct OS_HandleNode OS_HandleNode; {
struct OS_HandleNode OS_HandleNode *next;
{ OS_Handle v;
OS_HandleNode *next; };
OS_Handle v;
}; typedef struct OS_HandleList OS_HandleList;
struct OS_HandleList
typedef struct OS_HandleList OS_HandleList; {
struct OS_HandleList OS_HandleNode *first;
{ OS_HandleNode *last;
OS_HandleNode *first; U64 count;
OS_HandleNode *last; };
U64 count;
}; typedef struct OS_HandleArray OS_HandleArray;
struct OS_HandleArray
typedef struct OS_HandleArray OS_HandleArray; {
struct OS_HandleArray OS_Handle *v;
{ U64 count;
OS_Handle *v; };
U64 count;
}; ////////////////////////////////
//~ rjf: Globally Unique IDs
////////////////////////////////
// Time typedef struct OS_Guid OS_Guid;
struct OS_Guid
#define OS_UNIX_TIME_MAX max_U32 {
typedef U32 OS_UnixTime; U32 data1;
U16 data2;
//////////////////////////////// U16 data3;
// Global Unique ID U8 data4[8];
};
typedef struct OS_Guid StaticAssert(sizeof(OS_Guid) == 16, os_guid_check);
{
U32 data1; ////////////////////////////////
U16 data2; //~ rjf: Thread Types
U16 data3;
U8 data4[8]; typedef void OS_ThreadFunctionType(void *ptr);
} OS_Guid;
StaticAssert(sizeof(OS_Guid) == 16, os_guid_check); ////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once)
////////////////////////////////
//~ rjf: Thread Types internal OS_Handle os_handle_zero(void);
internal B32 os_handle_match(OS_Handle a, OS_Handle b);
typedef void OS_ThreadFunctionType(void *ptr); internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle);
internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list);
////////////////////////////////
//~ rjf: Handle Type Functions (Helpers, Implemented Once) ////////////////////////////////
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once)
internal OS_Handle os_handle_zero(void);
internal B32 os_handle_match(OS_Handle a, OS_Handle b); internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
internal void os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle);
internal OS_HandleArray os_handle_array_from_list(Arena *arena, OS_HandleList *list); ////////////////////////////////
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
////////////////////////////////
//~ rjf: System Path Helper (Helper, Implemented Once) internal String8 os_data_from_file_path(Arena *arena, String8 path);
internal B32 os_write_data_to_file_path(String8 path, String8 data);
internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path); internal B32 os_write_data_list_to_file_path(String8 path, String8List list);
internal B32 os_append_data_to_file_path(String8 path, String8 data);
//////////////////////////////// internal OS_FileID os_id_from_file_path(String8 path);
//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) internal S64 os_file_id_compare(OS_FileID a, OS_FileID b);
internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range);
internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv);
////////////////////////////////
//////////////////////////////// //~ rjf: GUID Helpers (Helpers, Implemented Once)
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
internal String8 os_string_from_guid(Arena *arena, OS_Guid guid);
internal String8 os_data_from_file_path(Arena *arena, String8 path);
internal B32 os_write_data_to_file_path(String8 path, String8 data); ////////////////////////////////
internal B32 os_write_data_list_to_file_path(String8 path, String8List list); //~ rjf: @os_hooks System/Process Info (Implemented Per-OS)
internal B32 os_append_data_to_file_path(String8 path, String8 data);
internal OS_FileID os_id_from_file_path(String8 path); internal OS_SystemInfo *os_get_system_info(void);
internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); internal OS_ProcessInfo *os_get_process_info(void);
internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); internal String8 os_get_current_path(Arena *arena);
//////////////////////////////// ////////////////////////////////
//~ rjf: Synchronization Primitive Helpers (Helpers, Implemented Once) //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS)
internal void os_mutex_take(OS_Handle mutex); //- rjf: basic
internal void os_mutex_drop(OS_Handle mutex); internal void *os_reserve(U64 size);
internal void os_rw_mutex_take_r(OS_Handle rw_mutex); internal B32 os_commit(void *ptr, U64 size);
internal void os_rw_mutex_drop_r(OS_Handle rw_mutex); internal void os_decommit(void *ptr, U64 size);
internal void os_rw_mutex_take_w(OS_Handle rw_mutex); internal void os_release(void *ptr, U64 size);
internal void os_rw_mutex_drop_w(OS_Handle rw_mutex);
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout //- rjf: large pages
internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us); internal B32 os_set_large_pages_enabled(B32 flag);
internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); internal B32 os_large_pages_enabled(void);
internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle rw_mutex, U64 endt_us); internal void *os_reserve_large(U64 size);
internal void os_condition_variable_signal(OS_Handle cv); internal B32 os_commit_large(void *ptr, U64 size);
internal void os_condition_variable_broadcast(OS_Handle cv);
////////////////////////////////
#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) //~ rjf: @os_hooks Thread Info (Implemented Per-OS)
#define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex))
#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex)) internal U32 os_tid(void);
#define OS_MutexScopeRWPromote(mutex) DeferLoop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex))) internal void os_set_thread_name(String8 string);
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) //~ rjf: @os_hooks Aborting (Implemented Per-OS)
internal void os_init(void); internal void os_abort(S32 exit_code);
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) //~ rjf: @os_hooks File System (Implemented Per-OS)
internal void* os_reserve(U64 size); //- rjf: files
internal B32 os_commit(void *ptr, U64 size); internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path);
internal void* os_reserve_large(U64 size); internal void os_file_close(OS_Handle file);
internal B32 os_commit_large(void *ptr, U64 size); internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data);
internal void os_decommit(void *ptr, U64 size); internal void os_file_write(OS_Handle file, Rng1U64 rng, void *data);
internal void os_release(void *ptr, U64 size); internal B32 os_file_set_times(OS_Handle file, DateTime time);
internal FileProperties os_properties_from_file(OS_Handle file);
internal B32 os_set_large_pages(B32 flag); internal OS_FileID os_id_from_file(OS_Handle file);
internal B32 os_large_pages_enabled(void); internal B32 os_delete_file_at_path(String8 path);
internal U64 os_large_page_size(void); internal B32 os_copy_file_path(String8 dst, String8 src);
internal String8 os_full_path_from_path(Arena *arena, String8 path);
internal void* os_alloc_ring_buffer(U64 size, U64 *actual_size_out); internal B32 os_file_path_exists(String8 path);
internal void os_free_ring_buffer(void *ring_buffer, U64 actual_size); internal FileProperties os_properties_from_file_path(String8 path);
//////////////////////////////// //- rjf: file maps
//~ rjf: @os_hooks System Info (Implemented Per-OS) internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file);
internal void os_file_map_close(OS_Handle map);
internal String8 os_machine_name(void); internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range);
internal U64 os_page_size(void); internal void os_file_map_view_close(OS_Handle map, void *ptr);
internal U64 os_allocation_granularity(void);
internal U64 os_logical_core_count(void); //- rjf: directory iteration
internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags);
//////////////////////////////// internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out);
//~ rjf: @os_hooks Process & Thread Info (Implemented Per-OS) internal void os_file_iter_end(OS_FileIter *iter);
internal S32 os_get_pid(void); //- rjf: directory creation
internal S32 os_get_tid(void); internal B32 os_make_directory(String8 path);
internal String8List os_get_environment(void);
internal U64 os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out); ////////////////////////////////
//~ rjf: @os_hooks Shared Memory (Implemented Per-OS)
////////////////////////////////
//~ rjf: @os_hooks Thread Names internal OS_Handle os_shared_memory_alloc(U64 size, String8 name);
internal OS_Handle os_shared_memory_open(String8 name);
internal void os_set_thread_name(String8 string); internal void os_shared_memory_close(OS_Handle handle);
internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range);
//////////////////////////////// internal void os_shared_memory_view_close(OS_Handle handle, void *ptr);
//~ rjf: @os_hooks Process Control (Implemented Per-OS)
////////////////////////////////
internal void os_exit_process(S32 exit_code); //~ rjf: @os_hooks Time (Implemented Per-OS)
//////////////////////////////// internal U64 os_now_microseconds(void);
//~ rjf: @os_hooks File System (Implemented Per-OS) internal U32 os_now_unix(void);
internal DateTime os_now_universal_time(void);
//- rjf: files internal DateTime os_universal_time_from_local(DateTime *local_time);
internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); internal DateTime os_local_time_from_universal(DateTime *universal_time);
internal void os_file_close(OS_Handle file); internal void os_sleep_milliseconds(U32 msec);
internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data);
internal void os_file_write(OS_Handle file, Rng1U64 rng, void *data); ////////////////////////////////
internal B32 os_file_set_times(OS_Handle file, DateTime time); //~ rjf: @os_hooks Child Processes (Implemented Per-OS)
internal FileProperties os_properties_from_file(OS_Handle file);
internal OS_FileID os_id_from_file(OS_Handle file); internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params);
internal B32 os_delete_file_at_path(String8 path); internal B32 os_process_join(OS_Handle handle, U64 endt_us);
internal B32 os_copy_file_path(String8 dst, String8 src); internal void os_process_detach(OS_Handle handle);
internal String8 os_full_path_from_path(Arena *arena, String8 path);
internal B32 os_file_path_exists(String8 path); ////////////////////////////////
internal FileProperties os_properties_from_file_path(String8 path); //~ rjf: @os_hooks Threads (Implemented Per-OS)
//- rjf: file maps internal OS_Handle os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params);
internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file); internal B32 os_thread_join(OS_Handle handle, U64 endt_us);
internal void os_file_map_close(OS_Handle map); internal void os_thread_detach(OS_Handle handle);
internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range);
internal void os_file_map_view_close(OS_Handle map, void *ptr); ////////////////////////////////
//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS)
//- rjf: directory iteration
internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags); //- rjf: recursive mutexes
internal B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out); internal OS_Handle os_mutex_alloc(void);
internal void os_file_iter_end(OS_FileIter *iter); internal void os_mutex_release(OS_Handle mutex);
internal void os_mutex_take(OS_Handle mutex);
//- rjf: directory creation internal void os_mutex_drop(OS_Handle mutex);
internal B32 os_make_directory(String8 path);
//- rjf: reader/writer mutexes
//////////////////////////////// internal OS_Handle os_rw_mutex_alloc(void);
//~ rjf: @os_hooks Shared Memory (Implemented Per-OS) internal void os_rw_mutex_release(OS_Handle rw_mutex);
internal void os_rw_mutex_take_r(OS_Handle mutex);
internal OS_Handle os_shared_memory_alloc(U64 size, String8 name); internal void os_rw_mutex_drop_r(OS_Handle mutex);
internal OS_Handle os_shared_memory_open(String8 name); internal void os_rw_mutex_take_w(OS_Handle mutex);
internal void os_shared_memory_close(OS_Handle handle); internal void os_rw_mutex_drop_w(OS_Handle mutex);
internal void * os_shared_memory_view_open(OS_Handle handle, Rng1U64 range);
internal void os_shared_memory_view_close(OS_Handle handle, void *ptr); //- rjf: condition variables
internal OS_Handle os_condition_variable_alloc(void);
//////////////////////////////// internal void os_condition_variable_release(OS_Handle cv);
//~ rjf: @os_hooks Time (Implemented Per-OS) // returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us);
internal OS_UnixTime os_now_unix(void); internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
internal DateTime os_now_universal_time(void); internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
internal DateTime os_universal_time_from_local_time(DateTime *local_time); internal void os_condition_variable_signal(OS_Handle cv);
internal DateTime os_local_time_from_universal_time(DateTime *universal_time); internal void os_condition_variable_broadcast(OS_Handle cv);
internal U64 os_now_microseconds(void);
internal void os_sleep_milliseconds(U32 msec); //- rjf: cross-process semaphores
internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
//////////////////////////////// internal void os_semaphore_release(OS_Handle semaphore);
//~ rjf: @os_hooks Child Processes (Implemented Per-OS) internal OS_Handle os_semaphore_open(String8 name);
internal void os_semaphore_close(OS_Handle semaphore);
internal B32 os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out); internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us);
internal B32 os_process_wait(OS_Handle handle, U64 endt_us); internal void os_semaphore_drop(OS_Handle semaphore);
internal void os_process_release_handle(OS_Handle handle);
//- rjf: scope macros
//////////////////////////////// #define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex))
//~ rjf: @os_hooks Threads (Implemented Per-OS) #define OS_MutexScopeR(mutex) DeferLoop(os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex))
#define OS_MutexScopeW(mutex) DeferLoop(os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex))
internal OS_Handle os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params); #define OS_MutexScopeRWPromote(mutex) DeferLoop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex)))
internal B32 os_thread_wait(OS_Handle handle, U64 endt_us);
internal void os_release_thread_handle(OS_Handle thread); ////////////////////////////////
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
////////////////////////////////
//~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) internal OS_Handle os_library_open(String8 path);
internal void os_library_close(OS_Handle lib);
// NOTE(allen): Mutexes are recursive - support counted acquire/release nesting internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name);
// on a single thread
////////////////////////////////
//- rjf: recursive mutexes //~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal OS_Handle os_mutex_alloc(void);
internal void os_mutex_release(OS_Handle mutex); internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr);
internal void os_mutex_take_(OS_Handle mutex);
internal void os_mutex_drop_(OS_Handle mutex); ////////////////////////////////
//~ rjf: @os_hooks GUIDs (Implemented Per-OS)
//- rjf: reader/writer mutexes
internal OS_Handle os_rw_mutex_alloc(void); internal OS_Guid os_make_guid(void);
internal void os_rw_mutex_release(OS_Handle rw_mutex);
internal void os_rw_mutex_take_r_(OS_Handle mutex); ////////////////////////////////
internal void os_rw_mutex_drop_r_(OS_Handle mutex); //~ rjf: @os_hooks Entry Points (Implemented Per-OS)
internal void os_rw_mutex_take_w_(OS_Handle mutex);
internal void os_rw_mutex_drop_w_(OS_Handle mutex); // NOTE(rjf): The implementation of `os_core` will define low-level entry
// points if BUILD_ENTRY_DEFINING_UNIT is defined to 1. These will call
//- rjf: condition variables // into the standard codebase program entry points, named "entry_point".
internal OS_Handle os_condition_variable_alloc(void);
internal void os_condition_variable_release(OS_Handle cv); #if BUILD_ENTRY_DEFINING_UNIT
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout internal void entry_point(CmdLine *cmdline);
internal B32 os_condition_variable_wait_(OS_Handle cv, OS_Handle mutex, U64 endt_us); #endif
internal B32 os_condition_variable_wait_rw_r_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us);
internal B32 os_condition_variable_wait_rw_w_(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); #endif // OS_CORE_H
internal void os_condition_variable_signal_(OS_Handle cv);
internal void os_condition_variable_broadcast_(OS_Handle cv);
//- rjf: cross-process semaphores
internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
internal void os_semaphore_release(OS_Handle semaphore);
internal OS_Handle os_semaphore_open(String8 name);
internal void os_semaphore_close(OS_Handle semaphore);
internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us);
internal void os_semaphore_drop(OS_Handle semaphore);
////////////////////////////////
//~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS)
internal OS_Handle os_library_open(String8 path);
internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name);
internal void os_library_close(OS_Handle lib);
////////////////////////////////
//~ rjf: @os_hooks Safe Calls (Implemented Per-OS)
internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr);
////////////////////////////////
//~ rjf: @os_hooks GUIDs (Implemented Per-OS)
internal OS_Guid os_make_guid(void);
internal String8 os_string_from_guid(Arena *arena, OS_Guid guid);
////////////////////////////////
//~ rjf: @os_hooks Entry Points (Implemented Per-OS)
// NOTE(rjf): The implementation of `os_core` will define low-level entry
// points if BUILD_ENTRY_DEFINING_UNIT is defined to 1. These will call
// into the standard codebase program entry points, named "entry_point".
#if BUILD_ENTRY_DEFINING_UNIT
internal void entry_point(CmdLine *cmdline);
#endif
#endif // OS_CORE_H
File diff suppressed because it is too large Load Diff
+124 -84
View File
@@ -1,84 +1,124 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_H #ifndef OS_CORE_WIN32_H
#define WIN32_H #define OS_CORE_WIN32_H
//////////////////////////////// ////////////////////////////////
//~ NOTE(allen): Negotiate the windows header include order //~ rjf: Includes / Libraries
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <windowsx.h> #include <windowsx.h>
#include <timeapi.h> #include <timeapi.h>
#include <tlhelp32.h> #include <tlhelp32.h>
#include <Shlobj.h> #include <Shlobj.h>
#include <processthreadsapi.h> #include <processthreadsapi.h>
#pragma comment(lib, "user32")
//////////////////////////////// #pragma comment(lib, "winmm")
//~ NOTE(allen): File Iterator #pragma comment(lib, "shell32")
#pragma comment(lib, "advapi32")
typedef struct W32_FileIter W32_FileIter; #pragma comment(lib, "rpcrt4")
struct W32_FileIter #pragma comment(lib, "shlwapi")
{ #pragma comment(lib, "comctl32")
HANDLE handle; #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // this is required for loading correct comctl32 dll file
WIN32_FIND_DATAW find_data;
B32 is_volume_iter; ////////////////////////////////
String8Array drive_strings; //~ rjf: File Iterator Types
U64 drive_strings_iter_idx;
}; typedef struct OS_W32_FileIter OS_W32_FileIter;
StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(W32_FileIter), file_iter_memory_size); struct OS_W32_FileIter
{
//////////////////////////////// HANDLE handle;
//~ NOTE(allen): Threading Entities WIN32_FIND_DATAW find_data;
B32 is_volume_iter;
typedef enum W32_EntityKind String8Array drive_strings;
{ U64 drive_strings_iter_idx;
W32_EntityKind_Null, };
W32_EntityKind_Thread, StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_W32_FileIter), file_iter_memory_size);
W32_EntityKind_Mutex,
W32_EntityKind_RWMutex, ////////////////////////////////
W32_EntityKind_ConditionVariable, //~ rjf: Entity Types
}
W32_EntityKind; typedef enum OS_W32_EntityKind
{
typedef struct W32_Entity W32_Entity; OS_W32_EntityKind_Null,
struct W32_Entity OS_W32_EntityKind_Thread,
{ OS_W32_EntityKind_Mutex,
W32_Entity *next; OS_W32_EntityKind_RWMutex,
W32_EntityKind kind; OS_W32_EntityKind_ConditionVariable,
volatile U32 reference_mask; }
union{ OS_W32_EntityKind;
struct{
OS_ThreadFunctionType *func; typedef struct OS_W32_Entity OS_W32_Entity;
void *ptr; struct OS_W32_Entity
HANDLE handle; {
DWORD tid; OS_W32_Entity *next;
} thread; OS_W32_EntityKind kind;
CRITICAL_SECTION mutex; union
SRWLOCK rw_mutex; {
CONDITION_VARIABLE cv; struct
}; {
}; OS_ThreadFunctionType *func;
void *ptr;
//////////////////////////////// HANDLE handle;
//~ rjf: Helpers DWORD tid;
} thread;
//- rjf: files CRITICAL_SECTION mutex;
internal FilePropertyFlags w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes); SRWLOCK rw_mutex;
internal void w32_file_properties_from_attributes(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes); CONDITION_VARIABLE cv;
};
//- rjf: time };
internal void w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in);
internal void w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in); ////////////////////////////////
internal void w32_dense_time_from_file_time(DenseTime *out, FILETIME *in); //~ rjf: State
internal U32 w32_sleep_ms_from_endt_us(U64 endt_us);
typedef struct OS_W32_State OS_W32_State;
//- rjf: entities struct OS_W32_State
internal W32_Entity* w32_alloc_entity(W32_EntityKind kind); {
internal void w32_free_entity(W32_Entity *entity); Arena *arena;
//- rjf: threads // rjf: info
internal DWORD w32_thread_base(void *ptr); OS_SystemInfo system_info;
OS_ProcessInfo process_info;
#endif //WIN32_H
// rjf: large pages
B32 large_pages_enabled;
// rjf: entity storage
CRITICAL_SECTION entity_mutex;
Arena *entity_arena;
OS_W32_Entity *entity_free;
};
////////////////////////////////
//~ rjf: Globals
global OS_W32_State os_w32_state = {0};
////////////////////////////////
//~ rjf: File Info Conversion Helpers
internal FilePropertyFlags os_w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes);
internal void os_w32_file_properties_from_attribute_data(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes);
////////////////////////////////
//~ rjf: Time Conversion Helpers
internal void os_w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in);
internal void os_w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in);
internal void os_w32_dense_time_from_file_time(DenseTime *out, FILETIME *in);
internal U32 os_w32_sleep_ms_from_endt_us(U64 endt_us);
////////////////////////////////
//~ rjf: Entity Functions
internal OS_W32_Entity *os_w32_entity_alloc(OS_W32_EntityKind kind);
internal void os_w32_entity_release(OS_W32_Entity *entity);
////////////////////////////////
//~ rjf: Thread Entry Point
internal DWORD os_w32_thread_entry_point(void *ptr);
#endif // OS_CORE_WIN32_H
+191 -182
View File
@@ -1,182 +1,191 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_GRAPHICAL_H #ifndef OS_GRAPHICAL_H
#define OS_GRAPHICAL_H #define OS_GRAPHICAL_H
//////////////////////////////// ////////////////////////////////
//~ rjf: Window Types //~ rjf: Graphics System Info
typedef U32 OS_WindowFlags; typedef struct OS_GfxInfo OS_GfxInfo;
enum struct OS_GfxInfo
{ {
OS_WindowFlag_CustomBorder = (1<<0), F32 double_click_time;
}; F32 caret_blink_time;
F32 default_refresh_rate;
typedef void OS_WindowRepaintFunctionType(OS_Handle window, void *user_data); };
//////////////////////////////// ////////////////////////////////
//~ rjf: Cursor Types //~ rjf: Window Types
typedef enum OS_Cursor typedef U32 OS_WindowFlags;
{ enum
OS_Cursor_Pointer, {
OS_Cursor_IBar, OS_WindowFlag_CustomBorder = (1<<0),
OS_Cursor_LeftRight, };
OS_Cursor_UpDown,
OS_Cursor_DownRight, typedef void OS_WindowRepaintFunctionType(OS_Handle window, void *user_data);
OS_Cursor_UpRight,
OS_Cursor_UpDownLeftRight, ////////////////////////////////
OS_Cursor_HandPoint, //~ rjf: Cursor Types
OS_Cursor_Disabled,
OS_Cursor_COUNT, typedef enum OS_Cursor
} {
OS_Cursor; OS_Cursor_Pointer,
OS_Cursor_IBar,
//////////////////////////////// OS_Cursor_LeftRight,
//~ rjf: Generated Code OS_Cursor_UpDown,
OS_Cursor_DownRight,
#include "os/gfx/generated/os_gfx.meta.h" OS_Cursor_UpRight,
OS_Cursor_UpDownLeftRight,
//////////////////////////////// OS_Cursor_HandPoint,
//~ rjf: Event Types OS_Cursor_Disabled,
OS_Cursor_COUNT,
typedef enum OS_EventKind }
{ OS_Cursor;
OS_EventKind_Null,
OS_EventKind_Press, ////////////////////////////////
OS_EventKind_Release, //~ rjf: Generated Code
OS_EventKind_MouseMove,
OS_EventKind_Text, #include "os/gfx/generated/os_gfx.meta.h"
OS_EventKind_Scroll,
OS_EventKind_WindowLoseFocus, ////////////////////////////////
OS_EventKind_WindowClose, //~ rjf: Event Types
OS_EventKind_FileDrop,
OS_EventKind_Wakeup, typedef enum OS_EventKind
OS_EventKind_COUNT {
} OS_EventKind_Null,
OS_EventKind; OS_EventKind_Press,
OS_EventKind_Release,
typedef U32 OS_EventFlags; OS_EventKind_MouseMove,
enum OS_EventKind_Text,
{ OS_EventKind_Scroll,
OS_EventFlag_Ctrl = (1<<0), OS_EventKind_WindowLoseFocus,
OS_EventFlag_Shift = (1<<1), OS_EventKind_WindowClose,
OS_EventFlag_Alt = (1<<2), OS_EventKind_FileDrop,
}; OS_EventKind_Wakeup,
OS_EventKind_COUNT
typedef struct OS_Event OS_Event; }
struct OS_Event OS_EventKind;
{
OS_Event *next; typedef U32 OS_EventFlags;
OS_Event *prev; enum
U64 timestamp_us; {
OS_Handle window; OS_EventFlag_Ctrl = (1<<0),
OS_EventKind kind; OS_EventFlag_Shift = (1<<1),
OS_EventFlags flags; OS_EventFlag_Alt = (1<<2),
OS_Key key; };
B32 is_repeat;
B32 right_sided; typedef struct OS_Event OS_Event;
U32 character; struct OS_Event
U32 repeat_count; {
Vec2F32 pos; OS_Event *next;
Vec2F32 delta; OS_Event *prev;
String8List strings; U64 timestamp_us;
}; OS_Handle window;
OS_EventKind kind;
typedef struct OS_EventList OS_EventList; OS_EventFlags flags;
struct OS_EventList OS_Key key;
{ B32 is_repeat;
U64 count; B32 right_sided;
OS_Event *first; U32 character;
OS_Event *last; U32 repeat_count;
}; Vec2F32 pos;
Vec2F32 delta;
//////////////////////////////// String8List strings;
//~ rjf: Event Functions (Helpers, Implemented Once) };
internal String8List os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags); typedef struct OS_EventList OS_EventList;
internal U32 os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key); struct OS_EventList
internal void os_eat_event(OS_EventList *events, OS_Event *event); {
internal B32 os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key); U64 count;
internal B32 os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key); OS_Event *first;
internal B32 os_text(OS_EventList *events, OS_Handle window, U32 character); OS_Event *last;
internal OS_EventList os_event_list_copy(Arena *arena, OS_EventList *src); };
internal void os_event_list_concat_in_place(OS_EventList *dst, OS_EventList *to_push);
////////////////////////////////
//////////////////////////////// //~ rjf: Event Functions (Helpers, Implemented Once)
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
internal String8List os_string_list_from_event_flags(Arena *arena, OS_EventFlags flags);
internal void os_graphical_init(void); internal U32 os_codepoint_from_event_flags_and_key(OS_EventFlags flags, OS_Key key);
internal void os_eat_event(OS_EventList *events, OS_Event *event);
//////////////////////////////// internal B32 os_key_press(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key);
//~ rjf: @os_hooks Clipboards (Implemented Per-OS) internal B32 os_key_release(OS_EventList *events, OS_Handle window, OS_EventFlags flags, OS_Key key);
internal B32 os_text(OS_EventList *events, OS_Handle window, U32 character);
internal void os_set_clipboard_text(String8 string); internal OS_EventList os_event_list_copy(Arena *arena, OS_EventList *src);
internal String8 os_get_clipboard_text(Arena *arena); internal void os_event_list_concat_in_place(OS_EventList *dst, OS_EventList *to_push);
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Windows (Implemented Per-OS) //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
internal OS_Handle os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title); internal void os_gfx_init(void);
internal void os_window_close(OS_Handle window);
internal void os_window_first_paint(OS_Handle window); ////////////////////////////////
internal void os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data); //~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)
internal void os_window_focus(OS_Handle window);
internal B32 os_window_is_focused(OS_Handle window); internal OS_GfxInfo *os_get_gfx_info(void);
internal B32 os_window_is_fullscreen(OS_Handle window);
internal void os_window_set_fullscreen(OS_Handle window, B32 fullscreen); ////////////////////////////////
internal B32 os_window_is_maximized(OS_Handle window); //~ rjf: @os_hooks Clipboards (Implemented Per-OS)
internal void os_window_set_maximized(OS_Handle window, B32 maximized);
internal void os_window_minimize(OS_Handle window); internal void os_set_clipboard_text(String8 string);
internal void os_window_bring_to_front(OS_Handle window); internal String8 os_get_clipboard_text(Arena *arena);
internal void os_window_set_monitor(OS_Handle window, OS_Handle monitor);
internal void os_window_clear_custom_border_data(OS_Handle handle); ////////////////////////////////
internal void os_window_push_custom_title_bar(OS_Handle handle, F32 thickness); //~ rjf: @os_hooks Windows (Implemented Per-OS)
internal void os_window_push_custom_edges(OS_Handle handle, F32 thickness);
internal void os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect); internal OS_Handle os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title);
internal Rng2F32 os_rect_from_window(OS_Handle window); internal void os_window_close(OS_Handle window);
internal Rng2F32 os_client_rect_from_window(OS_Handle window); internal void os_window_first_paint(OS_Handle window);
internal F32 os_dpi_from_window(OS_Handle window); internal void os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data);
internal void os_window_focus(OS_Handle window);
//////////////////////////////// internal B32 os_window_is_focused(OS_Handle window);
//~ rjf: @os_hooks Monitors (Implemented Per-OS) internal B32 os_window_is_fullscreen(OS_Handle window);
internal void os_window_set_fullscreen(OS_Handle window, B32 fullscreen);
internal OS_HandleArray os_push_monitors_array(Arena *arena); internal B32 os_window_is_maximized(OS_Handle window);
internal OS_Handle os_primary_monitor(void); internal void os_window_set_maximized(OS_Handle window, B32 maximized);
internal OS_Handle os_monitor_from_window(OS_Handle window); internal void os_window_minimize(OS_Handle window);
internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor); internal void os_window_bring_to_front(OS_Handle window);
internal Vec2F32 os_dim_from_monitor(OS_Handle monitor); internal void os_window_set_monitor(OS_Handle window, OS_Handle monitor);
internal void os_window_clear_custom_border_data(OS_Handle handle);
//////////////////////////////// internal void os_window_push_custom_title_bar(OS_Handle handle, F32 thickness);
//~ rjf: @os_hooks Events (Implemented Per-OS) internal void os_window_push_custom_edges(OS_Handle handle, F32 thickness);
internal void os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect);
internal void os_send_wakeup_event(void); internal Rng2F32 os_rect_from_window(OS_Handle window);
internal OS_EventList os_get_events(Arena *arena, B32 wait); internal Rng2F32 os_client_rect_from_window(OS_Handle window);
internal OS_EventFlags os_get_event_flags(void); internal F32 os_dpi_from_window(OS_Handle window);
internal B32 os_key_is_down(OS_Key key);
internal Vec2F32 os_mouse_from_window(OS_Handle window); ////////////////////////////////
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
////////////////////////////////
//~ rjf: @os_hooks Cursors (Implemented Per-OS) internal OS_HandleArray os_push_monitors_array(Arena *arena);
internal OS_Handle os_primary_monitor(void);
internal void os_set_cursor(OS_Cursor cursor); internal OS_Handle os_monitor_from_window(OS_Handle window);
internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor);
//////////////////////////////// internal Vec2F32 os_dim_from_monitor(OS_Handle monitor);
//~ rjf: @os_hooks System Properties (Implemented Per-OS)
////////////////////////////////
internal F32 os_double_click_time(void); //~ rjf: @os_hooks Events (Implemented Per-OS)
internal F32 os_caret_blink_time(void);
internal F32 os_default_refresh_rate(void); internal void os_send_wakeup_event(void);
internal OS_EventList os_get_events(Arena *arena, B32 wait);
//////////////////////////////// internal OS_EventFlags os_get_event_flags(void);
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS) internal B32 os_key_is_down(OS_Key key);
internal Vec2F32 os_mouse_from_window(OS_Handle window);
internal void os_graphical_message(B32 error, String8 title, String8 message);
////////////////////////////////
//////////////////////////////// //~ rjf: @os_hooks Cursors (Implemented Per-OS)
//~ rjf: @os_hooks Shell Operations
internal void os_set_cursor(OS_Cursor cursor);
internal void os_show_in_filesystem_ui(String8 path);
////////////////////////////////
#endif // OS_GRAPHICAL_H //~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
internal void os_graphical_message(B32 error, String8 title, String8 message);
////////////////////////////////
//~ rjf: @os_hooks Shell Operations
internal void os_show_in_filesystem_ui(String8 path);
#endif // OS_GRAPHICAL_H
+229 -256
View File
@@ -1,256 +1,229 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
internal void internal void
os_graphical_init(void) os_gfx_init(void)
{ {
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Clipboards (Implemented Per-OS) //~ rjf: @os_hooks Clipboards (Implemented Per-OS)
internal void internal void
os_set_clipboard_text(String8 string) os_set_clipboard_text(String8 string)
{ {
} }
internal String8 internal String8
os_get_clipboard_text(Arena *arena) os_get_clipboard_text(Arena *arena)
{ {
return str8_zero(); return str8_zero();
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Windows (Implemented Per-OS) //~ rjf: @os_hooks Windows (Implemented Per-OS)
internal OS_Handle internal OS_Handle
os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title)
{ {
OS_Handle handle = {1}; OS_Handle handle = {1};
return handle; return handle;
} }
internal void internal void
os_window_close(OS_Handle window) os_window_close(OS_Handle window)
{ {
} }
internal void internal void
os_window_first_paint(OS_Handle window) os_window_first_paint(OS_Handle window)
{ {
} }
internal void internal void
os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data) os_window_equip_repaint(OS_Handle window, OS_WindowRepaintFunctionType *repaint, void *user_data)
{ {
} }
internal void internal void
os_window_focus(OS_Handle window) os_window_focus(OS_Handle window)
{ {
} }
internal B32 internal B32
os_window_is_focused(OS_Handle window) os_window_is_focused(OS_Handle window)
{ {
return 0; return 0;
} }
internal B32 internal B32
os_window_is_fullscreen(OS_Handle window) os_window_is_fullscreen(OS_Handle window)
{ {
return 0; return 0;
} }
internal void internal void
os_window_set_fullscreen(OS_Handle window, B32 fullscreen) os_window_set_fullscreen(OS_Handle window, B32 fullscreen)
{ {
} }
internal B32 internal B32
os_window_is_maximized(OS_Handle window) os_window_is_maximized(OS_Handle window)
{ {
return 0; return 0;
} }
internal void internal void
os_window_set_maximized(OS_Handle window, B32 maximized) os_window_set_maximized(OS_Handle window, B32 maximized)
{ {
} }
internal void internal void
os_window_minimize(OS_Handle window) os_window_minimize(OS_Handle window)
{ {
} }
internal void internal void
os_window_bring_to_front(OS_Handle window) os_window_bring_to_front(OS_Handle window)
{ {
} }
internal void internal void
os_window_set_monitor(OS_Handle window, OS_Handle monitor) os_window_set_monitor(OS_Handle window, OS_Handle monitor)
{ {
} }
internal void internal void
os_window_clear_custom_border_data(OS_Handle handle) os_window_clear_custom_border_data(OS_Handle handle)
{ {
} }
internal void internal void
os_window_push_custom_title_bar(OS_Handle handle, F32 thickness) os_window_push_custom_title_bar(OS_Handle handle, F32 thickness)
{ {
} }
internal void internal void
os_window_push_custom_edges(OS_Handle handle, F32 thickness) os_window_push_custom_edges(OS_Handle handle, F32 thickness)
{ {
} }
internal void internal void
os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect) os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect)
{ {
} }
internal Rng2F32 internal Rng2F32
os_rect_from_window(OS_Handle window) os_rect_from_window(OS_Handle window)
{ {
Rng2F32 rect = r2f32(v2f32(0, 0), v2f32(500, 500)); Rng2F32 rect = r2f32(v2f32(0, 0), v2f32(500, 500));
return rect; return rect;
} }
internal Rng2F32 internal Rng2F32
os_client_rect_from_window(OS_Handle window) os_client_rect_from_window(OS_Handle window)
{ {
Rng2F32 rect = r2f32(v2f32(0, 0), v2f32(500, 500)); Rng2F32 rect = r2f32(v2f32(0, 0), v2f32(500, 500));
return rect; return rect;
} }
internal F32 internal F32
os_dpi_from_window(OS_Handle window) os_dpi_from_window(OS_Handle window)
{ {
return 96.f; return 96.f;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Monitors (Implemented Per-OS) //~ rjf: @os_hooks Monitors (Implemented Per-OS)
internal OS_HandleArray internal OS_HandleArray
os_push_monitors_array(Arena *arena) os_push_monitors_array(Arena *arena)
{ {
OS_HandleArray arr = {0}; OS_HandleArray arr = {0};
return arr; return arr;
} }
internal OS_Handle internal OS_Handle
os_primary_monitor(void) os_primary_monitor(void)
{ {
OS_Handle handle = {1}; OS_Handle handle = {1};
return handle; return handle;
} }
internal OS_Handle internal OS_Handle
os_monitor_from_window(OS_Handle window) os_monitor_from_window(OS_Handle window)
{ {
OS_Handle handle = {1}; OS_Handle handle = {1};
return handle; return handle;
} }
internal String8 internal String8
os_name_from_monitor(Arena *arena, OS_Handle monitor) os_name_from_monitor(Arena *arena, OS_Handle monitor)
{ {
return str8_zero(); return str8_zero();
} }
internal Vec2F32 internal Vec2F32
os_dim_from_monitor(OS_Handle monitor) os_dim_from_monitor(OS_Handle monitor)
{ {
Vec2F32 v = v2f32(1000, 1000); Vec2F32 v = v2f32(1000, 1000);
return v; return v;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Events (Implemented Per-OS) //~ rjf: @os_hooks Events (Implemented Per-OS)
internal void internal void
os_send_wakeup_event(void) os_send_wakeup_event(void)
{ {
} }
internal OS_EventList internal OS_EventList
os_get_events(Arena *arena, B32 wait) os_get_events(Arena *arena, B32 wait)
{ {
OS_EventList evts = {0}; OS_EventList evts = {0};
return evts; return evts;
} }
internal OS_EventFlags internal OS_EventFlags
os_get_event_flags(void) os_get_event_flags(void)
{ {
OS_EventFlags f = 0; OS_EventFlags f = 0;
return f; return f;
} }
internal B32 internal B32
os_key_is_down(OS_Key key) os_key_is_down(OS_Key key)
{ {
return 0; return 0;
} }
internal Vec2F32 internal Vec2F32
os_mouse_from_window(OS_Handle window) os_mouse_from_window(OS_Handle window)
{ {
return v2f32(0, 0); return v2f32(0, 0);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks Cursors (Implemented Per-OS) //~ rjf: @os_hooks Cursors (Implemented Per-OS)
internal void internal void
os_set_cursor(OS_Cursor cursor) os_set_cursor(OS_Cursor cursor)
{ {
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: @os_hooks System Properties (Implemented Per-OS) //~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
internal F32 internal void
os_double_click_time(void) os_graphical_message(B32 error, String8 title, String8 message)
{ {
return 1.f; }
}
////////////////////////////////
internal F32 //~ rjf: @os_hooks Shell Operations
os_caret_blink_time(void)
{ internal void
return 1.f; os_show_in_filesystem_ui(String8 path)
} {
}
internal F32
os_default_refresh_rate(void)
{
return 60.f;
}
internal B32
os_granular_sleep_enabled(void)
{
return 1;
}
////////////////////////////////
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
internal void
os_graphical_message(B32 error, String8 title, String8 message)
{
}
////////////////////////////////
//~ rjf: @os_hooks Shell Operations
internal void
os_show_in_filesystem_ui(String8 path)
{
}
File diff suppressed because it is too large Load Diff
+115 -82
View File
@@ -1,82 +1,115 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_GRAPHICAL_H #ifndef OS_GFX_WIN32_H
#define WIN32_GRAPHICAL_H #define OS_GFX_WIN32_H
#pragma comment(lib, "user32") ////////////////////////////////
#pragma comment(lib, "gdi32") //~ rjf: Includes / Libraries
#ifndef WM_NCUAHDRAWCAPTION #include <uxtheme.h>
#define WM_NCUAHDRAWCAPTION (0x00AE) #include <dwmapi.h>
#endif #include <shellscalingapi.h>
#ifndef WM_NCUAHDRAWFRAME #pragma comment(lib, "gdi32")
#define WM_NCUAHDRAWFRAME (0x00AF) #pragma comment(lib, "dwmapi")
#endif #pragma comment(lib, "UxTheme")
#pragma comment(lib, "ole32")
//////////////////////////////// #pragma comment(lib, "user32")
//~ rjf: Windows #ifndef WM_NCUAHDRAWCAPTION
#define WM_NCUAHDRAWCAPTION (0x00AE)
typedef struct W32_TitleBarClientArea W32_TitleBarClientArea; #endif
struct W32_TitleBarClientArea #ifndef WM_NCUAHDRAWFRAME
{ #define WM_NCUAHDRAWFRAME (0x00AF)
W32_TitleBarClientArea *next; #endif
Rng2F32 rect;
}; ////////////////////////////////
//~ rjf: Windows
typedef struct W32_Window W32_Window;
struct W32_Window typedef struct OS_W32_TitleBarClientArea OS_W32_TitleBarClientArea;
{ struct OS_W32_TitleBarClientArea
W32_Window *next; {
W32_Window *prev; OS_W32_TitleBarClientArea *next;
HWND hwnd; Rng2F32 rect;
WINDOWPLACEMENT last_window_placement; };
OS_WindowRepaintFunctionType *repaint;
void *repaint_user_data; typedef struct OS_W32_Window OS_W32_Window;
F32 dpi; struct OS_W32_Window
B32 first_paint_done; {
B32 maximized; OS_W32_Window *next;
B32 custom_border; OS_W32_Window *prev;
F32 custom_border_title_thickness; HWND hwnd;
F32 custom_border_edge_thickness; WINDOWPLACEMENT last_window_placement;
B32 custom_border_composition_enabled; OS_WindowRepaintFunctionType *repaint;
Arena *paint_arena; void *repaint_user_data;
W32_TitleBarClientArea *first_title_bar_client_area; F32 dpi;
W32_TitleBarClientArea *last_title_bar_client_area; B32 first_paint_done;
}; B32 maximized;
B32 custom_border;
//////////////////////////////// F32 custom_border_title_thickness;
//~ rjf: Monitor Gathering Bundle F32 custom_border_edge_thickness;
B32 custom_border_composition_enabled;
typedef struct W32_MonitorGatherBundle W32_MonitorGatherBundle; Arena *paint_arena;
struct W32_MonitorGatherBundle OS_W32_TitleBarClientArea *first_title_bar_client_area;
{ OS_W32_TitleBarClientArea *last_title_bar_client_area;
Arena *arena; };
OS_HandleList *list;
}; ////////////////////////////////
//~ rjf: Monitor Gathering Bundle
////////////////////////////////
//~ rjf: Basic Helpers typedef struct OS_W32_MonitorGatherBundle OS_W32_MonitorGatherBundle;
struct OS_W32_MonitorGatherBundle
internal Rng2F32 w32_base_rect_from_win32_rect(RECT rect); {
Arena *arena;
//////////////////////////////// OS_HandleList *list;
//~ rjf: Windows };
internal OS_Handle os_window_from_w32_window(W32_Window *window); ////////////////////////////////
internal W32_Window * w32_window_from_os_window(OS_Handle window); //~ rjf: Global State
internal W32_Window * w32_window_from_hwnd(HWND hwnd);
internal HWND w32_hwnd_from_window(W32_Window *window); typedef struct OS_W32_GfxState OS_W32_GfxState;
internal W32_Window * w32_allocate_window(void); struct OS_W32_GfxState
internal void w32_free_window(W32_Window *window); {
internal OS_Event * w32_push_event(OS_EventKind kind, W32_Window *window); Arena *arena;
internal OS_Key w32_os_key_from_vkey(WPARAM vkey); U32 gfx_thread_tid;
internal WPARAM w32_vkey_from_os_key(OS_Key key); HINSTANCE hInstance;
internal LRESULT w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); HCURSOR hCursor;
OS_GfxInfo gfx_info;
//////////////////////////////// OS_W32_Window *first_window;
//~ rjf: Monitors OS_W32_Window *last_window;
OS_W32_Window *free_window;
internal BOOL w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr); OS_Key key_from_vkey_table[256];
};
#endif // WIN32_GRAPHICAL_H
////////////////////////////////
//~ rjf: Globals
global OS_W32_GfxState *os_w32_gfx_state = 0;
global OS_EventList os_w32_event_list = {0};
global Arena *os_w32_event_arena = 0;
B32 os_w32_resizing = 0;
////////////////////////////////
//~ rjf: Basic Helpers
internal Rng2F32 os_w32_rng2f32_from_rect(RECT rect);
////////////////////////////////
//~ rjf: Windows
internal OS_Handle os_w32_handle_from_window(OS_W32_Window *window);
internal OS_W32_Window * os_w32_window_from_handle(OS_Handle window);
internal OS_W32_Window * os_w32_window_from_hwnd(HWND hwnd);
internal HWND os_w32_hwnd_from_window(OS_W32_Window *window);
internal OS_W32_Window * os_w32_window_alloc(void);
internal void os_w32_window_release(OS_W32_Window *window);
internal OS_Event * os_w32_push_event(OS_EventKind kind, OS_W32_Window *window);
internal OS_Key os_w32_os_key_from_vkey(WPARAM vkey);
internal WPARAM os_w32_vkey_from_os_key(OS_Key key);
internal LRESULT os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
////////////////////////////////
//~ rjf: Monitors
internal BOOL os_w32_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr);
#endif // OS_GFX_WIN32_H
+27 -33
View File
@@ -1,33 +1,27 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// #include "os/core/os_core.c"
// NOTE(allen): Include OS features for extra features and target OS #if OS_FEATURE_GRAPHICAL
# include "os/gfx/os_gfx.c"
#include "core/os_core.c" #endif
#if OS_FEATURE_SOCKET #if OS_WINDOWS
#include "socket/os_socket.c" # include "os/core/win32/os_core_win32.c"
#endif #elif OS_LINUX
# include "os/core/linux/os_core_linux.c"
#if OS_FEATURE_GRAPHICAL #else
#include "gfx/os_gfx.c" # error OS core layer not implemented for this operating system.
#endif #endif
#if OS_WINDOWS #if OS_FEATURE_GRAPHICAL
# include "core/win32/os_core_win32.c" # if OS_GFX_STUB
# if OS_FEATURE_SOCKET # include "os/gfx/stub/os_gfx_stub.c"
# include "socket/win32/os_socket_win32.c" # elif OS_WINDOWS
# endif # include "os/gfx/win32/os_gfx_win32.c"
# if OS_FEATURE_GRAPHICAL && !OS_GFX_STUB # elif OS_LINUX
# include "gfx/win32/os_gfx_win32.c" # include "os/gfx/linux/os_gfx_linux.c"
# endif # else
#elif OS_LINUX # error OS graphical layer not implemented for this operating system.
# include "core/linux/os_core_linux.c" # endif
#else #endif
# error no OS layer setup
#endif
#if OS_GFX_STUB
#include "gfx/stub/os_gfx_stub.c"
#endif
+40 -47
View File
@@ -1,47 +1,40 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_INC_H #ifndef OS_INC_H
#define OS_INC_H #define OS_INC_H
#if !defined(OS_FEATURE_SOCKET) #if !defined(OS_FEATURE_GRAPHICAL)
# define OS_FEATURE_SOCKET 0 # define OS_FEATURE_GRAPHICAL 0
#endif #endif
#if !defined(OS_FEATURE_GRAPHICAL) #if !defined(OS_GFX_STUB)
# define OS_FEATURE_GRAPHICAL 0 # define OS_GFX_STUB 0
#endif #endif
#if !defined(OS_GFX_STUB) #include "os/core/os_core.h"
# define OS_GFX_STUB 0 #if OS_FEATURE_GRAPHICAL
#endif # include "os/gfx/os_gfx.h"
#endif
#include "core/os_core.h"
#if OS_WINDOWS
#if OS_FEATURE_SOCKET # include "os/core/win32/os_core_win32.h"
#include "socket/os_socket.h" #elif OS_LINUX
#endif # include "os/core/linux/os_core_linux.h"
#else
#if OS_FEATURE_GRAPHICAL # error OS core layer not implemented for this operating system.
#include "gfx/os_gfx.h" #endif
#endif
#if OS_FEATURE_GRAPHICAL
#if OS_WINDOWS # if OS_GFX_STUB
# include "core/win32/os_core_win32.h" # include "os/gfx/stub/os_gfx_stub.h"
# if OS_FEATURE_SOCKET # elif OS_WINDOWS
# include "socket/win32/os_socket_win32.h" # include "os/gfx/win32/os_gfx_win32.h"
# endif # elif OS_LINUX
# if OS_FEATURE_GRAPHICAL && !OS_GFX_STUB # include "os/gfx/linux/os_gfx_linux.h"
# include "gfx/win32/os_gfx_win32.h" # else
# endif # error OS graphical layer not implemented for this operating system.
#elif OS_LINUX # endif
# include "core/linux/os_core_linux.h" #endif
#else
# error no OS layer setup #endif // OS_INC_H
#endif
#if OS_GFX_STUB
#include "gfx/stub/os_gfx_stub.h"
#endif
#endif //OS_SWITCH_H
-16
View File
@@ -1,16 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
// NOTE(allen): Helper
internal B32
os_socket_write(OS_Socket *socket, String8 data){
String8Node node = {0};
String8List list = {0};
str8_list_push(&list, &node, data);
B32 result = os_socket_write(socket, list);
return(result);
}
#endif
-49
View File
@@ -1,49 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OS_SOCKET_H
#define OS_SOCKET_H
enum OS_SocketStatus{
OS_SocketStatus_Uninitialized,
OS_SocketStatus_Connected,
OS_SocketStatus_GracefullyClosed,
OS_SocketStatus_Error,
};
typedef U16 OS_SocketError;
enum{
OS_SocketError_None,
OS_SocketError_SocketSystemNotInitialized,
OS_SocketError_BadPortArgument,
OS_SocketError_BadIPArgument,
OS_SocketError_WSAError,
};
struct OS_Socket{
U8 memory[32];
};
////////////////////////////////
//~ NOTE(allen): Implemented Per Operating System
internal void os_socket_init(void);
internal void os_socket_listen(OS_Socket *socket, String8 port);
internal void os_socket_connect(OS_Socket *socket, String8 ip, String8 port);
internal void os_socket_close(OS_Socket *socket);
internal String8 os_socket_read(Arena *arena, OS_Socket *socket);
internal B32 os_socket_write(OS_Socket *socket, String8List list);
internal B32 os_socket_status(OS_Socket *socket, OS_SocketStatus status);
internal String8 os_socket_error_string(Arena *arena, OS_Socket *socket);
internal void os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error);
////////////////////////////////
//~ NOTE(allen): Helpers - Portable Implementation
internal B32 os_socket_write(OS_Socket *socket, String8 data);
#endif //OS_SOCKET_H
-353
View File
@@ -1,353 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal void
w32_socket_set_error(W32_Socket *socket, OS_SocketError error){
socket->error = error;
// NOTE(allen): This flag was set earlier so that the socket would assert
// when an error occurs. The "bug" or issue is whatever caused this error
// not the fact the flag is set. Unless the flag wasn't supposed to be set!
Assert(!(socket->flags & W32_SocketFlag_AssertOnError));
}
internal void
w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error){
switch (wsa_error){
default:
{
socket->wsa_error = wsa_error;
w32_socket_set_error(socket, OS_SocketError_WSAError);
}break;
case WSANOTINITIALISED:
{
w32_socket_set_error(socket, OS_SocketError_SocketSystemNotInitialized);
}break;
}
}
internal B32
w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size){
U32 p = 0;
CHAR *ptr = (CHAR*)buffer;
for (;p < size;){
DWORD amt = (DWORD)(size - p);
WSABUF wsabuf = {amt, ptr};
// NOTE(allen): The flags pointer is _NOT_ optional but we can ignore it.
// We have to zero it because it's an in/out pointer.
DWORD ignore = 0;
if (WSARecv(w32_socket->socket, &wsabuf, 1, &amt, &ignore, 0, 0) != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
break;
}
if (amt == 0){
w32_socket->flags |= W32_SocketFlag_Closed;
break;
}
p += amt;
ptr += amt;
}
B32 result = (p == size);
return(result);
}
////////////////////////////////
//~ rjf: Per-OS Hook Implementations
internal void
os_socket_init(void){
WSADATA wsaData;
WORD vreq = MAKEWORD(2,2);
WSAStartup(vreq, &wsaData);
}
internal void
os_socket_listen(OS_Socket *s, String8 port){
W32_Socket *w32_socket = (W32_Socket*)s->memory;
// NOTE(allen): check port string
char port_buffer[6];
if (port.size == 0 || port.size >= sizeof(port_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument);
return;
}
MemoryCopy(port_buffer, port.str, port.size);
port_buffer[port.size] = 0;
// NOTE(allen): listen socket addrinfo
addrinfo listen_hint = {0};
listen_hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV;
listen_hint.ai_family = AF_UNSPEC;
listen_hint.ai_socktype = SOCK_STREAM;
listen_hint.ai_protocol = AF_UNSPEC;
addrinfo *addr = {0};
INT error = getaddrinfo(0, port_buffer, &listen_hint, &addr);
if (error != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): init listen socket
SOCKET socket_listener = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
W32_SocketCloser listener_closer(&socket_listener);
// NOTE(allen): reuseraddr
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(socket_listener, SOL_SOCKET, SO_REUSEADDR, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): bind
if (bind(socket_listener, addr->ai_addr, (int)addr->ai_addrlen) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): listen
if (listen(socket_listener, 1) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): accept
SOCKET client_socket = accept(socket_listener, 0, 0);
W32_SocketCloser client_closer(&client_socket);
// NOTE(allen): TCP_NODELAY
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(client_socket, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): success
w32_socket->flags |= W32_SocketFlag_Connected;
w32_socket->socket = client_socket;
w32_socket->error = OS_SocketError_None;
client_closer.do_not_close();
}
internal void
os_socket_connect(OS_Socket *s, String8 ip, String8 port){
W32_Socket *w32_socket = (W32_Socket*)s->memory;
// NOTE(allen): check port string
char port_buffer[6];
if (port.size == 0 || port.size >= sizeof(port_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadPortArgument);
return;
}
MemoryCopy(port_buffer, port.str, port.size);
port_buffer[port.size] = 0;
// NOTE(allen): check ip string
if (ip.size == 0){
ip = str8_lit("localhost");
}
char ip_buffer[KB(1)];
if (ip.size >= sizeof(ip_buffer)){
w32_socket_set_error(w32_socket, OS_SocketError_BadIPArgument);
return;
}
MemoryCopy(ip_buffer, ip.str, ip.size);
ip_buffer[ip.size] = 0;
// NOTE(allen): socket addrinfo
addrinfo hint = {0};
hint.ai_flags = AI_PASSIVE|AI_NUMERICSERV;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = AF_UNSPEC;
addrinfo *addr = {0};
INT error = getaddrinfo(ip_buffer, port_buffer, &hint, &addr);
if (error != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): init socket
SOCKET socket_server = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
W32_SocketCloser closer(&socket_server);
// NOTE(allen): TCP_NODELAY
{
union { B32 b; char c[1]; } enable;
enable.b = true;
if (setsockopt(socket_server, IPPROTO_TCP, TCP_NODELAY, enable.c, sizeof(enable)) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
}
// NOTE(allen): connect
if (connect(socket_server, addr->ai_addr, (int)addr->ai_addrlen) < 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
return;
}
// NOTE(allen): success
w32_socket->flags |= W32_SocketFlag_Connected;
w32_socket->socket = socket_server;
w32_socket->error = OS_SocketError_None;
closer.do_not_close();
}
internal void
os_socket_close(OS_Socket *socket){
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
closesocket(w32_socket->socket);
MemoryZeroStruct(w32_socket);
}
internal String8
os_socket_read(Arena *arena, OS_Socket *socket){
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
String8 result = {0};
U32 size = 0;
if (w32_socket_read_looped(w32_socket, &size, sizeof(size))){
Temp restore = temp_begin(arena);
result.str = push_array_no_zero(arena, U8, size);
if (w32_socket_read_looped(w32_socket, result.str, size)){
result.size = size;
}
else{
temp_end(restore);
result.str = 0;
}
}
return(result);
}
internal B32
os_socket_write(OS_Socket *socket, String8List list){
U32 size = (U32)list.total_size;
String8Node node = {0};
str8_list_push_front(&list, &node, str8_struct(&size));
W32_Socket *w32_socket = (W32_Socket*)socket->memory;
WSABUF wsabuf[64];
Assert(list.node_count <= ArrayCount(wsabuf));
U64 wsabuf_count = 0;
for (String8Node *node = list.first;
node != 0;
node = node->next){
wsabuf[wsabuf_count].len = (U32)node->string.size;
wsabuf[wsabuf_count].buf = (CHAR*)node->string.str;
wsabuf_count += 1;
}
B32 result = false;
DWORD amt = 0;
if (WSASend(w32_socket->socket, wsabuf, wsabuf_count, &amt, 0, 0, 0) != 0){
w32_socket_set_error_wsa(w32_socket, WSAGetLastError());
}
else if (amt == 0){
w32_socket->flags |= W32_SocketFlag_Connected;
}
else{
result = true;
}
return(result);
}
internal B32
os_socket_status(OS_Socket *socket, OS_SocketStatus status){
W32_Socket *w32_socket = (W32_Socket*)socket;
B32 result = false;
switch (status){
case OS_SocketStatus_Uninitialized:
{
result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == 0) &&
(w32_socket->error == 0));
}break;
case OS_SocketStatus_Connected:
{
result = (((w32_socket->flags & (W32_SocketFlag_Connected|W32_SocketFlag_Closed)) == W32_SocketFlag_Connected) &&
(w32_socket->error == 0));
}break;
case OS_SocketStatus_GracefullyClosed:
{
result = (((w32_socket->flags & W32_SocketFlag_Closed) == W32_SocketFlag_Closed) && (w32_socket->error == 0));
}break;
case OS_SocketStatus_Error:
{
result = (w32_socket->error != 0);
}break;
}
return(result);
}
internal String8
os_socket_error_string(Arena *arena, OS_Socket *socket){
String8 result = str8_lit("no error");
W32_Socket *w32_socket = (W32_Socket*)socket;
switch (w32_socket->error){
default:
{
result = str8_lit("Bad error code");
}break;
case OS_SocketError_None:break;
case OS_SocketError_SocketSystemNotInitialized:
{
result = str8_lit("Missing call to os_socket_init");
}break;
case OS_SocketError_BadPortArgument:
{
result = str8_lit("Invalid port argument to socket API");
}break;
case OS_SocketError_BadIPArgument:
{
result = str8_lit("Invalid ip argument to socket API");
}break;
case OS_SocketError_WSAError:
{
DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM;
CHAR *message = 0;
DWORD size = FormatMessageA(flags, 0, w32_socket->wsa_error, 0, (CHAR*)&message, 0, 0);
if (size == 0){
result = str8_lit("Unknown WSA error");
}
else{
String8 string = str8_skip_chop_whitespace(str8((U8*)message, size));
result = push_str8_copy(arena, string);
LocalFree(message);
}
}break;
}
return(result);
}
internal void
os_socket_assert_on_error(OS_Socket *socket, B32 assert_on_error){
W32_Socket *w32_socket = (W32_Socket*)socket;
if (assert_on_error){
w32_socket->flags |= W32_SocketFlag_AssertOnError;
}
else{
w32_socket->flags &= ~W32_SocketFlag_AssertOnError;
}
}
-54
View File
@@ -1,54 +0,0 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_SOCKET_H
#define WIN32_SOCKET_H
////////////////////////////////
//~ rjf: Types
typedef U16 W32_SocketFlags;
enum{
W32_SocketFlag_Connected = (1 << 0),
W32_SocketFlag_Closed = (1 << 1),
W32_SocketFlag_AssertOnError = (1 << 2),
};
struct W32_Socket{
W32_SocketFlags flags;
OS_SocketError error;
int wsa_error;
SOCKET socket;
};
struct W32_SocketCloser{
B32 need_to_close;
SOCKET *socket;
W32_SocketCloser(SOCKET *s){
this->need_to_close = true;
this->socket = s;
}
~W32_SocketCloser(){
this->close_now();
}
void close_now(){
if (this->need_to_close){
closesocket(*this->socket);
this->need_to_close = false;
}
}
void do_not_close(){
this->need_to_close = false;
}
};
StaticAssert(sizeof(Member(OS_Socket, memory)) >= sizeof(W32_Socket), socket_memory_size);
////////////////////////////////
//~ rjf: Helpers
internal void w32_socket_set_error(W32_Socket *socket, OS_SocketError error);
internal void w32_socket_set_error_wsa(W32_Socket *socket, int wsa_error);
internal B32 w32_socket_read_looped(W32_Socket *w32_socket, void *buffer, U32 size);
#endif // WIN32_SOCKET_H
+165 -167
View File
@@ -1,167 +1,165 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ allen: Path Helper Functions //~ allen: Path Helper Functions
internal StringMatchFlags internal StringMatchFlags
path_match_flags_from_os(OperatingSystem os) path_match_flags_from_os(OperatingSystem os)
{ {
StringMatchFlags flags = StringMatchFlag_SlashInsensitive; StringMatchFlags flags = StringMatchFlag_SlashInsensitive;
switch(os) switch(os)
{ {
default:{}break; default:{}break;
case OperatingSystem_Windows: case OperatingSystem_Windows:
{ {
flags |= StringMatchFlag_CaseInsensitive; flags |= StringMatchFlag_CaseInsensitive;
}break; }break;
case OperatingSystem_Linux: case OperatingSystem_Linux:
case OperatingSystem_Mac: case OperatingSystem_Mac:
{ {
// NOTE(rjf): no-op // NOTE(rjf): no-op
}break; }break;
} }
return flags; return flags;
} }
internal String8 internal String8
path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
// rjf: gather path parts // rjf: gather path parts
String8 dst_name = str8_skip_last_slash(dst); String8 dst_name = str8_skip_last_slash(dst);
String8 src_folder = str8_chop_last_slash(src); String8 src_folder = str8_chop_last_slash(src);
String8 dst_folder = str8_chop_last_slash(dst); String8 dst_folder = str8_chop_last_slash(dst);
String8List src_folders = str8_split_path(scratch.arena, src_folder); String8List src_folders = str8_split_path(scratch.arena, src_folder);
String8List dst_folders = str8_split_path(scratch.arena, dst_folder); String8List dst_folders = str8_split_path(scratch.arena, dst_folder);
// rjf: count # of backtracks to get from src -> dest // rjf: count # of backtracks to get from src -> dest
U64 num_backtracks = src_folders.node_count; U64 num_backtracks = src_folders.node_count;
for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first; for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first;
src_n != 0 && bp_n != 0; src_n != 0 && bp_n != 0;
src_n = src_n->next, bp_n = bp_n->next) src_n = src_n->next, bp_n = bp_n->next)
{ {
if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context()))) if(str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context())))
{ {
num_backtracks -= 1; num_backtracks -= 1;
} }
else else
{ {
break; break;
} }
} }
// rjf: only build relative string if # of backtracks is not the entire `src`. // rjf: only build relative string if # of backtracks is not the entire `src`.
// if getting to `dst` from `src` requires erasing the entire `src`, then the // if getting to `dst` from `src` requires erasing the entire `src`, then the
// only possible way to get to `dst` from `src` is via absolute path. // only possible way to get to `dst` from `src` is via absolute path.
String8 dst_path = {0}; String8 dst_path = {0};
if(num_backtracks >= src_folders.node_count) if(num_backtracks >= src_folders.node_count)
{ {
dst_path = path_normalized_from_string(arena, dst); dst_path = path_normalized_from_string(arena, dst);
} }
else else
{ {
// rjf: build backtrack parts // rjf: build backtrack parts
String8List dst_path_strs = {0}; String8List dst_path_strs = {0};
for(U64 idx = 0; idx < num_backtracks; idx += 1) for(U64 idx = 0; idx < num_backtracks; idx += 1)
{ {
str8_list_push(scratch.arena, &dst_path_strs, str8_lit("..")); str8_list_push(scratch.arena, &dst_path_strs, str8_lit(".."));
} }
// rjf: build parts of dst which are unique from src // rjf: build parts of dst which are unique from src
{ {
B32 unique_from_src = 0; B32 unique_from_src = 0;
for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first; for(String8Node *src_n = src_folders.first, *bp_n = dst_folders.first;
bp_n != 0; bp_n != 0;
bp_n = bp_n->next) bp_n = bp_n->next)
{ {
if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context())))) if(!unique_from_src && (src_n == 0 || !str8_match(src_n->string, bp_n->string, path_match_flags_from_os(operating_system_from_context()))))
{ {
unique_from_src = 1; unique_from_src = 1;
} }
if(unique_from_src) if(unique_from_src)
{ {
str8_list_push(scratch.arena, &dst_path_strs, bp_n->string); str8_list_push(scratch.arena, &dst_path_strs, bp_n->string);
} }
if(src_n != 0) if(src_n != 0)
{ {
src_n = src_n->next; src_n = src_n->next;
} }
} }
} }
// rjf: build file name // rjf: build file name
str8_list_push(scratch.arena, &dst_path_strs, dst_name); str8_list_push(scratch.arena, &dst_path_strs, dst_name);
// rjf: join // rjf: join
StringJoin join = {0}; StringJoin join = {0};
{ {
join.sep = str8_lit("/"); join.sep = str8_lit("/");
} }
dst_path = str8_list_join(arena, &dst_path_strs, &join); dst_path = str8_list_join(arena, &dst_path_strs, &join);
} }
scratch_end(scratch); scratch_end(scratch);
return dst_path; return dst_path;
} }
internal String8 internal String8
path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src) path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src)
{ {
String8 result = dst; String8 result = dst;
PathStyle dst_style = path_style_from_str8(dst); PathStyle dst_style = path_style_from_str8(dst);
if(dst_style == PathStyle_Relative) if(dst_style == PathStyle_Relative)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst); String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst);
String8 dst_from_src_absolute_normalized = path_normalized_from_string(arena, dst_from_src_absolute); String8 dst_from_src_absolute_normalized = path_normalized_from_string(arena, dst_from_src_absolute);
result = dst_from_src_absolute_normalized; result = dst_from_src_absolute_normalized;
scratch_end(scratch); scratch_end(scratch);
} }
return result; return result;
} }
internal String8List internal String8List
path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out){ path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out){
// analyze path // analyze path
PathStyle path_style = path_style_from_str8(path_string); PathStyle path_style = path_style_from_str8(path_string);
String8List path = str8_split_path(arena, path_string); String8List path = str8_split_path(arena, path_string);
// prepend current path to convert relative -> absolute // prepend current path to convert relative -> absolute
PathStyle path_style_full = path_style; PathStyle path_style_full = path_style;
if (path.node_count != 0 && path_style == PathStyle_Relative){ if (path.node_count != 0 && path_style == PathStyle_Relative){
String8List current_path_strs = {0}; String8 current_path_string = os_get_current_path(arena);
os_string_list_from_system_path(arena, OS_SystemPath_Current, &current_path_strs);
String8 current_path_string = str8_list_first(&current_path_strs); PathStyle current_path_style = path_style_from_str8(current_path_string);
Assert(current_path_style != PathStyle_Relative);
PathStyle current_path_style = path_style_from_str8(current_path_string);
Assert(current_path_style != PathStyle_Relative); String8List current_path = str8_split_path(arena, current_path_string);
str8_list_concat_in_place(&current_path, &path);
String8List current_path = str8_split_path(arena, current_path_string); path = current_path;
str8_list_concat_in_place(&current_path, &path); path_style_full = current_path_style;
path = current_path; }
path_style_full = current_path_style;
} // resolve dots
str8_path_list_resolve_dots_in_place(&path, path_style_full);
// resolve dots
str8_path_list_resolve_dots_in_place(&path, path_style_full); // return
if (style_out != 0){
// return *style_out = path_style_full;
if (style_out != 0){ }
*style_out = path_style_full; return(path);
} }
return(path);
} internal String8
path_normalized_from_string(Arena *arena, String8 path_string){
internal String8 Temp scratch = scratch_begin(&arena, 1);
path_normalized_from_string(Arena *arena, String8 path_string){
Temp scratch = scratch_begin(&arena, 1); PathStyle style = PathStyle_Relative;
String8List path = path_normalized_list_from_string(scratch.arena, path_string, &style);
PathStyle style = PathStyle_Relative;
String8List path = path_normalized_list_from_string(scratch.arena, path_string, &style); String8 result = str8_path_list_join_by_style(arena, &path, style);
scratch_end(scratch);
String8 result = str8_path_list_join_by_style(arena, &path, style); return(result);
scratch_end(scratch); }
return(result);
}
+1003 -1004
View File
File diff suppressed because it is too large Load Diff
+397 -397
View File
@@ -1,397 +1,397 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Frontend Entry Points //~ rjf: Frontend Entry Points
internal void internal void
update_and_render(OS_Handle repaint_window_handle, void *user_data) update_and_render(OS_Handle repaint_window_handle, void *user_data)
{ {
ProfTick(0); ProfTick(0);
ProfBeginFunction(); ProfBeginFunction();
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
////////////////////////////// //////////////////////////////
//- rjf: begin logging //- rjf: begin logging
// //
if(main_thread_log == 0) if(main_thread_log == 0)
{ {
main_thread_log = log_alloc(); main_thread_log = log_alloc();
String8 user_program_data_path = os_string_from_system_path(scratch.arena, OS_SystemPath_UserProgramData); String8 user_program_data_path = os_get_process_info()->user_program_data_path;
String8 user_data_folder = push_str8f(scratch.arena, "%S/raddbg/logs", user_program_data_path); String8 user_data_folder = push_str8f(scratch.arena, "%S/raddbg/logs", user_program_data_path);
main_thread_log_path = push_str8f(df_state->arena, "%S/ui_thread.raddbg_log", user_data_folder); main_thread_log_path = push_str8f(df_state->arena, "%S/ui_thread.raddbg_log", user_data_folder);
os_make_directory(user_data_folder); os_make_directory(user_data_folder);
os_write_data_to_file_path(main_thread_log_path, str8_zero()); os_write_data_to_file_path(main_thread_log_path, str8_zero());
} }
log_select(main_thread_log); log_select(main_thread_log);
log_scope_begin(); log_scope_begin();
////////////////////////////// //////////////////////////////
//- rjf: tick cache layers //- rjf: tick cache layers
// //
txt_user_clock_tick(); txt_user_clock_tick();
dasm_user_clock_tick(); dasm_user_clock_tick();
geo_user_clock_tick(); geo_user_clock_tick();
tex_user_clock_tick(); tex_user_clock_tick();
////////////////////////////// //////////////////////////////
//- rjf: pick target hz //- rjf: pick target hz
// //
// TODO(rjf): maximize target, given all windows and their monitors // TODO(rjf): maximize target, given all windows and their monitors
F32 target_hz = os_default_refresh_rate(); F32 target_hz = os_get_gfx_info()->default_refresh_rate;
if(frame_time_us_history_idx > 32) if(frame_time_us_history_idx > 32)
{ {
// rjf: calculate average frame time out of the last N // rjf: calculate average frame time out of the last N
U64 num_frames_in_history = Min(ArrayCount(frame_time_us_history), frame_time_us_history_idx); U64 num_frames_in_history = Min(ArrayCount(frame_time_us_history), frame_time_us_history_idx);
U64 frame_time_history_sum_us = 0; U64 frame_time_history_sum_us = 0;
for(U64 idx = 0; idx < num_frames_in_history; idx += 1) for(U64 idx = 0; idx < num_frames_in_history; idx += 1)
{ {
frame_time_history_sum_us += frame_time_us_history[idx]; frame_time_history_sum_us += frame_time_us_history[idx];
} }
U64 frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history; U64 frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history;
// rjf: pick among a number of sensible targets to snap to, given how well // rjf: pick among a number of sensible targets to snap to, given how well
// we've been performing // we've been performing
F32 possible_alternate_hz_targets[] = {target_hz, 60.f, 120.f, 144.f, 240.f}; F32 possible_alternate_hz_targets[] = {target_hz, 60.f, 120.f, 144.f, 240.f};
F32 best_target_hz = target_hz; F32 best_target_hz = target_hz;
S64 best_target_hz_frame_time_us_diff = max_S64; S64 best_target_hz_frame_time_us_diff = max_S64;
for(U64 idx = 0; idx < ArrayCount(possible_alternate_hz_targets); idx += 1) for(U64 idx = 0; idx < ArrayCount(possible_alternate_hz_targets); idx += 1)
{ {
F32 candidate = possible_alternate_hz_targets[idx]; F32 candidate = possible_alternate_hz_targets[idx];
if(candidate <= target_hz) if(candidate <= target_hz)
{ {
U64 candidate_frame_time_us = 1000000/(U64)candidate; U64 candidate_frame_time_us = 1000000/(U64)candidate;
S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us; S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us;
if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff) if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff)
{ {
best_target_hz = candidate; best_target_hz = candidate;
best_target_hz_frame_time_us_diff = frame_time_us_diff; best_target_hz_frame_time_us_diff = frame_time_us_diff;
} }
} }
} }
target_hz = best_target_hz; target_hz = best_target_hz;
} }
////////////////////////////// //////////////////////////////
//- rjf: target Hz -> delta time //- rjf: target Hz -> delta time
// //
F32 dt = 1.f/target_hz; F32 dt = 1.f/target_hz;
////////////////////////////// //////////////////////////////
//- rjf: get events from the OS //- rjf: get events from the OS
// //
OS_EventList events = {0}; OS_EventList events = {0};
if(os_handle_match(repaint_window_handle, os_handle_zero())) if(os_handle_match(repaint_window_handle, os_handle_zero()))
{ {
events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0);
} }
////////////////////////////// //////////////////////////////
//- rjf: begin measuring actual per-frame work //- rjf: begin measuring actual per-frame work
// //
U64 begin_time_us = os_now_microseconds(); U64 begin_time_us = os_now_microseconds();
////////////////////////////// //////////////////////////////
//- rjf: bind change //- rjf: bind change
// //
if(!df_gfx_state->confirm_active && df_gfx_state->bind_change_active) if(!df_gfx_state->confirm_active && df_gfx_state->bind_change_active)
{ {
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc)) if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc))
{ {
df_gfx_request_frame(); df_gfx_request_frame();
df_gfx_state->bind_change_active = 0; df_gfx_state->bind_change_active = 0;
} }
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete)) if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete))
{ {
df_gfx_request_frame(); df_gfx_request_frame();
df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding); df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding);
df_gfx_state->bind_change_active = 0; df_gfx_state->bind_change_active = 0;
DF_CmdParams p = df_cmd_params_from_gfx(); DF_CmdParams p = df_cmd_params_from_gfx();
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User])); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User]));
} }
for(OS_Event *event = events.first, *next = 0; event != 0; event = next) for(OS_Event *event = events.first, *next = 0; event != 0; event = next)
{ {
if(event->kind == OS_EventKind_Press && if(event->kind == OS_EventKind_Press &&
event->key != OS_Key_Esc && event->key != OS_Key_Esc &&
event->key != OS_Key_Return && event->key != OS_Key_Return &&
event->key != OS_Key_Backspace && event->key != OS_Key_Backspace &&
event->key != OS_Key_Delete && event->key != OS_Key_Delete &&
event->key != OS_Key_LeftMouseButton && event->key != OS_Key_LeftMouseButton &&
event->key != OS_Key_RightMouseButton && event->key != OS_Key_RightMouseButton &&
event->key != OS_Key_MiddleMouseButton && event->key != OS_Key_MiddleMouseButton &&
event->key != OS_Key_Ctrl && event->key != OS_Key_Ctrl &&
event->key != OS_Key_Alt && event->key != OS_Key_Alt &&
event->key != OS_Key_Shift) event->key != OS_Key_Shift)
{ {
df_gfx_state->bind_change_active = 0; df_gfx_state->bind_change_active = 0;
DF_Binding binding = zero_struct; DF_Binding binding = zero_struct;
{ {
binding.key = event->key; binding.key = event->key;
binding.flags = event->flags; binding.flags = event->flags;
} }
df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding); df_unbind_spec(df_gfx_state->bind_change_cmd_spec, df_gfx_state->bind_change_binding);
df_bind_spec(df_gfx_state->bind_change_cmd_spec, binding); df_bind_spec(df_gfx_state->bind_change_cmd_spec, binding);
U32 codepoint = os_codepoint_from_event_flags_and_key(event->flags, event->key); U32 codepoint = os_codepoint_from_event_flags_and_key(event->flags, event->key);
os_text(&events, os_handle_zero(), codepoint); os_text(&events, os_handle_zero(), codepoint);
os_eat_event(&events, event); os_eat_event(&events, event);
DF_CmdParams p = df_cmd_params_from_gfx(); DF_CmdParams p = df_cmd_params_from_gfx();
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User])); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(df_g_cfg_src_write_cmd_kind_table[DF_CfgSrc_User]));
df_gfx_request_frame(); df_gfx_request_frame();
break; break;
} }
} }
} }
////////////////////////////// //////////////////////////////
//- rjf: consume events //- rjf: consume events
// //
B32 queue_drag_drop = 0; B32 queue_drag_drop = 0;
{ {
for(OS_Event *event = events.first, *next = 0; for(OS_Event *event = events.first, *next = 0;
event != 0; event != 0;
event = next) event = next)
{ {
next = event->next; next = event->next;
DF_Window *window = df_window_from_os_handle(event->window); DF_Window *window = df_window_from_os_handle(event->window);
DF_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx(); DF_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx();
B32 take = 0; B32 take = 0;
B32 skip = 0; B32 skip = 0;
//- rjf: try drag-drop //- rjf: try drag-drop
if(df_drag_is_active() && event->kind == OS_EventKind_Release && event->key == OS_Key_LeftMouseButton) if(df_drag_is_active() && event->kind == OS_EventKind_Release && event->key == OS_Key_LeftMouseButton)
{ {
skip = 1; skip = 1;
queue_drag_drop = 1; queue_drag_drop = 1;
} }
//- rjf: try window close //- rjf: try window close
if(!take && event->kind == OS_EventKind_WindowClose && window != 0) if(!take && event->kind == OS_EventKind_WindowClose && window != 0)
{ {
take = 1; take = 1;
DF_CmdParams params = df_cmd_params_from_window(window); DF_CmdParams params = df_cmd_params_from_window(window);
df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow)); df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow));
} }
//- rjf: try menu bar operations //- rjf: try menu bar operations
{ {
if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0) if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{ {
take = 1; take = 1;
df_gfx_request_frame(); df_gfx_request_frame();
window->menu_bar_focused_on_press = window->menu_bar_focused; window->menu_bar_focused_on_press = window->menu_bar_focused;
window->menu_bar_key_held = 1; window->menu_bar_key_held = 1;
window->menu_bar_focus_press_started = 1; window->menu_bar_focus_press_started = 1;
} }
if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0) if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{ {
take = 1; take = 1;
df_gfx_request_frame(); df_gfx_request_frame();
window->menu_bar_key_held = 0; window->menu_bar_key_held = 0;
} }
if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0) if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{ {
take = 1; take = 1;
df_gfx_request_frame(); df_gfx_request_frame();
window->menu_bar_focused = 0; window->menu_bar_focused = 0;
} }
else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0) else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0)
{ {
take = 1; take = 1;
df_gfx_request_frame(); df_gfx_request_frame();
window->menu_bar_focused = !window->menu_bar_focused_on_press; window->menu_bar_focused = !window->menu_bar_focused_on_press;
window->menu_bar_focus_press_started = 0; window->menu_bar_focus_press_started = 0;
} }
else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open()) else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open())
{ {
take = 1; take = 1;
df_gfx_request_frame(); df_gfx_request_frame();
window->menu_bar_focused = 0; window->menu_bar_focused = 0;
} }
} }
//- rjf: try hotkey presses //- rjf: try hotkey presses
if(!take && event->kind == OS_EventKind_Press) if(!take && event->kind == OS_EventKind_Press)
{ {
DF_Binding binding = {event->key, event->flags}; DF_Binding binding = {event->key, event->flags};
DF_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding); DF_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding);
if(spec_candidates.first != 0 && !df_cmd_spec_is_nil(spec_candidates.first->spec)) if(spec_candidates.first != 0 && !df_cmd_spec_is_nil(spec_candidates.first->spec))
{ {
DF_CmdSpec *run_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunCommand); DF_CmdSpec *run_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunCommand);
DF_CmdSpec *spec = spec_candidates.first->spec; DF_CmdSpec *spec = spec_candidates.first->spec;
if(run_spec != spec) if(run_spec != spec)
{ {
params.cmd_spec = spec; params.cmd_spec = spec;
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_CmdSpec); df_cmd_params_mark_slot(&params, DF_CmdParamSlot_CmdSpec);
} }
U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key); U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key);
take = 1; take = 1;
df_push_cmd__root(&params, run_spec); df_push_cmd__root(&params, run_spec);
if(event->flags & OS_EventFlag_Alt) if(event->flags & OS_EventFlag_Alt)
{ {
window->menu_bar_focus_press_started = 0; window->menu_bar_focus_press_started = 0;
} }
} }
else if(OS_Key_F1 <= event->key && event->key <= OS_Key_F19) else if(OS_Key_F1 <= event->key && event->key <= OS_Key_F19)
{ {
window->menu_bar_focus_press_started = 0; window->menu_bar_focus_press_started = 0;
} }
df_gfx_request_frame(); df_gfx_request_frame();
} }
//- rjf: try text events //- rjf: try text events
if(!take && event->kind == OS_EventKind_Text) if(!take && event->kind == OS_EventKind_Text)
{ {
String32 insertion32 = str32(&event->character, 1); String32 insertion32 = str32(&event->character, 1);
String8 insertion8 = str8_from_32(scratch.arena, insertion32); String8 insertion8 = str8_from_32(scratch.arena, insertion32);
DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_InsertText); DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_InsertText);
params.string = insertion8; params.string = insertion8;
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_String); df_cmd_params_mark_slot(&params, DF_CmdParamSlot_String);
df_push_cmd__root(&params, spec); df_push_cmd__root(&params, spec);
df_gfx_request_frame(); df_gfx_request_frame();
take = 1; take = 1;
if(event->flags & OS_EventFlag_Alt) if(event->flags & OS_EventFlag_Alt)
{ {
window->menu_bar_focus_press_started = 0; window->menu_bar_focus_press_started = 0;
} }
} }
//- rjf: do fall-through //- rjf: do fall-through
if(!take) if(!take)
{ {
take = 1; take = 1;
params.os_event = event; params.os_event = event;
df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OSEvent)); df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OSEvent));
} }
//- rjf: take //- rjf: take
if(take && !skip) if(take && !skip)
{ {
os_eat_event(&events, event); os_eat_event(&events, event);
} }
} }
} }
////////////////////////////// //////////////////////////////
//- rjf: gather root-level commands //- rjf: gather root-level commands
// //
DF_CmdList cmds = df_core_gather_root_cmds(scratch.arena); DF_CmdList cmds = df_core_gather_root_cmds(scratch.arena);
////////////////////////////// //////////////////////////////
//- rjf: begin frame //- rjf: begin frame
// //
df_core_begin_frame(scratch.arena, &cmds, dt); df_core_begin_frame(scratch.arena, &cmds, dt);
df_gfx_begin_frame(scratch.arena, &cmds); df_gfx_begin_frame(scratch.arena, &cmds);
////////////////////////////// //////////////////////////////
//- rjf: queue drop for drag/drop //- rjf: queue drop for drag/drop
// //
if(queue_drag_drop) if(queue_drag_drop)
{ {
df_queue_drag_drop(); df_queue_drag_drop();
} }
////////////////////////////// //////////////////////////////
//- rjf: auto-focus moused-over windows while dragging //- rjf: auto-focus moused-over windows while dragging
// //
if(df_drag_is_active()) if(df_drag_is_active())
{ {
B32 over_focused_window = 0; B32 over_focused_window = 0;
{ {
for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next)
{ {
Vec2F32 mouse = os_mouse_from_window(window->os); Vec2F32 mouse = os_mouse_from_window(window->os);
Rng2F32 rect = os_client_rect_from_window(window->os); Rng2F32 rect = os_client_rect_from_window(window->os);
if(os_window_is_focused(window->os) && contains_2f32(rect, mouse)) if(os_window_is_focused(window->os) && contains_2f32(rect, mouse))
{ {
over_focused_window = 1; over_focused_window = 1;
break; break;
} }
} }
} }
if(!over_focused_window) if(!over_focused_window)
{ {
for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next) for(DF_Window *window = df_gfx_state->first_window; window != 0; window = window->next)
{ {
Vec2F32 mouse = os_mouse_from_window(window->os); Vec2F32 mouse = os_mouse_from_window(window->os);
Rng2F32 rect = os_client_rect_from_window(window->os); Rng2F32 rect = os_client_rect_from_window(window->os);
if(!os_window_is_focused(window->os) && contains_2f32(rect, mouse)) if(!os_window_is_focused(window->os) && contains_2f32(rect, mouse))
{ {
os_window_focus(window->os); os_window_focus(window->os);
break; break;
} }
} }
} }
} }
////////////////////////////// //////////////////////////////
//- rjf: update & render //- rjf: update & render
// //
{ {
d_begin_frame(); d_begin_frame();
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
{ {
B32 window_is_focused = os_window_is_focused(w->os); B32 window_is_focused = os_window_is_focused(w->os);
if(window_is_focused) if(window_is_focused)
{ {
last_focused_window = df_handle_from_window(w); last_focused_window = df_handle_from_window(w);
} }
df_push_interact_regs(); df_push_interact_regs();
df_window_update_and_render(scratch.arena, w, &cmds); df_window_update_and_render(scratch.arena, w, &cmds);
DF_InteractRegs *window_regs = df_pop_interact_regs(); DF_InteractRegs *window_regs = df_pop_interact_regs();
if(df_window_from_handle(last_focused_window) == w) if(df_window_from_handle(last_focused_window) == w)
{ {
MemoryCopyStruct(df_interact_regs(), window_regs); MemoryCopyStruct(df_interact_regs(), window_regs);
} }
} }
} }
////////////////////////////// //////////////////////////////
//- rjf: end frontend frame, send signals, etc. //- rjf: end frontend frame, send signals, etc.
// //
df_gfx_end_frame(); df_gfx_end_frame();
df_core_end_frame(); df_core_end_frame();
////////////////////////////// //////////////////////////////
//- rjf: submit rendering to all windows //- rjf: submit rendering to all windows
// //
{ {
r_begin_frame(); r_begin_frame();
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next) for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
{ {
r_window_begin_frame(w->os, w->r); r_window_begin_frame(w->os, w->r);
d_submit_bucket(w->os, w->r, w->draw_bucket); d_submit_bucket(w->os, w->r, w->draw_bucket);
r_window_end_frame(w->os, w->r); r_window_end_frame(w->os, w->r);
} }
r_end_frame(); r_end_frame();
} }
////////////////////////////// //////////////////////////////
//- rjf: determine frame time, record into history //- rjf: determine frame time, record into history
// //
U64 end_time_us = os_now_microseconds(); U64 end_time_us = os_now_microseconds();
U64 frame_time_us = end_time_us-begin_time_us; U64 frame_time_us = end_time_us-begin_time_us;
frame_time_us_history[frame_time_us_history_idx%ArrayCount(frame_time_us_history)] = frame_time_us; frame_time_us_history[frame_time_us_history_idx%ArrayCount(frame_time_us_history)] = frame_time_us;
frame_time_us_history_idx += 1; frame_time_us_history_idx += 1;
////////////////////////////// //////////////////////////////
//- rjf: end logging //- rjf: end logging
// //
{ {
LogScopeResult log = log_scope_end(scratch.arena); LogScopeResult log = log_scope_end(scratch.arena);
os_append_data_to_file_path(main_thread_log_path, log.strings[LogMsgKind_Info]); os_append_data_to_file_path(main_thread_log_path, log.strings[LogMsgKind_Info]);
if(log.strings[LogMsgKind_UserError].size != 0) if(log.strings[LogMsgKind_UserError].size != 0)
{ {
DF_CmdParams p = df_cmd_params_from_gfx(); DF_CmdParams p = df_cmd_params_from_gfx();
p.string = log.strings[LogMsgKind_UserError]; p.string = log.strings[LogMsgKind_UserError];
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error));
} }
} }
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
} }
internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl) internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl)
{ {
os_send_wakeup_event(); os_send_wakeup_event();
} }
+574 -574
View File
File diff suppressed because it is too large Load Diff
@@ -1,316 +1,316 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Build Options //~ rjf: Build Options
#define BUILD_VERSION_MAJOR 0 #define BUILD_VERSION_MAJOR 0
#define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_MINOR 9
#define BUILD_VERSION_PATCH 11 #define BUILD_VERSION_PATCH 11
#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#define BUILD_TITLE "rdi_breakpad_from_pdb" #define BUILD_TITLE "rdi_breakpad_from_pdb"
#define BUILD_CONSOLE_INTERFACE 1 #define BUILD_CONSOLE_INTERFACE 1
//////////////////////////////// ////////////////////////////////
//~ rjf: Includes //~ rjf: Includes
//- rjf: [lib] //- rjf: [lib]
#include "lib_rdi_format/rdi_format.h" #include "lib_rdi_format/rdi_format.h"
#include "lib_rdi_format/rdi_format.c" #include "lib_rdi_format/rdi_format.c"
#include "lib_rdi_format/rdi_format_parse.h" #include "lib_rdi_format/rdi_format_parse.h"
#include "lib_rdi_format/rdi_format_parse.c" #include "lib_rdi_format/rdi_format_parse.c"
#include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.h"
#include "third_party/rad_lzb_simple/rad_lzb_simple.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.c"
//- rjf: [h] //- rjf: [h]
#include "base/base_inc.h" #include "base/base_inc.h"
#include "os/os_inc.h" #include "os/os_inc.h"
#include "task_system/task_system.h" #include "task_system/task_system.h"
#include "rdi_make/rdi_make_local.h" #include "rdi_make/rdi_make_local.h"
#include "coff/coff.h" #include "coff/coff.h"
#include "codeview/codeview.h" #include "codeview/codeview.h"
#include "codeview/codeview_stringize.h" #include "codeview/codeview_stringize.h"
#include "msf/msf.h" #include "msf/msf.h"
#include "pdb/pdb.h" #include "pdb/pdb.h"
#include "pdb/pdb_stringize.h" #include "pdb/pdb_stringize.h"
#include "rdi_from_pdb/rdi_from_pdb.h" #include "rdi_from_pdb/rdi_from_pdb.h"
//- rjf: [c] //- rjf: [c]
#include "base/base_inc.c" #include "base/base_inc.c"
#include "os/os_inc.c" #include "os/os_inc.c"
#include "task_system/task_system.c" #include "task_system/task_system.c"
#include "rdi_make/rdi_make_local.c" #include "rdi_make/rdi_make_local.c"
#include "coff/coff.c" #include "coff/coff.c"
#include "codeview/codeview.c" #include "codeview/codeview.c"
#include "codeview/codeview_stringize.c" #include "codeview/codeview_stringize.c"
#include "msf/msf.c" #include "msf/msf.c"
#include "pdb/pdb.c" #include "pdb/pdb.c"
#include "pdb/pdb_stringize.c" #include "pdb/pdb_stringize.c"
#include "rdi_from_pdb/rdi_from_pdb.c" #include "rdi_from_pdb/rdi_from_pdb.c"
//////////////////////////////// ////////////////////////////////
//~ rjf: Baking Tasks //~ rjf: Baking Tasks
//- rjf: unit vmap baking //- rjf: unit vmap baking
typedef struct P2B_BakeUnitVMapIn P2B_BakeUnitVMapIn; typedef struct P2B_BakeUnitVMapIn P2B_BakeUnitVMapIn;
struct P2B_BakeUnitVMapIn struct P2B_BakeUnitVMapIn
{ {
RDIM_UnitChunkList *units; RDIM_UnitChunkList *units;
}; };
internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_vmap_task__entry_point) internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_vmap_task__entry_point)
{ {
P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p; P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p;
RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1);
*out = rdim_bake_unit_vmap(arena, in->units); *out = rdim_bake_unit_vmap(arena, in->units);
return out; return out;
} }
//- rjf: line table baking //- rjf: line table baking
typedef struct P2B_BakeLineTablesIn P2B_BakeLineTablesIn; typedef struct P2B_BakeLineTablesIn P2B_BakeLineTablesIn;
struct P2B_BakeLineTablesIn struct P2B_BakeLineTablesIn
{ {
RDIM_LineTableChunkList *line_tables; RDIM_LineTableChunkList *line_tables;
}; };
internal TS_TASK_FUNCTION_DEF(p2b_bake_line_table_task__entry_point) internal TS_TASK_FUNCTION_DEF(p2b_bake_line_table_task__entry_point)
{ {
P2B_BakeLineTablesIn *in = (P2B_BakeLineTablesIn *)p; P2B_BakeLineTablesIn *in = (P2B_BakeLineTablesIn *)p;
RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1);
*out = rdim_bake_line_tables(arena, in->line_tables); *out = rdim_bake_line_tables(arena, in->line_tables);
return out; return out;
} }
//- rjf: per-procedure chunk dumping //- rjf: per-procedure chunk dumping
typedef struct P2B_DumpProcChunkIn P2B_DumpProcChunkIn; typedef struct P2B_DumpProcChunkIn P2B_DumpProcChunkIn;
struct P2B_DumpProcChunkIn struct P2B_DumpProcChunkIn
{ {
RDI_VMapEntry *unit_vmap; RDI_VMapEntry *unit_vmap;
U32 unit_vmap_count; U32 unit_vmap_count;
U32 *unit_line_table_idxs; U32 *unit_line_table_idxs;
U64 unit_count; U64 unit_count;
RDIM_LineTableBakeResult *line_tables_bake; RDIM_LineTableBakeResult *line_tables_bake;
RDIM_SymbolChunkNode *chunk; RDIM_SymbolChunkNode *chunk;
}; };
internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point) internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point)
{ {
P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p; P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p;
String8List *out = push_array(arena, String8List, 1); String8List *out = push_array(arena, String8List, 1);
RDI_LineTable *line_tables = in->line_tables_bake->line_tables; RDI_LineTable *line_tables = in->line_tables_bake->line_tables;
RDI_U64 line_tables_count = in->line_tables_bake->line_tables_count; RDI_U64 line_tables_count = in->line_tables_bake->line_tables_count;
RDI_U64 *line_table_voffs = in->line_tables_bake->line_table_voffs; RDI_U64 *line_table_voffs = in->line_tables_bake->line_table_voffs;
RDI_U64 line_table_voffs_count = in->line_tables_bake->line_table_voffs_count; RDI_U64 line_table_voffs_count = in->line_tables_bake->line_table_voffs_count;
RDI_Line *line_table_lines = in->line_tables_bake->line_table_lines; RDI_Line *line_table_lines = in->line_tables_bake->line_table_lines;
RDI_U64 line_table_lines_count = in->line_tables_bake->line_table_lines_count; RDI_U64 line_table_lines_count = in->line_tables_bake->line_table_lines_count;
for(U64 idx = 0; idx < in->chunk->count; idx += 1) for(U64 idx = 0; idx < in->chunk->count; idx += 1)
{ {
// NOTE(rjf): breakpad does not support multiple voff ranges per procedure. // NOTE(rjf): breakpad does not support multiple voff ranges per procedure.
RDIM_Symbol *proc = &in->chunk->v[idx]; RDIM_Symbol *proc = &in->chunk->v[idx];
RDIM_Scope *root_scope = proc->root_scope; RDIM_Scope *root_scope = proc->root_scope;
if(root_scope != 0 && root_scope->voff_ranges.first != 0) if(root_scope != 0 && root_scope->voff_ranges.first != 0)
{ {
// rjf: dump function record // rjf: dump function record
RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v;
str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name);
// rjf: dump function lines // rjf: dump function lines
U64 unit_idx = rdi_vmap_idx_from_voff(in->unit_vmap, in->unit_vmap_count, voff_range.min); U64 unit_idx = rdi_vmap_idx_from_voff(in->unit_vmap, in->unit_vmap_count, voff_range.min);
if(0 < unit_idx && unit_idx <= in->unit_count) if(0 < unit_idx && unit_idx <= in->unit_count)
{ {
U32 line_table_idx = in->unit_line_table_idxs[unit_idx]; U32 line_table_idx = in->unit_line_table_idxs[unit_idx];
if(0 < line_table_idx && line_table_idx <= line_tables_count) if(0 < line_table_idx && line_table_idx <= line_tables_count)
{ {
// rjf: unpack unit line info // rjf: unpack unit line info
RDI_LineTable *line_table = &line_tables[line_table_idx]; RDI_LineTable *line_table = &line_tables[line_table_idx];
RDI_ParsedLineTable line_info = RDI_ParsedLineTable line_info =
{ {
line_table_voffs + line_table->voffs_base_idx, line_table_voffs + line_table->voffs_base_idx,
line_table_lines + line_table->lines_base_idx, line_table_lines + line_table->lines_base_idx,
0, 0,
line_table->lines_count, line_table->lines_count,
0 0
}; };
for(U64 voff = voff_range.min, last_voff = 0; for(U64 voff = voff_range.min, last_voff = 0;
voff < voff_range.max && voff > last_voff;) voff < voff_range.max && voff > last_voff;)
{ {
RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff);
if(line_info_idx < line_info.count) if(line_info_idx < line_info.count)
{ {
RDI_Line *line = &line_info.lines[line_info_idx]; RDI_Line *line = &line_info.lines[line_info_idx];
U64 line_voff_min = line_info.voffs[line_info_idx]; U64 line_voff_min = line_info.voffs[line_info_idx];
U64 line_voff_opl = line_info.voffs[line_info_idx+1]; U64 line_voff_opl = line_info.voffs[line_info_idx+1];
if(line->file_idx != 0) if(line->file_idx != 0)
{ {
str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n", str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n",
line_voff_min, line_voff_min,
line_voff_opl-line_voff_min, line_voff_opl-line_voff_min,
(U64)line->line_num, (U64)line->line_num,
(U64)line->file_idx); (U64)line->file_idx);
} }
last_voff = voff; last_voff = voff;
voff = line_voff_opl; voff = line_voff_opl;
} }
else else
{ {
break; break;
} }
} }
} }
} }
} }
} }
return out; return out;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Entry Point //~ rjf: Entry Point
internal void internal void
entry_point(CmdLine *cmdline) entry_point(CmdLine *cmdline)
{ {
//- rjf: initialize state, unpack command line //- rjf: initialize state, unpack command line
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) || B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) ||
cmd_line_has_flag(cmdline, str8_lit("h")) || cmd_line_has_flag(cmdline, str8_lit("h")) ||
cmd_line_has_flag(cmdline, str8_lit("?"))); cmd_line_has_flag(cmdline, str8_lit("?")));
P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline);
user2convert->flags &= ~(P2R_ConvertFlag_Types|P2R_ConvertFlag_UDTs); user2convert->flags &= ~(P2R_ConvertFlag_Types|P2R_ConvertFlag_UDTs);
//- rjf: display help //- rjf: display help
if(do_help || user2convert->errors.node_count != 0) if(do_help || user2convert->errors.node_count != 0)
{ {
fprintf(stderr, "--- rdi_breakpad_from_pdb -----------------------------------------------------\n\n"); fprintf(stderr, "--- rdi_breakpad_from_pdb -----------------------------------------------------\n\n");
fprintf(stderr, "This utility converts debug information from PDBs into the textual Breakpad\n"); fprintf(stderr, "This utility converts debug information from PDBs into the textual Breakpad\n");
fprintf(stderr, "symbol information format, used for various external utilities, using the RAD\n"); fprintf(stderr, "symbol information format, used for various external utilities, using the RAD\n");
fprintf(stderr, "Debug Info conversion systems. The following arguments are accepted:\n\n"); fprintf(stderr, "Debug Info conversion systems. The following arguments are accepted:\n\n");
fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable file for which the\n"); fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable file for which the\n");
fprintf(stderr, " debug info was generated.\n"); fprintf(stderr, " debug info was generated.\n");
fprintf(stderr, "--pdb:<path> Specifies the path of the PDB debug info file to\n"); fprintf(stderr, "--pdb:<path> Specifies the path of the PDB debug info file to\n");
fprintf(stderr, " convert.\n"); fprintf(stderr, " convert.\n");
fprintf(stderr, "--out:<path> Specifies the path at which the output Breakpad debug\n"); fprintf(stderr, "--out:<path> Specifies the path at which the output Breakpad debug\n");
fprintf(stderr, " info will be written.\n\n"); fprintf(stderr, " info will be written.\n\n");
if(!do_help) if(!do_help)
{ {
for(String8Node *n = user2convert->errors.first; n != 0; n = n->next) for(String8Node *n = user2convert->errors.first; n != 0; n = n->next)
{ {
fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string)); fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string));
} }
} }
os_exit_process(0); os_abort(0);
} }
//- rjf: convert //- rjf: convert
P2R_Convert2Bake *convert2bake = 0; P2R_Convert2Bake *convert2bake = 0;
ProfScope("convert") ProfScope("convert")
{ {
convert2bake = p2r_convert(arena, user2convert); convert2bake = p2r_convert(arena, user2convert);
} }
//- rjf: dump breakpad text //- rjf: dump breakpad text
String8List dump = {0}; String8List dump = {0};
ProfScope("dump breakpad text") ProfScope("dump breakpad text")
{ {
RDIM_BakeParams *params = &convert2bake->bake_params; RDIM_BakeParams *params = &convert2bake->bake_params;
//- rjf: kick off unit vmap baking //- rjf: kick off unit vmap baking
P2B_BakeUnitVMapIn bake_unit_vmap_in = {&params->units}; P2B_BakeUnitVMapIn bake_unit_vmap_in = {&params->units};
TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in);
//- rjf: kick off line-table baking //- rjf: kick off line-table baking
P2B_BakeLineTablesIn bake_line_tables_in = {&params->line_tables}; P2B_BakeLineTablesIn bake_line_tables_in = {&params->line_tables};
TS_Ticket bake_line_tables_ticket = ts_kickoff(p2b_bake_line_table_task__entry_point, 0, &bake_line_tables_in); TS_Ticket bake_line_tables_ticket = ts_kickoff(p2b_bake_line_table_task__entry_point, 0, &bake_line_tables_in);
//- rjf: build unit -> line table idx array //- rjf: build unit -> line table idx array
U64 unit_count = params->units.total_count; U64 unit_count = params->units.total_count;
U32 *unit_line_table_idxs = push_array(arena, U32, unit_count+1); U32 *unit_line_table_idxs = push_array(arena, U32, unit_count+1);
{ {
U64 dst_idx = 1; U64 dst_idx = 1;
for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next)
{ {
for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, dst_idx += 1) for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, dst_idx += 1)
{ {
unit_line_table_idxs[dst_idx] = rdim_idx_from_line_table(n->v[n_idx].line_table); unit_line_table_idxs[dst_idx] = rdim_idx_from_line_table(n->v[n_idx].line_table);
} }
} }
} }
//- rjf: dump MODULE record //- rjf: dump MODULE record
str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", params->top_level_info.exe_hash, params->top_level_info.exe_name); str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", params->top_level_info.exe_hash, params->top_level_info.exe_name);
//- rjf: dump FILE records //- rjf: dump FILE records
ProfScope("dump FILE records") ProfScope("dump FILE records")
{ {
for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next)
{ {
for(U64 idx = 0; idx < n->count; idx += 1) for(U64 idx = 0; idx < n->count; idx += 1)
{ {
U64 file_idx = rdim_idx_from_src_file(&n->v[idx]); U64 file_idx = rdim_idx_from_src_file(&n->v[idx]);
String8 src_path = n->v[idx].normal_full_path; String8 src_path = n->v[idx].normal_full_path;
str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path); str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path);
} }
} }
} }
//- rjf: join unit vmap //- rjf: join unit vmap
ProfBegin("join unit vmap"); ProfBegin("join unit vmap");
RDIM_UnitVMapBakeResult *bake_unit_vmap_out = ts_join_struct(bake_unit_vmap_ticket, max_U64, RDIM_UnitVMapBakeResult); RDIM_UnitVMapBakeResult *bake_unit_vmap_out = ts_join_struct(bake_unit_vmap_ticket, max_U64, RDIM_UnitVMapBakeResult);
RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap.vmap; RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap.vmap;
U32 unit_vmap_count = bake_unit_vmap_out->vmap.count; U32 unit_vmap_count = bake_unit_vmap_out->vmap.count;
ProfEnd(); ProfEnd();
//- rjf: join line tables //- rjf: join line tables
ProfBegin("join line table"); ProfBegin("join line table");
RDIM_LineTableBakeResult *bake_line_tables_out = ts_join_struct(bake_line_tables_ticket, max_U64, RDIM_LineTableBakeResult); RDIM_LineTableBakeResult *bake_line_tables_out = ts_join_struct(bake_line_tables_ticket, max_U64, RDIM_LineTableBakeResult);
ProfEnd(); ProfEnd();
//- rjf: kick off FUNC & line record dump tasks //- rjf: kick off FUNC & line record dump tasks
P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, params->procedures.chunk_count); P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, params->procedures.chunk_count);
TS_Ticket *dump_proc_chunk_tickets = push_array(arena, TS_Ticket, params->procedures.chunk_count); TS_Ticket *dump_proc_chunk_tickets = push_array(arena, TS_Ticket, params->procedures.chunk_count);
ProfScope("kick off FUNC & line record dump tasks") ProfScope("kick off FUNC & line record dump tasks")
{ {
U64 task_idx = 0; U64 task_idx = 0;
for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next, task_idx += 1) for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next, task_idx += 1)
{ {
dump_proc_chunk_in[task_idx].unit_vmap = unit_vmap; dump_proc_chunk_in[task_idx].unit_vmap = unit_vmap;
dump_proc_chunk_in[task_idx].unit_vmap_count = unit_vmap_count; dump_proc_chunk_in[task_idx].unit_vmap_count = unit_vmap_count;
dump_proc_chunk_in[task_idx].unit_line_table_idxs = unit_line_table_idxs; dump_proc_chunk_in[task_idx].unit_line_table_idxs = unit_line_table_idxs;
dump_proc_chunk_in[task_idx].unit_count = unit_count; dump_proc_chunk_in[task_idx].unit_count = unit_count;
dump_proc_chunk_in[task_idx].line_tables_bake = bake_line_tables_out; dump_proc_chunk_in[task_idx].line_tables_bake = bake_line_tables_out;
dump_proc_chunk_in[task_idx].chunk = n; dump_proc_chunk_in[task_idx].chunk = n;
dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, 0, &dump_proc_chunk_in[task_idx]); dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, 0, &dump_proc_chunk_in[task_idx]);
} }
} }
//- rjf: join FUNC & line record dump tasks //- rjf: join FUNC & line record dump tasks
ProfScope("join FUNC & line record dump tasks") ProfScope("join FUNC & line record dump tasks")
{ {
for(U64 idx = 0; idx < params->procedures.chunk_count; idx += 1) for(U64 idx = 0; idx < params->procedures.chunk_count; idx += 1)
{ {
String8List *out = ts_join_struct(dump_proc_chunk_tickets[idx], max_U64, String8List); String8List *out = ts_join_struct(dump_proc_chunk_tickets[idx], max_U64, String8List);
str8_list_concat_in_place(&dump, out); str8_list_concat_in_place(&dump, out);
} }
} }
} }
//- rjf: bake //- rjf: bake
String8 baked = {0}; String8 baked = {0};
ProfScope("bake") ProfScope("bake")
{ {
baked = str8_list_join(arena, &dump, 0); baked = str8_list_join(arena, &dump, 0);
} }
//- rjf: write //- rjf: write
ProfScope("write") ProfScope("write")
{ {
OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name); OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name);
os_file_write(output_file, r1u64(0, baked.size), baked.str); os_file_write(output_file, r1u64(0, baked.size), baked.str);
os_file_close(output_file); os_file_close(output_file);
} }
} }
File diff suppressed because it is too large Load Diff
+132 -132
View File
@@ -1,132 +1,132 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Build Options //~ rjf: Build Options
#define BUILD_VERSION_MAJOR 0 #define BUILD_VERSION_MAJOR 0
#define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_MINOR 9
#define BUILD_VERSION_PATCH 11 #define BUILD_VERSION_PATCH 11
#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
#define BUILD_TITLE "rdi_from_pdb" #define BUILD_TITLE "rdi_from_pdb"
#define BUILD_CONSOLE_INTERFACE 1 #define BUILD_CONSOLE_INTERFACE 1
//////////////////////////////// ////////////////////////////////
//~ rjf: Includes //~ rjf: Includes
//- rjf: [lib] //- rjf: [lib]
#include "lib_rdi_format/rdi_format.h" #include "lib_rdi_format/rdi_format.h"
#include "lib_rdi_format/rdi_format.c" #include "lib_rdi_format/rdi_format.c"
#include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.h"
#include "third_party/rad_lzb_simple/rad_lzb_simple.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.c"
//- rjf: [h] //- rjf: [h]
#include "base/base_inc.h" #include "base/base_inc.h"
#include "os/os_inc.h" #include "os/os_inc.h"
#include "task_system/task_system.h" #include "task_system/task_system.h"
#include "rdi_make/rdi_make_local.h" #include "rdi_make/rdi_make_local.h"
#include "coff/coff.h" #include "coff/coff.h"
#include "codeview/codeview.h" #include "codeview/codeview.h"
#include "codeview/codeview_stringize.h" #include "codeview/codeview_stringize.h"
#include "msf/msf.h" #include "msf/msf.h"
#include "pdb/pdb.h" #include "pdb/pdb.h"
#include "pdb/pdb_stringize.h" #include "pdb/pdb_stringize.h"
#include "rdi_from_pdb.h" #include "rdi_from_pdb.h"
//- rjf: [c] //- rjf: [c]
#include "base/base_inc.c" #include "base/base_inc.c"
#include "os/os_inc.c" #include "os/os_inc.c"
#include "task_system/task_system.c" #include "task_system/task_system.c"
#include "rdi_make/rdi_make_local.c" #include "rdi_make/rdi_make_local.c"
#include "coff/coff.c" #include "coff/coff.c"
#include "codeview/codeview.c" #include "codeview/codeview.c"
#include "codeview/codeview_stringize.c" #include "codeview/codeview_stringize.c"
#include "msf/msf.c" #include "msf/msf.c"
#include "pdb/pdb.c" #include "pdb/pdb.c"
#include "pdb/pdb_stringize.c" #include "pdb/pdb_stringize.c"
#include "rdi_from_pdb.c" #include "rdi_from_pdb.c"
//////////////////////////////// ////////////////////////////////
//~ rjf: Entry Point //~ rjf: Entry Point
internal void internal void
entry_point(CmdLine *cmdline) entry_point(CmdLine *cmdline)
{ {
//- rjf: initialize state, unpack command line //- rjf: initialize state, unpack command line
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) || B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) ||
cmd_line_has_flag(cmdline, str8_lit("h")) || cmd_line_has_flag(cmdline, str8_lit("h")) ||
cmd_line_has_flag(cmdline, str8_lit("?"))); cmd_line_has_flag(cmdline, str8_lit("?")));
P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline);
//- rjf: display help //- rjf: display help
if(do_help || user2convert->errors.node_count != 0) if(do_help || user2convert->errors.node_count != 0)
{ {
fprintf(stderr, "--- rdi_from_pdb --------------------------------------------------------------\n\n"); fprintf(stderr, "--- rdi_from_pdb --------------------------------------------------------------\n\n");
fprintf(stderr, "This utility converts debug information from PDBs into the RAD Debug Info\n"); fprintf(stderr, "This utility converts debug information from PDBs into the RAD Debug Info\n");
fprintf(stderr, "format. The following arguments are accepted:\n\n"); fprintf(stderr, "format. The following arguments are accepted:\n\n");
fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable file for which the\n"); fprintf(stderr, "--exe:<path> [optional] Specifies the path of the executable file for which the\n");
fprintf(stderr, " debug info was generated.\n"); fprintf(stderr, " debug info was generated.\n");
fprintf(stderr, "--pdb:<path> Specifies the path of the PDB debug info file to\n"); fprintf(stderr, "--pdb:<path> Specifies the path of the PDB debug info file to\n");
fprintf(stderr, " convert.\n"); fprintf(stderr, " convert.\n");
fprintf(stderr, "--out:<path> Specifies the path at which the output Breakpad debug\n"); fprintf(stderr, "--out:<path> Specifies the path at which the output Breakpad debug\n");
fprintf(stderr, " info will be written.\n\n"); fprintf(stderr, " info will be written.\n\n");
if(!do_help) if(!do_help)
{ {
for(String8Node *n = user2convert->errors.first; n != 0; n = n->next) for(String8Node *n = user2convert->errors.first; n != 0; n = n->next)
{ {
fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string)); fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string));
} }
} }
os_exit_process(0); os_abort(0);
} }
//- rjf: convert //- rjf: convert
P2R_Convert2Bake *convert2bake = 0; P2R_Convert2Bake *convert2bake = 0;
ProfScope("convert") ProfScope("convert")
{ {
convert2bake = p2r_convert(arena, user2convert); convert2bake = p2r_convert(arena, user2convert);
} }
//- rjf: bake //- rjf: bake
P2R_Bake2Serialize *bake2srlz = 0; P2R_Bake2Serialize *bake2srlz = 0;
ProfScope("bake") ProfScope("bake")
{ {
bake2srlz = p2r_bake(arena, convert2bake); bake2srlz = p2r_bake(arena, convert2bake);
} }
//- rjf: serialize //- rjf: serialize
P2R_Serialize2File *srlz2file = 0; P2R_Serialize2File *srlz2file = 0;
ProfScope("serialize") ProfScope("serialize")
{ {
srlz2file = push_array(arena, P2R_Serialize2File, 1); srlz2file = push_array(arena, P2R_Serialize2File, 1);
srlz2file->bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); srlz2file->bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results);
} }
//- rjf: compress //- rjf: compress
P2R_Serialize2File *srlz2file_compressed = srlz2file; P2R_Serialize2File *srlz2file_compressed = srlz2file;
if(cmd_line_has_flag(cmdline, str8_lit("compress"))) ProfScope("compress") if(cmd_line_has_flag(cmdline, str8_lit("compress"))) ProfScope("compress")
{ {
srlz2file_compressed = push_array(arena, P2R_Serialize2File, 1); srlz2file_compressed = push_array(arena, P2R_Serialize2File, 1);
srlz2file_compressed = p2r_compress(arena, srlz2file); srlz2file_compressed = p2r_compress(arena, srlz2file);
} }
//- rjf: serialize //- rjf: serialize
String8List blobs = rdim_file_blobs_from_section_bundle(arena, &srlz2file_compressed->bundle); String8List blobs = rdim_file_blobs_from_section_bundle(arena, &srlz2file_compressed->bundle);
//- rjf: write //- rjf: write
ProfScope("write") ProfScope("write")
{ {
OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name); OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name);
U64 off = 0; U64 off = 0;
for(String8Node *n = blobs.first; n != 0; n = n->next) for(String8Node *n = blobs.first; n != 0; n = n->next)
{ {
os_file_write(output_file, r1u64(off, off+n->string.size), n->string.str); os_file_write(output_file, r1u64(off, off+n->string.size), n->string.str);
off += n->string.size; off += n->string.size;
} }
os_file_close(output_file); os_file_close(output_file);
} }
} }
File diff suppressed because it is too large Load Diff
+227 -227
View File
@@ -1,227 +1,227 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Type Functions //~ rjf: Basic Type Functions
internal TS_Ticket internal TS_Ticket
ts_ticket_zero(void) ts_ticket_zero(void)
{ {
TS_Ticket ticket = {0}; TS_Ticket ticket = {0};
return ticket; return ticket;
} }
internal void internal void
ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket) ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket)
{ {
TS_TicketNode *n = push_array(arena, TS_TicketNode, 1); TS_TicketNode *n = push_array(arena, TS_TicketNode, 1);
n->v = ticket; n->v = ticket;
SLLQueuePush(list->first, list->last, n); SLLQueuePush(list->first, list->last, n);
list->count += 1; list->count += 1;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Top-Level Layer Initialization //~ rjf: Top-Level Layer Initialization
internal void internal void
ts_init(void) ts_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
ts_shared = push_array(arena, TS_Shared, 1); ts_shared = push_array(arena, TS_Shared, 1);
ts_shared->arena = arena; ts_shared->arena = arena;
ts_shared->artifact_slots_count = 1024; ts_shared->artifact_slots_count = 1024;
ts_shared->artifact_stripes_count = Min(ts_shared->artifact_slots_count, os_logical_core_count()); ts_shared->artifact_stripes_count = Min(ts_shared->artifact_slots_count, os_get_system_info()->logical_processor_count);
ts_shared->artifact_slots = push_array(arena, TS_TaskArtifactSlot, ts_shared->artifact_slots_count); ts_shared->artifact_slots = push_array(arena, TS_TaskArtifactSlot, ts_shared->artifact_slots_count);
ts_shared->artifact_stripes = push_array(arena, TS_TaskArtifactStripe, ts_shared->artifact_stripes_count); ts_shared->artifact_stripes = push_array(arena, TS_TaskArtifactStripe, ts_shared->artifact_stripes_count);
for(U64 idx = 0; idx < ts_shared->artifact_stripes_count; idx += 1) for(U64 idx = 0; idx < ts_shared->artifact_stripes_count; idx += 1)
{ {
ts_shared->artifact_stripes[idx].arena = arena_alloc(); ts_shared->artifact_stripes[idx].arena = arena_alloc();
ts_shared->artifact_stripes[idx].cv = os_condition_variable_alloc(); ts_shared->artifact_stripes[idx].cv = os_condition_variable_alloc();
ts_shared->artifact_stripes[idx].rw_mutex = os_rw_mutex_alloc(); ts_shared->artifact_stripes[idx].rw_mutex = os_rw_mutex_alloc();
} }
ts_shared->u2t_ring_size = MB(1); ts_shared->u2t_ring_size = MB(1);
ts_shared->u2t_ring_base = push_array_no_zero(arena, U8, ts_shared->u2t_ring_size); ts_shared->u2t_ring_base = push_array_no_zero(arena, U8, ts_shared->u2t_ring_size);
ts_shared->u2t_ring_mutex = os_mutex_alloc(); ts_shared->u2t_ring_mutex = os_mutex_alloc();
ts_shared->u2t_ring_cv = os_condition_variable_alloc(); ts_shared->u2t_ring_cv = os_condition_variable_alloc();
ts_shared->task_threads_count = os_logical_core_count()-1; ts_shared->task_threads_count = os_get_system_info()->logical_processor_count-1;
ts_shared->task_threads = push_array(arena, TS_TaskThread, ts_shared->task_threads_count); ts_shared->task_threads = push_array(arena, TS_TaskThread, ts_shared->task_threads_count);
for(U64 idx = 0; idx < ts_shared->task_threads_count; idx += 1) for(U64 idx = 0; idx < ts_shared->task_threads_count; idx += 1)
{ {
ts_shared->task_threads[idx].arena = arena_alloc(); ts_shared->task_threads[idx].arena = arena_alloc();
ts_shared->task_threads[idx].thread = os_launch_thread(ts_task_thread__entry_point, (void *)idx, 0); ts_shared->task_threads[idx].thread = os_thread_launch(ts_task_thread__entry_point, (void *)idx, 0);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Top-Level Accessors //~ rjf: Top-Level Accessors
internal U64 internal U64
ts_thread_count(void) ts_thread_count(void)
{ {
return ts_shared->task_threads_count; return ts_shared->task_threads_count;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: High-Level Task Kickoff / Joining //~ rjf: High-Level Task Kickoff / Joining
internal TS_Ticket internal TS_Ticket
ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p) ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p)
{ {
ProfBeginFunction(); ProfBeginFunction();
// rjf: obtain number & slot/stripe for next artifact // rjf: obtain number & slot/stripe for next artifact
U64 artifact_num = ins_atomic_u64_inc_eval(&ts_shared->artifact_num_gen); U64 artifact_num = ins_atomic_u64_inc_eval(&ts_shared->artifact_num_gen);
U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; U64 slot_idx = artifact_num%ts_shared->artifact_slots_count;
U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count;
TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx];
TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx];
// rjf: allocate artifact // rjf: allocate artifact
TS_TaskArtifact *artifact = 0; TS_TaskArtifact *artifact = 0;
ProfScope("allocate artifact") ProfScope("allocate artifact")
{ {
OS_MutexScopeW(stripe->rw_mutex) OS_MutexScopeW(stripe->rw_mutex)
{ {
artifact = stripe->free_artifact; artifact = stripe->free_artifact;
if(artifact != 0) if(artifact != 0)
{ {
SLLStackPop(stripe->free_artifact); SLLStackPop(stripe->free_artifact);
} }
else else
{ {
artifact = push_array_no_zero(stripe->arena, TS_TaskArtifact, 1); artifact = push_array_no_zero(stripe->arena, TS_TaskArtifact, 1);
} }
artifact->num = artifact_num; artifact->num = artifact_num;
artifact->task_is_done = 0; artifact->task_is_done = 0;
artifact->result = 0; artifact->result = 0;
} }
} }
// rjf: form ticket out of artifact info // rjf: form ticket out of artifact info
TS_Ticket ticket = {artifact_num, (U64)artifact}; TS_Ticket ticket = {artifact_num, (U64)artifact};
// rjf: push task info to task ring buffer // rjf: push task info to task ring buffer
ProfScope("push task info to task ring buffer") ProfScope("push task info to task ring buffer")
{ {
OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;) OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;)
{ {
U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos; U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos;
U64 available_size = ts_shared->u2t_ring_size-unconsumed_size; U64 available_size = ts_shared->u2t_ring_size-unconsumed_size;
if(available_size >= sizeof(entry_point) + sizeof(p) + sizeof(ticket)) if(available_size >= sizeof(entry_point) + sizeof(p) + sizeof(ticket))
{ {
Arena *task_arena = 0; Arena *task_arena = 0;
if(optional_arena_ptr != 0) if(optional_arena_ptr != 0)
{ {
task_arena = *optional_arena_ptr; task_arena = *optional_arena_ptr;
} }
ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &entry_point); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &entry_point);
ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &task_arena); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &task_arena);
ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &p); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &p);
ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &ticket); ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &ticket);
if(optional_arena_ptr != 0) if(optional_arena_ptr != 0)
{ {
*optional_arena_ptr = 0; *optional_arena_ptr = 0;
} }
break; break;
} }
os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64); os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64);
} }
os_condition_variable_signal(ts_shared->u2t_ring_cv); os_condition_variable_signal(ts_shared->u2t_ring_cv);
} }
ProfEnd(); ProfEnd();
return ticket; return ticket;
} }
internal void * internal void *
ts_join(TS_Ticket ticket, U64 endt_us) ts_join(TS_Ticket ticket, U64 endt_us)
{ {
void *result = 0; void *result = 0;
U64 artifact_num = ticket.u64[0]; U64 artifact_num = ticket.u64[0];
U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; U64 slot_idx = artifact_num%ts_shared->artifact_slots_count;
U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count;
TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx];
TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx];
TS_TaskArtifact *artifact = (TS_TaskArtifact *)ticket.u64[1]; TS_TaskArtifact *artifact = (TS_TaskArtifact *)ticket.u64[1];
if(artifact != 0) if(artifact != 0)
{ {
OS_MutexScopeR(stripe->rw_mutex) for(;;) OS_MutexScopeR(stripe->rw_mutex) for(;;)
{ {
B64 task_is_done = artifact->task_is_done; B64 task_is_done = artifact->task_is_done;
if(task_is_done) if(task_is_done)
{ {
OS_MutexScopeRWPromote(stripe->rw_mutex) OS_MutexScopeRWPromote(stripe->rw_mutex)
{ {
result = artifact->result; result = artifact->result;
SLLStackPush(stripe->free_artifact, artifact); SLLStackPush(stripe->free_artifact, artifact);
} }
break; break;
} }
if(os_now_microseconds() >= endt_us) if(os_now_microseconds() >= endt_us)
{ {
break; break;
} }
os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us);
} }
} }
return result; return result;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Task Threads //~ rjf: Task Threads
internal void internal void
ts_u2t_dequeue_task(TS_TaskFunctionType **entry_point_out, Arena **arena_out, void **p_out, TS_Ticket *ticket_out) ts_u2t_dequeue_task(TS_TaskFunctionType **entry_point_out, Arena **arena_out, void **p_out, TS_Ticket *ticket_out)
{ {
OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;) OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;)
{ {
U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos; U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos;
if(unconsumed_size >= sizeof(*entry_point_out) + sizeof(*p_out) + sizeof(*ticket_out)) if(unconsumed_size >= sizeof(*entry_point_out) + sizeof(*p_out) + sizeof(*ticket_out))
{ {
ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, entry_point_out); ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, entry_point_out);
ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, arena_out); ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, arena_out);
ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, p_out); ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, p_out);
ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, ticket_out); ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, ticket_out);
break; break;
} }
os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64); os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64);
} }
os_condition_variable_broadcast(ts_shared->u2t_ring_cv); os_condition_variable_broadcast(ts_shared->u2t_ring_cv);
} }
internal void internal void
ts_task_thread__entry_point(void *p) ts_task_thread__entry_point(void *p)
{ {
U64 thread_idx = (U64)p; U64 thread_idx = (U64)p;
ThreadNameF("[ts] task thread #%I64u", thread_idx); ThreadNameF("[ts] task thread #%I64u", thread_idx);
TS_TaskThread *thread = &ts_shared->task_threads[thread_idx]; TS_TaskThread *thread = &ts_shared->task_threads[thread_idx];
for(;;) for(;;)
{ {
//- rjf: grab next task //- rjf: grab next task
TS_TaskFunctionType *task_function = 0; TS_TaskFunctionType *task_function = 0;
Arena *task_arena = 0; Arena *task_arena = 0;
void *task_params = 0; void *task_params = 0;
TS_Ticket task_ticket = {0}; TS_Ticket task_ticket = {0};
ts_u2t_dequeue_task(&task_function, &task_arena, &task_params, &task_ticket); ts_u2t_dequeue_task(&task_function, &task_arena, &task_params, &task_ticket);
//- rjf: use task thread's arena if none specified //- rjf: use task thread's arena if none specified
if(task_arena == 0) if(task_arena == 0)
{ {
task_arena = thread->arena; task_arena = thread->arena;
} }
//- rjf: run task //- rjf: run task
void *task_result = task_function(task_arena, thread_idx, task_params); void *task_result = task_function(task_arena, thread_idx, task_params);
//- rjf: store into artifact //- rjf: store into artifact
U64 artifact_num = task_ticket.u64[0]; U64 artifact_num = task_ticket.u64[0];
U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; U64 slot_idx = artifact_num%ts_shared->artifact_slots_count;
U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count;
TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx];
TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx];
TS_TaskArtifact *artifact = (TS_TaskArtifact *)task_ticket.u64[1]; TS_TaskArtifact *artifact = (TS_TaskArtifact *)task_ticket.u64[1];
OS_MutexScopeW(stripe->rw_mutex) OS_MutexScopeW(stripe->rw_mutex)
{ {
artifact->task_is_done = 1; artifact->task_is_done = 1;
artifact->result = task_result; artifact->result = task_result;
} }
os_condition_variable_broadcast(stripe->cv); os_condition_variable_broadcast(stripe->cv);
} }
} }
+2386 -2386
View File
File diff suppressed because it is too large Load Diff
+405 -405
View File
@@ -1,405 +1,405 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Helpers //~ rjf: Basic Helpers
internal TEX_Topology internal TEX_Topology
tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt) tex_topology_make(Vec2S32 dim, R_Tex2DFormat fmt)
{ {
TEX_Topology top = {0}; TEX_Topology top = {0};
top.dim.x = (S16)Clamp(0, dim.x, max_S32); top.dim.x = (S16)Clamp(0, dim.x, max_S32);
top.dim.y = (S16)Clamp(0, dim.y, max_S32); top.dim.y = (S16)Clamp(0, dim.y, max_S32);
top.fmt = fmt; top.fmt = fmt;
return top; return top;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Main Layer Initialization //~ rjf: Main Layer Initialization
internal void internal void
tex_init(void) tex_init(void)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
tex_shared = push_array(arena, TEX_Shared, 1); tex_shared = push_array(arena, TEX_Shared, 1);
tex_shared->arena = arena; tex_shared->arena = arena;
tex_shared->slots_count = 1024; tex_shared->slots_count = 1024;
tex_shared->stripes_count = Min(tex_shared->slots_count, os_logical_core_count()); tex_shared->stripes_count = Min(tex_shared->slots_count, os_get_system_info()->logical_processor_count);
tex_shared->slots = push_array(arena, TEX_Slot, tex_shared->slots_count); tex_shared->slots = push_array(arena, TEX_Slot, tex_shared->slots_count);
tex_shared->stripes = push_array(arena, TEX_Stripe, tex_shared->stripes_count); tex_shared->stripes = push_array(arena, TEX_Stripe, tex_shared->stripes_count);
tex_shared->stripes_free_nodes = push_array(arena, TEX_Node *, tex_shared->stripes_count); tex_shared->stripes_free_nodes = push_array(arena, TEX_Node *, tex_shared->stripes_count);
for(U64 idx = 0; idx < tex_shared->stripes_count; idx += 1) for(U64 idx = 0; idx < tex_shared->stripes_count; idx += 1)
{ {
tex_shared->stripes[idx].arena = arena_alloc(); tex_shared->stripes[idx].arena = arena_alloc();
tex_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); tex_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc();
tex_shared->stripes[idx].cv = os_condition_variable_alloc(); tex_shared->stripes[idx].cv = os_condition_variable_alloc();
} }
tex_shared->u2x_ring_size = KB(64); tex_shared->u2x_ring_size = KB(64);
tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size);
tex_shared->u2x_ring_cv = os_condition_variable_alloc(); tex_shared->u2x_ring_cv = os_condition_variable_alloc();
tex_shared->u2x_ring_mutex = os_mutex_alloc(); tex_shared->u2x_ring_mutex = os_mutex_alloc();
tex_shared->xfer_thread_count = Clamp(1, os_logical_core_count()-1, 4); tex_shared->xfer_thread_count = Clamp(1, os_get_system_info()->logical_processor_count-1, 4);
tex_shared->xfer_threads = push_array(arena, OS_Handle, tex_shared->xfer_thread_count); tex_shared->xfer_threads = push_array(arena, OS_Handle, tex_shared->xfer_thread_count);
for(U64 idx = 0; idx < tex_shared->xfer_thread_count; idx += 1) for(U64 idx = 0; idx < tex_shared->xfer_thread_count; idx += 1)
{ {
tex_shared->xfer_threads[idx] = os_launch_thread(tex_xfer_thread__entry_point, (void *)idx, 0); tex_shared->xfer_threads[idx] = os_thread_launch(tex_xfer_thread__entry_point, (void *)idx, 0);
} }
tex_shared->evictor_thread = os_launch_thread(tex_evictor_thread__entry_point, 0, 0); tex_shared->evictor_thread = os_thread_launch(tex_evictor_thread__entry_point, 0, 0);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Thread Context Initialization //~ rjf: Thread Context Initialization
internal void internal void
tex_tctx_ensure_inited(void) tex_tctx_ensure_inited(void)
{ {
if(tex_tctx == 0) if(tex_tctx == 0)
{ {
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
tex_tctx = push_array(arena, TEX_TCTX, 1); tex_tctx = push_array(arena, TEX_TCTX, 1);
tex_tctx->arena = arena; tex_tctx->arena = arena;
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: User Clock //~ rjf: User Clock
internal void internal void
tex_user_clock_tick(void) tex_user_clock_tick(void)
{ {
ins_atomic_u64_inc_eval(&tex_shared->user_clock_idx); ins_atomic_u64_inc_eval(&tex_shared->user_clock_idx);
} }
internal U64 internal U64
tex_user_clock_idx(void) tex_user_clock_idx(void)
{ {
return ins_atomic_u64_eval(&tex_shared->user_clock_idx); return ins_atomic_u64_eval(&tex_shared->user_clock_idx);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Scoped Access //~ rjf: Scoped Access
internal TEX_Scope * internal TEX_Scope *
tex_scope_open(void) tex_scope_open(void)
{ {
tex_tctx_ensure_inited(); tex_tctx_ensure_inited();
TEX_Scope *scope = tex_tctx->free_scope; TEX_Scope *scope = tex_tctx->free_scope;
if(scope) if(scope)
{ {
SLLStackPop(tex_tctx->free_scope); SLLStackPop(tex_tctx->free_scope);
} }
else else
{ {
scope = push_array_no_zero(tex_tctx->arena, TEX_Scope, 1); scope = push_array_no_zero(tex_tctx->arena, TEX_Scope, 1);
} }
MemoryZeroStruct(scope); MemoryZeroStruct(scope);
return scope; return scope;
} }
internal void internal void
tex_scope_close(TEX_Scope *scope) tex_scope_close(TEX_Scope *scope)
{ {
for(TEX_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next) for(TEX_Touch *touch = scope->top_touch, *next = 0; touch != 0; touch = next)
{ {
U128 hash = touch->hash; U128 hash = touch->hash;
next = touch->next; next = touch->next;
U64 slot_idx = hash.u64[1]%tex_shared->slots_count; U64 slot_idx = hash.u64[1]%tex_shared->slots_count;
U64 stripe_idx = slot_idx%tex_shared->stripes_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count;
TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Slot *slot = &tex_shared->slots[slot_idx];
TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx];
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash) && MemoryMatchStruct(&touch->topology, &n->topology)) if(u128_match(hash, n->hash) && MemoryMatchStruct(&touch->topology, &n->topology))
{ {
ins_atomic_u64_dec_eval(&n->scope_ref_count); ins_atomic_u64_dec_eval(&n->scope_ref_count);
break; break;
} }
} }
} }
SLLStackPush(tex_tctx->free_touch, touch); SLLStackPush(tex_tctx->free_touch, touch);
} }
SLLStackPush(tex_tctx->free_scope, scope); SLLStackPush(tex_tctx->free_scope, scope);
} }
internal void internal void
tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node) tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node)
{ {
TEX_Touch *touch = tex_tctx->free_touch; TEX_Touch *touch = tex_tctx->free_touch;
ins_atomic_u64_inc_eval(&node->scope_ref_count); ins_atomic_u64_inc_eval(&node->scope_ref_count);
ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds());
ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, tex_user_clock_idx()); ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, tex_user_clock_idx());
if(touch != 0) if(touch != 0)
{ {
SLLStackPop(tex_tctx->free_touch); SLLStackPop(tex_tctx->free_touch);
} }
else else
{ {
touch = push_array_no_zero(tex_tctx->arena, TEX_Touch, 1); touch = push_array_no_zero(tex_tctx->arena, TEX_Touch, 1);
} }
MemoryZeroStruct(touch); MemoryZeroStruct(touch);
touch->hash = node->hash; touch->hash = node->hash;
touch->topology = node->topology; touch->topology = node->topology;
SLLStackPush(scope->top_touch, touch); SLLStackPush(scope->top_touch, touch);
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Cache Lookups //~ rjf: Cache Lookups
internal R_Handle internal R_Handle
tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology) tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology)
{ {
R_Handle handle = {0}; R_Handle handle = {0};
{ {
U64 slot_idx = hash.u64[1]%tex_shared->slots_count; U64 slot_idx = hash.u64[1]%tex_shared->slots_count;
U64 stripe_idx = slot_idx%tex_shared->stripes_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count;
TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Slot *slot = &tex_shared->slots[slot_idx];
TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx];
B32 found = 0; B32 found = 0;
B32 stale = 0; B32 stale = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology))
{ {
handle = n->texture; handle = n->texture;
found = !r_handle_match(r_handle_zero(), handle); found = !r_handle_match(r_handle_zero(), handle);
tex_scope_touch_node__stripe_r_guarded(scope, n); tex_scope_touch_node__stripe_r_guarded(scope, n);
break; break;
} }
} }
} }
B32 node_is_new = 0; B32 node_is_new = 0;
if(!found) if(!found)
{ {
OS_MutexScopeW(stripe->rw_mutex) OS_MutexScopeW(stripe->rw_mutex)
{ {
TEX_Node *node = 0; TEX_Node *node = 0;
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) if(u128_match(hash, n->hash) && MemoryMatchStruct(&topology, &n->topology))
{ {
node = n; node = n;
break; break;
} }
} }
if(node == 0) if(node == 0)
{ {
node = tex_shared->stripes_free_nodes[stripe_idx]; node = tex_shared->stripes_free_nodes[stripe_idx];
if(node) if(node)
{ {
SLLStackPop(tex_shared->stripes_free_nodes[stripe_idx]); SLLStackPop(tex_shared->stripes_free_nodes[stripe_idx]);
} }
else else
{ {
node = push_array_no_zero(stripe->arena, TEX_Node, 1); node = push_array_no_zero(stripe->arena, TEX_Node, 1);
} }
MemoryZeroStruct(node); MemoryZeroStruct(node);
DLLPushBack(slot->first, slot->last, node); DLLPushBack(slot->first, slot->last, node);
node->hash = hash; node->hash = hash;
MemoryCopyStruct(&node->topology, &topology); MemoryCopyStruct(&node->topology, &topology);
node_is_new = 1; node_is_new = 1;
} }
} }
} }
if(node_is_new) if(node_is_new)
{ {
tex_u2x_enqueue_req(hash, topology, max_U64); tex_u2x_enqueue_req(hash, topology, max_U64);
} }
} }
return handle; return handle;
} }
internal R_Handle internal R_Handle
tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out) tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out)
{ {
R_Handle handle = {0}; R_Handle handle = {0};
for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1)
{ {
U128 hash = hs_hash_from_key(key, rewind_idx); U128 hash = hs_hash_from_key(key, rewind_idx);
handle = tex_texture_from_hash_topology(scope, hash, topology); handle = tex_texture_from_hash_topology(scope, hash, topology);
if(!r_handle_match(handle, r_handle_zero())) if(!r_handle_match(handle, r_handle_zero()))
{ {
if(hash_out) if(hash_out)
{ {
*hash_out = hash; *hash_out = hash;
} }
break; break;
} }
} }
return handle; return handle;
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Transfer Threads //~ rjf: Transfer Threads
internal B32 internal B32
tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us)
{ {
B32 good = 0; B32 good = 0;
OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;)
{ {
U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos;
U64 available_size = tex_shared->u2x_ring_size-unconsumed_size; U64 available_size = tex_shared->u2x_ring_size-unconsumed_size;
if(available_size >= sizeof(hash)+sizeof(top)) if(available_size >= sizeof(hash)+sizeof(top))
{ {
good = 1; good = 1;
tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &hash); tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &hash);
tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &top); tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &top);
break; break;
} }
if(os_now_microseconds() >= endt_us) if(os_now_microseconds() >= endt_us)
{ {
break; break;
} }
os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us); os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, endt_us);
} }
if(good) if(good)
{ {
os_condition_variable_broadcast(tex_shared->u2x_ring_cv); os_condition_variable_broadcast(tex_shared->u2x_ring_cv);
} }
return good; return good;
} }
internal void internal void
tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out)
{ {
OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;)
{ {
U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos;
if(unconsumed_size >= sizeof(*hash_out)+sizeof(*top_out)) if(unconsumed_size >= sizeof(*hash_out)+sizeof(*top_out))
{ {
tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, hash_out); tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, hash_out);
tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out); tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out);
break; break;
} }
os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64); os_condition_variable_wait(tex_shared->u2x_ring_cv, tex_shared->u2x_ring_mutex, max_U64);
} }
os_condition_variable_broadcast(tex_shared->u2x_ring_cv); os_condition_variable_broadcast(tex_shared->u2x_ring_cv);
} }
internal void internal void
tex_xfer_thread__entry_point(void *p) tex_xfer_thread__entry_point(void *p)
{ {
for(;;) for(;;)
{ {
HS_Scope *scope = hs_scope_open(); HS_Scope *scope = hs_scope_open();
//- rjf: decode //- rjf: decode
U128 hash = {0}; U128 hash = {0};
TEX_Topology top = {0}; TEX_Topology top = {0};
tex_u2x_dequeue_req(&hash, &top); tex_u2x_dequeue_req(&hash, &top);
//- rjf: unpack hash //- rjf: unpack hash
U64 slot_idx = hash.u64[1]%tex_shared->slots_count; U64 slot_idx = hash.u64[1]%tex_shared->slots_count;
U64 stripe_idx = slot_idx%tex_shared->stripes_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count;
TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Slot *slot = &tex_shared->slots[slot_idx];
TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx];
//- rjf: take task //- rjf: take task
B32 got_task = 0; B32 got_task = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology))
{ {
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
break; break;
} }
} }
} }
//- rjf: hash -> data //- rjf: hash -> data
String8 data = {0}; String8 data = {0};
if(got_task) if(got_task)
{ {
data = hs_data_from_hash(scope, hash); data = hs_data_from_hash(scope, hash);
} }
//- rjf: data * topology -> texture //- rjf: data * topology -> texture
R_Handle texture = {0}; R_Handle texture = {0};
if(got_task && top.dim.x > 0 && top.dim.y > 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt]) if(got_task && top.dim.x > 0 && top.dim.y > 0 && data.size >= (U64)top.dim.x*(U64)top.dim.y*(U64)r_tex2d_format_bytes_per_pixel_table[top.fmt])
{ {
texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str); texture = r_tex2d_alloc(R_ResourceKind_Static, v2s32(top.dim.x, top.dim.y), top.fmt, data.str);
} }
//- rjf: commit results to cache //- rjf: commit results to cache
if(got_task) OS_MutexScopeW(stripe->rw_mutex) if(got_task) OS_MutexScopeW(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology)) if(u128_match(n->hash, hash) && MemoryMatchStruct(&top, &n->topology))
{ {
n->texture = texture; n->texture = texture;
ins_atomic_u32_eval_assign(&n->is_working, 0); ins_atomic_u32_eval_assign(&n->is_working, 0);
ins_atomic_u64_inc_eval(&n->load_count); ins_atomic_u64_inc_eval(&n->load_count);
break; break;
} }
} }
} }
hs_scope_close(scope); hs_scope_close(scope);
} }
} }
//////////////////////////////// ////////////////////////////////
//~ rjf: Evictor Threads //~ rjf: Evictor Threads
internal void internal void
tex_evictor_thread__entry_point(void *p) tex_evictor_thread__entry_point(void *p)
{ {
for(;;) for(;;)
{ {
U64 check_time_us = os_now_microseconds(); U64 check_time_us = os_now_microseconds();
U64 check_time_user_clocks = tex_user_clock_idx(); U64 check_time_user_clocks = tex_user_clock_idx();
U64 evict_threshold_us = 10*1000000; U64 evict_threshold_us = 10*1000000;
U64 evict_threshold_user_clocks = 10; U64 evict_threshold_user_clocks = 10;
for(U64 slot_idx = 0; slot_idx < tex_shared->slots_count; slot_idx += 1) for(U64 slot_idx = 0; slot_idx < tex_shared->slots_count; slot_idx += 1)
{ {
U64 stripe_idx = slot_idx%tex_shared->stripes_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count;
TEX_Slot *slot = &tex_shared->slots[slot_idx]; TEX_Slot *slot = &tex_shared->slots[slot_idx];
TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx]; TEX_Stripe *stripe = &tex_shared->stripes[stripe_idx];
B32 slot_has_work = 0; B32 slot_has_work = 0;
OS_MutexScopeR(stripe->rw_mutex) OS_MutexScopeR(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first; n != 0; n = n->next) for(TEX_Node *n = slot->first; n != 0; n = n->next)
{ {
if(n->scope_ref_count == 0 && if(n->scope_ref_count == 0 &&
n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_time_touched_us+evict_threshold_us <= check_time_us &&
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
n->load_count != 0 && n->load_count != 0 &&
n->is_working == 0) n->is_working == 0)
{ {
slot_has_work = 1; slot_has_work = 1;
break; break;
} }
} }
} }
if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex)
{ {
for(TEX_Node *n = slot->first, *next = 0; n != 0; n = next) for(TEX_Node *n = slot->first, *next = 0; n != 0; n = next)
{ {
next = n->next; next = n->next;
if(n->scope_ref_count == 0 && if(n->scope_ref_count == 0 &&
n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_time_touched_us+evict_threshold_us <= check_time_us &&
n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks &&
n->load_count != 0 && n->load_count != 0 &&
n->is_working == 0) n->is_working == 0)
{ {
DLLRemove(slot->first, slot->last, n); DLLRemove(slot->first, slot->last, n);
if(!r_handle_match(n->texture, r_handle_zero())) if(!r_handle_match(n->texture, r_handle_zero()))
{ {
r_tex2d_release(n->texture); r_tex2d_release(n->texture);
} }
SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n); SLLStackPush(tex_shared->stripes_free_nodes[stripe_idx], n);
} }
} }
} }
os_sleep_milliseconds(5); os_sleep_milliseconds(5);
} }
os_sleep_milliseconds(1000); os_sleep_milliseconds(1000);
} }
} }
+2995 -2995
View File
File diff suppressed because it is too large Load Diff