From a4f915d27d62febe6da6b935eaf6a7f8151f16ee Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 7 Feb 2025 19:05:04 -0500 Subject: [PATCH] progress on os (on files) --- .vscode/settings.json | 6 +- code/base/platform.h | 15 +- code/base/strings.c | 14 +- code/base/thread_context.c | 4 +- code/os/core.c | 194 ------------------ code/os/linux/os_linux.h | 7 +- code/os/os.c | 93 +++++++++ code/os/os.h | 147 ++++++++++++-- code/os/win32/os_win32.c | 402 +++++++++++++------------------------ code/os/win32/os_win32.h | 234 ++++++++++++++++----- 10 files changed, 564 insertions(+), 552 deletions(-) delete mode 100644 code/os/core.c create mode 100644 code/os/os.c diff --git a/.vscode/settings.json b/.vscode/settings.json index cc2dac0..2fba9f1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -47,7 +47,11 @@ "thread": "c", "cmath": "c", "string.h": "c", - "time.h": "c" + "time.h": "c", + "sstream": "c", + "os_win32.h": "c", + "windows.h": "c", + "base.h": "c" }, "workbench.colorCustomizations": { "activityBar.activeBackground": "#713fb8", diff --git a/code/base/platform.h b/code/base/platform.h index 01fbd7a..f706363 100644 --- a/code/base/platform.h +++ b/code/base/platform.h @@ -10,20 +10,7 @@ # include # include # include -# ifndef WIN32_LEAN_AND_MEAN -# ifndef NOMINMAX -# define NOMINMAX -# endif -# -# define WIN32_LEAN_AND_MEAN -# define WIN32_MEAN_AND_LEAN -# define VC_EXTRALEAN -# include -# endif -# undef NOMINMAX -# undef WIN32_LEAN_AND_MEAN -# undef WIN32_MEAN_AND_LEAN -# undef VC_EXTRALEAN + #endif #if LANG_C diff --git a/code/base/strings.c b/code/base/strings.c index 3b3de53..a17be74 100644 --- a/code/base/strings.c +++ b/code/base/strings.c @@ -21,12 +21,12 @@ //////////////////////////////// //~ NOTE(allen): String <-> Integer Tables -read_only global U8 integer_symbols[16] = { +MD_API_C read_only global U8 integer_symbols[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', }; // NOTE(allen): Includes reverses for uppercase and lowercase hex. -read_only global U8 integer_symbol_reverse[128] = { +MD_API_C read_only global U8 integer_symbol_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -37,7 +37,7 @@ read_only global U8 integer_symbol_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; -read_only global U8 base64[64] = { +MD_API_C read_only global U8 base64[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', @@ -46,7 +46,7 @@ read_only global U8 base64[64] = { '_', '$', }; -read_only global U8 base64_reverse[128] = { +MD_API_C read_only global U8 base64_reverse[128] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -574,6 +574,7 @@ str8_from_alloctor_s64(AllocatorInfo ainfo, S64 s64, U32 radix, U8 min_digits, U { String8 result = {0}; if(s64 < 0) { + // TODO(Ed): Review, we should just keep using thread scratch arenas (and provide them to teh context) U8 bytes[KB(8)]; FArena scratch = farena_from_memory(bytes, size_of(bytes)); String8 numeric_part = str8_from_allocator_u64(farena_allocator(scratch), (U64)(-s64), radix, min_digits, digit_group_separator); @@ -969,6 +970,7 @@ path_style_from_str8(String8 string) { void str8_path_list_resolve_dots_in_place(String8List* path, PathStyle style) { + // TODO(Ed): Review TempArena scratch = scratch_begin(0, 0); String8MetaNode* stack = 0; String8MetaNode* free_meta_node = 0; @@ -1605,6 +1607,7 @@ indented_from_string(Arena* arena, String8 string) String8 indented_from_string_alloc(AllocatorInfo ainfo, String8 string) { + // TODO(Ed): Review, we should just keep using thread scratch arenas (and provide them to teh context) Arena* arena = arena_alloc(.backing = ainfo, .block_size = MB(1)); TempArena scratch = scratch_begin(&arena, 1); @@ -1697,6 +1700,7 @@ escaped_from_raw_str8(Arena* arena, String8 string) String8 escaped_from_raw_str8_alloc(AllocatorInfo ainfo, String8 string) { + // TODO(Ed): Review, we should just keep using thread scratch arenas (and provide them to teh context) Arena* arena = arena_alloc(.backing = ainfo, .block_size = MB(1)); TempArena scratch = scratch_begin(&arena, 1); @@ -1796,6 +1800,7 @@ raw_from_escaped_str8(Arena* arena, String8 string) String8 raw_from_escaped_str8_alloc(AllocatorInfo ainfo, String8 string) { + // TODO(Ed): Review, we should just keep using thread scratch arenas (and provide them to teh context) Arena* arena = arena_alloc(.backing = ainfo, .block_size = MB(1)); TempArena scratch = scratch_begin(&arena, 1); @@ -2054,6 +2059,7 @@ fuzzy_match_find(Arena *arena, String8 needle, String8 haystack) FuzzyMatchRangeList fuzzy_match_find_alloc(AllocatorInfo ainfo, String8 needle, String8 haystack) { + // TODO(Ed): Review, we should just keep using thread scratch arenas (and provide them to teh context) Arena* arena = arena_alloc(.backing = ainfo, .block_size = MB(1)); TempArena scratch = temp_begin(&arena, 1); diff --git a/code/base/thread_context.c b/code/base/thread_context.c index ea13036..fc4b2e8 100644 --- a/code/base/thread_context.c +++ b/code/base/thread_context.c @@ -9,10 +9,10 @@ //////////////////////////////// // NOTE(allen): Thread Context Functions -thread_static TCTX* tctx_thread_local; +MD_API_C thread_static TCTX* tctx_thread_local; #if ! MD_BUILD_SUPPLEMENTARY_UNIT -thread_static TCTX* tctx_thread_local = 0; +MD_API_C thread_static TCTX* tctx_thread_local = 0; #endif void diff --git a/code/os/core.c b/code/os/core.c deleted file mode 100644 index 6603ff7..0000000 --- a/code/os/core.c +++ /dev/null @@ -1,194 +0,0 @@ -#ifdef INTELLISENSE_DIRECTIVES -# include "os.h" -#endif - -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Handle Type Functions (Helpers, Implemented Once) - -OS_Handle -os_handle_zero(void) -{ - OS_Handle handle = {0}; - return handle; -} - -B32 -os_handle_match(OS_Handle a, OS_Handle b) -{ - return a.u64[0] == b.u64[0]; -} - -void -os_handle_list_push(Arena *arena, OS_HandleList *handles, OS_Handle handle) -{ - OS_HandleNode *n = push_array(arena, OS_HandleNode, 1); - n->v = handle; - SLLQueuePush(handles->first, handles->last, n); - handles->count += 1; -} - -OS_HandleArray -os_handle_array_from_list(Arena *arena, OS_HandleList *list) -{ - OS_HandleArray result = {0}; - result.count = list->count; - result.v = push_array_no_zero(arena, OS_Handle, result.count); - U64 idx = 0; - for(OS_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) - { - result.v[idx] = n->v; - } - return result; -} - -//////////////////////////////// -//~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) - -String8List -os_string_list_from_argcv(Arena *arena, int argc, char **argv) -{ - String8List result = {0}; - for(int i = 0; i < argc; i += 1) - { - String8 str = str8_cstring(argv[i]); - str8_list_push(arena, &result, str); - } - return result; -} - -//////////////////////////////// -//~ rjf: Filesystem Helpers (Helpers, Implemented Once) - -String8 -os_data_from_file_path(Arena *arena, String8 path) -{ - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); - FileProperties props = os_properties_from_file(file); - String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size)); - os_file_close(file); - return data; -} - -B32 -os_write_data_to_file_path(String8 path, String8 data) -{ - B32 good = 0; - OS_Handle file = os_file_open(OS_AccessFlag_Write, path); - if(!os_handle_match(file, os_handle_zero())) - { - good = 1; - os_file_write(file, r1u64(0, data.size), data.str); - os_file_close(file); - } - return good; -} - -B32 -os_write_data_list_to_file_path(String8 path, String8List list) -{ - B32 good = 0; - OS_Handle file = os_file_open(OS_AccessFlag_Write, path); - if( ! os_handle_match(file, os_handle_zero())) - { - good = 1; - U64 off = 0; - for(String8Node* n = list.first; n != 0; n = n->next) - { - os_file_write(file, r1u64(off, off+n->string.size), n->string.str); - off += n->string.size; - } - os_file_close(file); - } - return good; -} - -B32 -os_append_data_to_file_path(String8 path, String8 data) -{ - B32 good = 0; - if(data.size != 0) - { - OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append, path); - if( ! os_handle_match(file, os_handle_zero())) - { - good = 1; - U64 pos = os_properties_from_file(file).size; - os_file_write(file, r1u64(pos, pos+data.size), data.str); - os_file_close(file); - } - } - return good; -} - -OS_FileID -os_id_from_file_path(String8 path) -{ - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); - OS_FileID id = os_id_from_file(file); - os_file_close(file); - return id; -} - -S64 -os_file_id_compare(OS_FileID a, OS_FileID b) -{ - S64 cmp = memory_compare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v)); - return cmp; -} - -String8 -os_string_from_file_range(Arena* arena, OS_Handle file, Rng1U64 range) -{ - U64 pre_pos = arena_pos(arena); - String8 result; - result.size = dim_1u64(range); - result.str = push_array_no_zero(arena, U8, result.size); - U64 actual_read_size = os_file_read(file, range, result.str); - if(actual_read_size < result.size) - { - arena_pop_to(arena, pre_pos + actual_read_size); - result.size = actual_read_size; - } - return result; -} - -String8 -os_string_from_file_range_alloc(AllocatorInfo ainfo, OS_Handle file, Rng1U64 range) { - String8 result; - result.size = dim_1u64(range); - result.str = alloc_array_no_zero(ainfo, U8, result.size); - U64 actual_read_size = os_file_read(file, range, result.str); - if(actual_read_size < result.size) - { - // TODO(Ed): It may be better to actually wrap the alloation in an arena and then rewind it. - // This would ensure resize isn't doing an expensive shrink (from a bad heap realloc, or something else) - // That or we just leave it up to the user to make sure to pass in an arena. - resize(ainfo, result.str, result.size, result.str + actual_read_size); - result.size = actual_read_size; - } - return result; -} - -//////////////////////////////// -//~ rjf: GUID Helpers (Helpers, Implemented Once) - -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; -} diff --git a/code/os/linux/os_linux.h b/code/os/linux/os_linux.h index 857ab3c..e2f0076 100644 --- a/code/os/linux/os_linux.h +++ b/code/os/linux/os_linux.h @@ -1,7 +1,6 @@ #ifdef INTELLISENSE_DIRECTIVES -#pragma once -#include "base/macros.h" -#include "base/base_types.h" +# pragma once +# include "base/base.h" #endif // Copyright (c) 2024 Epic Games Tools @@ -45,7 +44,7 @@ struct OS_LNX_FileIter struct dirent* dp; String8 path; }; -StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_LNX_FileIter), os_lnx_file_iter_size_check); +md_assert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_LNX_FileIter), os_lnx_file_iter_size_check); //////////////////////////////// //~ rjf: Safe Call Handler Chain diff --git a/code/os/os.c b/code/os/os.c new file mode 100644 index 0000000..b765f30 --- /dev/null +++ b/code/os/os.c @@ -0,0 +1,93 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "os.h" +#endif + +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Filesystem Helpers (Helpers, Implemented Once) + +B32 +os_write_data_to_file_path(String8 path, String8 data) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if(! os_handle_match(file, os_handle_zero())) + { + good = 1; + os_file_write(file, r1u64(0, data.size), data.str); + os_file_close(file); + } + return good; +} + +B32 +os_write_data_list_to_file_path(String8 path, String8List list) +{ + B32 good = 0; + OS_Handle file = os_file_open(OS_AccessFlag_Write, path); + if( ! os_handle_match(file, os_handle_zero())) + { + good = 1; + U64 off = 0; + for(String8Node* n = list.first; n != 0; n = n->next) + { + os_file_write(file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; + } + os_file_close(file); + } + return good; +} + +B32 +os_append_data_to_file_path(String8 path, String8 data) +{ + B32 good = 0; + if(data.size != 0) + { + OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append, path); + if( ! os_handle_match(file, os_handle_zero())) + { + good = 1; + U64 pos = os_properties_from_file(file).size; + os_file_write(file, r1u64(pos, pos+data.size), data.str); + os_file_close(file); + } + } + return good; +} + +String8 +os_string_from_file_range(Arena* arena, OS_Handle file, Rng1U64 range) +{ + U64 pre_pos = arena_pos(arena); + String8 result; + result.size = dim_1u64(range); + result.str = push_array_no_zero(arena, U8, result.size); + U64 actual_read_size = os_file_read(file, range, result.str); + if(actual_read_size < result.size) + { + arena_pop_to(arena, pre_pos + actual_read_size); + result.size = actual_read_size; + } + return result; +} + +String8 +os_string_from_file_range_alloc(AllocatorInfo ainfo, OS_Handle file, Rng1U64 range) { + String8 result; + result.size = dim_1u64(range); + result.str = alloc_array_no_zero(ainfo, U8, result.size); + U64 actual_read_size = os_file_read(file, range, result.str); + if(actual_read_size < result.size) + { + // TODO(Ed): It may be better to actually wrap the alloation in an arena and then rewind it. + // This would ensure resize isn't doing an expensive shrink (from a bad heap realloc, or something else) + // That or we just leave it up to the user to make sure to pass in an arena. + resize(ainfo, result.str, result.size, result.str + actual_read_size); + result.size = actual_read_size; + } + return result; +} diff --git a/code/os/os.h b/code/os/os.h index e744b99..03fc26b 100644 --- a/code/os/os.h +++ b/code/os/os.h @@ -19,7 +19,6 @@ # error OS core layer not implemented for this operating system. #endif - // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) @@ -162,31 +161,144 @@ typedef void OS_ThreadFunctionType(void *ptr); //////////////////////////////// //~ rjf: Handle Type Functions (Helpers, Implemented Once) -OS_Handle os_handle_zero (void); -B32 os_handle_match (OS_Handle a, OS_Handle b); -void os_handle_list_push (Arena* arena, OS_HandleList* handles, OS_Handle handle); -OS_HandleArray os_handle_array_from_list(Arena* arena, OS_HandleList* list); +force_inline OS_Handle os_handle_zero (void) { OS_Handle handle = {0}; return handle; } +force_inline B32 os_handle_match(OS_Handle a, OS_Handle b) { return a.u64[0] == b.u64[0]; } + +void os_handle_list_push (Arena* arena, OS_HandleList* handles, OS_Handle handle); +void os_handle_list_alloc (AllocatorInfo ainfo, OS_HandleList* handles, OS_Handle handle); +OS_HandleArray os_handle_array_from_list (Arena* arena, OS_HandleList* list); +OS_HandleArray os_handle_array_from_list_alloc(AllocatorInfo ainfo, OS_HandleList* list); + +inline void +os_handle_list_push(Arena* arena, OS_HandleList* handles, OS_Handle handle) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + OS_HandleNode* n = push_array(arena, OS_HandleNode, 1); + n->v = handle; + sll_queue_push(handles->first, handles->last, n); + handles->count += 1; +#else + return os_handle_list_alloc(arena_allocator(arena), handles, handle); +#endif +} + +inline OS_HandleArray +os_handle_array_from_list(Arena* arena, OS_HandleList* list) { +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + OS_HandleArray result = {0}; + result.count = list->count; + result.v = push_array_no_zero(arena, OS_Handle, result.count); + U64 idx = 0; + for(OS_HandleNode* n = list->first; n != 0; n = n->next, idx += 1) { + result.v[idx] = n->v; + } + return result; +#else + return os_handle_array_from_list_alloc(arena_allocator(arena), list); +#endif +} + +inline void +os_handle_list_alloc(AllocatorInfo ainfo, OS_HandleList* handles, OS_Handle handle) { + OS_HandleNode* n = alloc_array(ainfo, OS_HandleNode, 1); + n->v = handle; + sll_queue_push(handles->first, handles->last, n); + handles->count += 1; +} + +inline OS_HandleArray +os_handle_array_from_list_alloc(AllocatorInfo ainfo, OS_HandleList* list) { + OS_HandleArray result = {0}; + result.count = list->count; + result.v = alloc_array_no_zero(ainfo, OS_Handle, result.count); + U64 idx = 0; + for(OS_HandleNode* n = list->first; n != 0; n = n->next, idx += 1) { + result.v[idx] = n->v; + } + return result; +} //////////////////////////////// //~ rjf: Command Line Argc/Argv Helper (Helper, Implemented Once) -internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv); +inline String8List +os_string_list_from_argcv(Arena* arena, int argc, char** argv) { + String8List result = {0}; + for(int i = 0; i < argc; i += 1) + { + String8 str = str8_cstring(argv[i]); + str8_list_push(arena, &result, str); + } + return result; +} //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, 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 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); -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); +MD_API B32 os_write_data_to_file_path (String8 path, String8 data); +MD_API B32 os_write_data_list_to_file_path(String8 path, String8List list); +MD_API B32 os_append_data_to_file_path (String8 path, String8 data); + OS_FileID os_id_from_file_path (String8 path); + S64 os_file_id_compare (OS_FileID a, OS_FileID b); + + String8 os_data_from_file_path (Arena* arena, String8 path); + String8 os_data_from_file_path_alloc (AllocatorInfo ainfo, String8 path); +MD_API String8 os_string_from_file_range (Arena* arena, OS_Handle file, Rng1U64 range); +MD_API String8 os_string_from_file_range_alloc(AllocatorInfo ainfo, OS_Handle file, Rng1U64 range); + +inline String8 +os_data_from_file_path(Arena* arena, String8 path) +{ +#if MD_DONT_MAP_ARENA_TO_ALLOCATOR_IMPL + OS_Handle file = os_file_open(OS_AccessFlag_Read | OS_AccessFlag_ShareRead, path); + FileProperties props = os_properties_from_file(file); + String8 data = os_string_from_file_range(arena, file, r1u64(0, props.size)); + os_file_close(file); + return data; +#else + return os_data_from_file_path_alloc(arena_allocator(arena), path); +#endif +} + +inline String8 +os_data_from_file_path_alloc(AllocatorInfo ainfo, String8 path) +{ + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, path); + FileProperties props = os_properties_from_file(file); + String8 data = os_string_from_file_range_alloc(ainfo, file, r1u64(0, props.size)); + os_file_close(file); + return data; +} + + +inline OS_FileID +os_id_from_file_path(String8 path) { + OS_Handle file = os_file_open(OS_AccessFlag_Read | OS_AccessFlag_ShareRead, path); + OS_FileID id = os_id_from_file(file); + os_file_close(file); + return id; +} + +inline S64 os_file_id_compare(OS_FileID a, OS_FileID b) { S64 cmp = memory_compare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v)); return cmp; } //////////////////////////////// //~ rjf: GUID Helpers (Helpers, Implemented Once) -internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); +inline 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; +} //////////////////////////////// //~ rjf: @os_hooks System/Process Info (Implemented Per-OS) @@ -239,11 +351,11 @@ internal FileProperties os_properties_from_file_path(String8 path); //- rjf: file maps internal OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file); internal void os_file_map_close(OS_Handle map); -internal void * os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range); +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, Rng1U64 range); //- rjf: directory iteration -internal OS_FileIter *os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags); +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); internal void os_file_iter_end(OS_FileIter *iter); @@ -256,7 +368,7 @@ internal B32 os_make_directory(String8 path); internal OS_Handle os_shared_memory_alloc(U64 size, String8 name); internal OS_Handle os_shared_memory_open(String8 name); 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_open(OS_Handle handle, Rng1U64 range); internal void os_shared_memory_view_close(OS_Handle handle, void *ptr, Rng1U64 range); //////////////////////////////// @@ -351,4 +463,3 @@ internal OS_Guid os_make_guid(void); #if BUILD_ENTRY_DEFINING_UNIT internal void entry_point(CmdLine *cmdline); #endif - diff --git a/code/os/win32/os_win32.c b/code/os/win32/os_win32.c index 8a06be3..90ff7e7 100644 --- a/code/os/win32/os_win32.c +++ b/code/os/win32/os_win32.c @@ -1,282 +1,158 @@ +#ifdef INTELLISENSE_DIRECTIVES +# include "os_win32.h" +# include "os/os.h" +#endif + // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +MD_API global OS_W32_State os_w32_state = {0}; + //////////////////////////////// //~ rjf: Modern Windows SDK Functions // // (We must dynamically link to them, since they can be missing in older SDKs) typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription); -global W32_SetThreadDescription_Type *w32_SetThreadDescription_func = 0; +MD_API_C global W32_SetThreadDescription_Type* w32_SetThreadDescription_func = 0; //////////////////////////////// //~ rjf: File Info Conversion Helpers -internal FilePropertyFlags -os_w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes) -{ - FilePropertyFlags flags = 0; - if(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - flags |= FilePropertyFlag_IsFolder; - } - return flags; -} - -internal void -os_w32_file_properties_from_attribute_data(FileProperties *properties, WIN32_FILE_ATTRIBUTE_DATA *attributes) -{ - properties->size = Compose64Bit(attributes->nFileSizeHigh, attributes->nFileSizeLow); - os_w32_dense_time_from_file_time(&properties->created, &attributes->ftCreationTime); - os_w32_dense_time_from_file_time(&properties->modified, &attributes->ftLastWriteTime); - properties->flags = os_w32_file_property_flags_from_dwFileAttributes(attributes->dwFileAttributes); -} - //////////////////////////////// //~ rjf: Time Conversion Helpers -internal void -os_w32_date_time_from_system_time(DateTime *out, SYSTEMTIME *in) -{ - out->year = in->wYear; - out->mon = in->wMonth - 1; - out->wday = in->wDayOfWeek; - out->day = in->wDay; - out->hour = in->wHour; - out->min = in->wMinute; - out->sec = in->wSecond; - out->msec = in->wMilliseconds; -} - -internal void -os_w32_system_time_from_date_time(SYSTEMTIME *out, DateTime *in) -{ - out->wYear = (WORD)(in->year); - out->wMonth = in->mon + 1; - out->wDay = in->day; - out->wHour = in->hour; - out->wMinute = in->min; - out->wSecond = in->sec; - out->wMilliseconds = in->msec; -} - -internal void -os_w32_dense_time_from_file_time(DenseTime *out, FILETIME *in) -{ - SYSTEMTIME systime = {0}; - FileTimeToSystemTime(in, &systime); - DateTime date_time = {0}; - os_w32_date_time_from_system_time(&date_time, &systime); - *out = dense_time_from_date_time(date_time); -} - -internal U32 +U32 os_w32_sleep_ms_from_endt_us(U64 endt_us) { - U32 sleep_ms = 0; - if(endt_us == max_U64) - { - sleep_ms = INFINITE; - } - else - { - U64 begint = os_now_microseconds(); - if(begint < endt_us) - { - U64 sleep_us = endt_us - begint; - sleep_ms = (U32)((sleep_us + 999)/1000); - } - } - return sleep_ms; + U32 sleep_ms = 0; + if (endt_us == MAX_U64) { + sleep_ms = INFINITE; + } + else + { + U64 begint = os_now_microseconds(); + if (begint < endt_us) { + U64 sleep_us = endt_us - begint; + sleep_ms = (U32)((sleep_us + 999)/1000); + } + } + return sleep_ms; } //////////////////////////////// //~ rjf: Entity Functions -internal OS_W32_Entity * +OS_W32_Entity* os_w32_entity_alloc(OS_W32_EntityKind kind) { - OS_W32_Entity *result = 0; - EnterCriticalSection(&os_w32_state.entity_mutex); - { - result = os_w32_state.entity_free; - if(result) - { - SLLStackPop(os_w32_state.entity_free); - } - else - { - result = push_array_no_zero(os_w32_state.entity_arena, OS_W32_Entity, 1); - } - MemoryZeroStruct(result); - } - LeaveCriticalSection(&os_w32_state.entity_mutex); - result->kind = kind; - return result; + OS_W32_Entity *result = 0; + EnterCriticalSection(&os_w32_state.entity_mutex); + { + result = os_w32_state.entity_free; + if(result) + { + sll_stack_pop(os_w32_state.entity_free); + } + else + { + result = push_array_no_zero(os_w32_state.entity_arena, OS_W32_Entity, 1); + } + memory_zero_struct(result); + } + LeaveCriticalSection(&os_w32_state.entity_mutex); + result->kind = kind; + return result; } -internal void +void os_w32_entity_release(OS_W32_Entity *entity) { entity->kind = OS_W32_EntityKind_Null; EnterCriticalSection(&os_w32_state.entity_mutex); - SLLStackPush(os_w32_state.entity_free, entity); + sll_stack_push(os_w32_state.entity_free, entity); LeaveCriticalSection(&os_w32_state.entity_mutex); } //////////////////////////////// //~ rjf: Thread Entry Point -internal DWORD +DWORD os_w32_thread_entry_point(void *ptr) { - OS_W32_Entity *entity = (OS_W32_Entity *)ptr; - OS_ThreadFunctionType *func = entity->thread.func; - void *thread_ptr = entity->thread.ptr; - TCTX tctx_; - tctx_init_and_equip(&tctx_); - func(thread_ptr); - tctx_release(); - return 0; + OS_W32_Entity* entity = (OS_W32_Entity*)ptr; + OS_ThreadFunctionType* func = entity->thread.func; + void* thread_ptr = entity->thread.ptr; + + TCTX tctx_; + tctx_init_and_equip(&tctx_); + func(thread_ptr); + tctx_release(); + return 0; } //////////////////////////////// //~ rjf: @os_hooks System/Process Info (Implemented Per-OS) -internal OS_SystemInfo * -os_get_system_info(void) -{ - return &os_w32_state.system_info; +OS_SystemInfo* +os_get_system_info(void) { + return &os_w32_state.system_info; } -internal OS_ProcessInfo * -os_get_process_info(void) -{ +OS_ProcessInfo* +os_get_process_info(void) { return &os_w32_state.process_info; } -internal String8 -os_get_current_path(Arena *arena) -{ - Temp scratch = scratch_begin(&arena, 1); - DWORD length = GetCurrentDirectoryW(0, 0); - U16 *memory = push_array_no_zero(scratch.arena, U16, length + 1); - length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory); - String8 name = str8_from_16(arena, str16(memory, length)); - scratch_end(scratch); - return name; -} - -//////////////////////////////// -//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) - -//- rjf: basic - -internal void * -os_reserve(U64 size) -{ - void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); - return result; -} - -internal B32 -os_commit(void *ptr, U64 size) -{ - B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); - return result; -} - -internal void -os_decommit(void *ptr, U64 size) -{ - VirtualFree(ptr, size, MEM_DECOMMIT); -} - -internal void -os_release(void *ptr, U64 size) -{ - // NOTE(rjf): size not used - not necessary on Windows, but necessary for other OSes. - VirtualFree(ptr, 0, MEM_RELEASE); -} - -//- rjf: large pages - -internal void * -os_reserve_large(U64 size) -{ - // we commit on reserve because windows - void *result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); - return result; -} - -internal B32 -os_commit_large(void *ptr, U64 size) -{ - return 1; -} - //////////////////////////////// //~ rjf: @os_hooks Thread Info (Implemented Per-OS) -internal U32 -os_tid(void) -{ - DWORD id = GetCurrentThreadId(); - return (U32)id; -} - -internal void +void os_set_thread_name(String8 name) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); - // rjf: windows 10 style - if(w32_SetThreadDescription_func) - { - String16 name16 = str16_from_8(scratch.arena, name); - HRESULT hr = w32_SetThreadDescription_func(GetCurrentThread(), (WCHAR*)name16.str); - } + // rjf: windows 10 style + if (w32_SetThreadDescription_func) + { + String16 name16 = str16_from_8(scratch.arena, name); + HRESULT hr = w32_SetThreadDescription_func(GetCurrentThread(), (WCHAR*)name16.str); + } - // rjf: raise-exception style - { - String8 name_copy = push_str8_copy(scratch.arena, name); -#pragma pack(push,8) - typedef struct THREADNAME_INFO THREADNAME_INFO; - struct THREADNAME_INFO - { - U32 dwType; // Must be 0x1000. - char *szName; // Pointer to name (in user addr space). - U32 dwThreadID; // Thread ID (-1=caller thread). - U32 dwFlags; // Reserved for future use, must be zero. - }; -#pragma pack(pop) - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = (char *)name_copy.str; - info.dwThreadID = os_tid(); - info.dwFlags = 0; -#pragma warning(push) -#pragma warning(disable: 6320 6322) - __try - { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } -#pragma warning(pop) - } - - scratch_end(scratch); -} + // rjf: raise-exception style + { + String8 name_copy = push_str8_copy(scratch.arena, name); -//////////////////////////////// -//~ rjf: @os_hooks Aborting (Implemented Per-OS) + #pragma pack(push,8) + typedef struct THREADNAME_INFO THREADNAME_INFO; + struct THREADNAME_INFO + { + U32 dwType; // Must be 0x1000. + char* szName; // Pointer to name (in user addr space). + U32 dwThreadID; // Thread ID (-1=caller thread). + U32 dwFlags; // Reserved for future use, must be zero. + }; + #pragma pack(pop) -internal void -os_abort(S32 exit_code) -{ - ExitProcess(exit_code); + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = (char *)name_copy.str; + info.dwThreadID = os_tid(); + info.dwFlags = 0; + + #pragma warning(push) + #pragma warning(disable: 6320 6322) + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + #pragma warning(pop) + } + + scratch_end(scratch); } //////////////////////////////// @@ -284,38 +160,42 @@ os_abort(S32 exit_code) //- rjf: files -internal OS_Handle +OS_Handle os_file_open(OS_AccessFlags flags, String8 path) { - OS_Handle result = {0}; - Temp scratch = scratch_begin(0, 0); - String16 path16 = str16_from_8(scratch.arena, path); - DWORD access_flags = 0; - DWORD share_mode = 0; - DWORD creation_disposition = OPEN_EXISTING; - if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} - if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} - if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} - if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} - if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} - if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} - if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS;} - HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); - if(file != INVALID_HANDLE_VALUE) - { - result.u64[0] = (U64)file; - } - scratch_end(scratch); - return result; + OS_Handle result = {0}; + TempArena scratch = scratch_begin(0, 0); + { + String16 path16 = str16_from_8(scratch.arena, path); + + DWORD access_flags = 0; + DWORD share_mode = 0; + DWORD creation_disposition = OPEN_EXISTING; + + if (flags & OS_AccessFlag_Read) { access_flags |= GENERIC_READ; } + if (flags & OS_AccessFlag_Write) { access_flags |= GENERIC_WRITE; } + if (flags & OS_AccessFlag_Execute) { access_flags |= GENERIC_EXECUTE; } + if (flags & OS_AccessFlag_ShareRead) { share_mode |= FILE_SHARE_READ; } + if (flags & OS_AccessFlag_ShareWrite) { share_mode |= FILE_SHARE_WRITE | FILE_SHARE_DELETE; } + if (flags & OS_AccessFlag_Write) { creation_disposition = CREATE_ALWAYS; } + if (flags & OS_AccessFlag_Append) { creation_disposition = OPEN_ALWAYS; } + + HANDLE file = CreateFileW((WCHAR*)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + if (file != INVALID_HANDLE_VALUE) { + result.u64[0] = (U64)file; + } + } + scratch_end(scratch); + return result; } -internal void +void os_file_close(OS_Handle file) { - if(os_handle_match(file, os_handle_zero())) { return; } - HANDLE handle = (HANDLE)file.u64[0]; - BOOL result = CloseHandle(handle); - (void)result; + if (os_handle_match(file, os_handle_zero())) { return; } + HANDLE handle = (HANDLE)file.u64[0]; + BOOL result = CloseHandle(handle); + (void)result; } internal U64 @@ -438,7 +318,7 @@ os_id_from_file(OS_Handle file) internal B32 os_delete_file_at_path(String8 path) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 path16 = str16_from_8(scratch.arena, path); B32 result = DeleteFileW((WCHAR*)path16.str); scratch_end(scratch); @@ -448,7 +328,7 @@ os_delete_file_at_path(String8 path) internal B32 os_copy_file_path(String8 dst, String8 src) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 dst16 = str16_from_8(scratch.arena, dst); String16 src16 = str16_from_8(scratch.arena, src); B32 result = CopyFileW((WCHAR*)src16.str, (WCHAR*)dst16.str, 0); @@ -459,7 +339,7 @@ os_copy_file_path(String8 dst, String8 src) internal String8 os_full_path_from_path(Arena *arena, String8 path) { - Temp scratch = scratch_begin(&arena, 1); + TempArena scratch = scratch_begin(&arena, 1); DWORD buffer_size = MAX_PATH + 1; U16 *buffer = push_array_no_zero(scratch.arena, U16, buffer_size); String16 path16 = str16_from_8(scratch.arena, path); @@ -472,7 +352,7 @@ os_full_path_from_path(Arena *arena, String8 path) internal B32 os_file_path_exists(String8 path) { - Temp scratch = scratch_begin(0,0); + TempArena scratch = scratch_begin(0,0); String16 path16 = str16_from_8(scratch.arena, path); DWORD attributes = GetFileAttributesW((WCHAR *)path16.str); B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && !!(~attributes & FILE_ATTRIBUTE_DIRECTORY); @@ -484,7 +364,7 @@ internal FileProperties os_properties_from_file_path(String8 path) { WIN32_FIND_DATAW find_data = {0}; - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 path16 = str16_from_8(scratch.arena, path); HANDLE handle = FindFirstFileW((WCHAR *)path16.str, &find_data); FileProperties props = {0}; @@ -589,7 +469,7 @@ os_file_map_view_close(OS_Handle map, void *ptr, Rng1U64 range) internal OS_FileIter * os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) { - Temp scratch = scratch_begin(&arena, 1); + TempArena scratch = scratch_begin(&arena, 1); String8 path_with_wildcard = push_str8_cat(scratch.arena, path, str8_lit("\\*")); String16 path16 = str16_from_8(scratch.arena, path_with_wildcard); OS_FileIter *iter = push_array(arena, OS_FileIter, 1); @@ -751,7 +631,7 @@ os_shared_memory_alloc(U64 size, String8 name) internal OS_Handle os_shared_memory_open(String8 name) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); HANDLE file = OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, (WCHAR *)name16.str); OS_Handle result = {(U64)file}; @@ -864,7 +744,7 @@ internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params) { OS_Handle result = {0}; - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); //- rjf: form full command string String8 cmd = {0}; @@ -1150,7 +1030,7 @@ os_condition_variable_broadcast(OS_Handle cv) internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); HANDLE handle = CreateSemaphoreW(0, initial_count, max_count, (WCHAR *)name16.str); OS_Handle result = {(U64)handle}; @@ -1168,7 +1048,7 @@ os_semaphore_release(OS_Handle semaphore) internal OS_Handle os_semaphore_open(String8 name) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 name16 = str16_from_8(scratch.arena, name); HANDLE handle = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS , 0, (WCHAR *)name16.str); OS_Handle result = {(U64)handle}; @@ -1206,7 +1086,7 @@ os_semaphore_drop(OS_Handle semaphore) internal OS_Handle os_library_open(String8 path) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); String16 path16 = str16_from_8(scratch.arena, path); HMODULE mod = LoadLibraryW((LPCWSTR)path16.str); OS_Handle result = { (U64)mod }; @@ -1217,7 +1097,7 @@ os_library_open(String8 path) internal VoidProc* os_library_load_proc(OS_Handle lib, String8 name) { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); HMODULE mod = (HMODULE)lib.u64[0]; name = push_str8_copy(scratch.arena, name); VoidProc *result = (VoidProc*)GetProcAddress(mod, (LPCSTR)name.str); @@ -1565,7 +1445,7 @@ w32_entry_point_caller(int argc, WCHAR **wargv) { OS_ProcessInfo *info = &os_w32_state.process_info; { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); DWORD size = KB(32); U16 *buffer = push_array_no_zero(scratch.arena, U16, size); DWORD length = GetModuleFileNameW(0, (WCHAR*)buffer, size); @@ -1576,7 +1456,7 @@ w32_entry_point_caller(int argc, WCHAR **wargv) } info->initial_path = os_get_current_path(arena); { - Temp scratch = scratch_begin(0, 0); + TempArena scratch = scratch_begin(0, 0); U64 size = KB(32); U16 *buffer = push_array_no_zero(scratch.arena, U16, size); if(SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))) diff --git a/code/os/win32/os_win32.h b/code/os/win32/os_win32.h index 93be306..f966cbf 100644 --- a/code/os/win32/os_win32.h +++ b/code/os/win32/os_win32.h @@ -1,13 +1,20 @@ +#ifdef INTELLISENSE_DIRECTIVES +# pragma once +# include "base/base.h" +#endif + // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef OS_CORE_WIN32_H -#define OS_CORE_WIN32_H - //////////////////////////////// //~ rjf: Includes / Libraries +#ifndef NOMINMAX +#define NOMINMAX +#endif #define WIN32_LEAN_AND_MEAN +#define WIN32_MEAN_AND_LEAN +#define VC_EXTRALEAN #include #include #include @@ -22,6 +29,10 @@ #pragma comment(lib, "shlwapi") #pragma comment(lib, "comctl32") #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 +#undef NOMINMAX +#undef WIN32_LEAN_AND_MEAN +#undef WIN32_MEAN_AND_LEAN +#undef VC_EXTRALEAN //////////////////////////////// //~ rjf: File Iterator Types @@ -29,45 +40,48 @@ typedef struct OS_W32_FileIter OS_W32_FileIter; struct OS_W32_FileIter { - HANDLE handle; - WIN32_FIND_DATAW find_data; - B32 is_volume_iter; - String8Array drive_strings; - U64 drive_strings_iter_idx; + HANDLE handle; + WIN32_FIND_DATAW find_data; + B32 is_volume_iter; + String8Array drive_strings; + U64 drive_strings_iter_idx; }; -StaticAssert(sizeof(Member(OS_FileIter, memory)) >= sizeof(OS_W32_FileIter), file_iter_memory_size); +md_static_assert(sizeof(member(OS_FileIter, memory)) >= sizeof(OS_W32_FileIter), file_iter_memory_size); //////////////////////////////// //~ rjf: Entity Types -typedef enum OS_W32_EntityKind +typedef enum OS_W32_EntityKind OS_W32_EntityKind; +enum OS_W32_EntityKind { - OS_W32_EntityKind_Null, - OS_W32_EntityKind_Thread, - OS_W32_EntityKind_Mutex, - OS_W32_EntityKind_RWMutex, - OS_W32_EntityKind_ConditionVariable, -} -OS_W32_EntityKind; + OS_W32_EntityKind_Null, + OS_W32_EntityKind_Thread, + OS_W32_EntityKind_Mutex, + OS_W32_EntityKind_RWMutex, + OS_W32_EntityKind_ConditionVariable, +}; + +typedef struct OS_W32_EntityThread OS_W32_EntityThread; +struct OS_W32_EntityThread +{ + OS_ThreadFunctionType* func; + void* ptr; + HANDLE handle; + DWORD tid; +}; typedef struct OS_W32_Entity OS_W32_Entity; struct OS_W32_Entity { - OS_W32_Entity *next; - OS_W32_EntityKind kind; - union - { - struct - { - OS_ThreadFunctionType *func; - void *ptr; - HANDLE handle; - DWORD tid; - } thread; - CRITICAL_SECTION mutex; - SRWLOCK rw_mutex; - CONDITION_VARIABLE cv; - }; + OS_W32_Entity* next; + OS_W32_EntityKind kind; + union + { + OS_W32_EntityThread thread; + CRITICAL_SECTION mutex; + SRWLOCK rw_mutex; + CONDITION_VARIABLE cv; + }; }; //////////////////////////////// @@ -76,47 +90,159 @@ struct OS_W32_Entity typedef struct OS_W32_State OS_W32_State; struct OS_W32_State { - Arena *arena; - - // rjf: info - OS_SystemInfo system_info; - OS_ProcessInfo process_info; - U64 microsecond_resolution; - - // rjf: entity storage - CRITICAL_SECTION entity_mutex; - Arena *entity_arena; - OS_W32_Entity *entity_free; + Arena* arena; + + // rjf: info + OS_SystemInfo system_info; + OS_ProcessInfo process_info; + U64 microsecond_resolution; + + // 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}; +MD_API extern 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); +inline FilePropertyFlags +os_w32_file_property_flags_from_dwFileAttributes(DWORD dwFileAttributes) +{ + FilePropertyFlags flags = 0; + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + flags |= FilePropertyFlag_IsFolder; + } + return flags; +} + +inline void +os_w32_file_properties_from_attribute_data(FileProperties* properties, WIN32_FILE_ATTRIBUTE_DATA* attributes) { + properties->size = compose_64bit(attributes->nFileSizeHigh, attributes->nFileSizeLow); + os_w32_dense_time_from_file_time(&properties->created, &attributes->ftCreationTime); + os_w32_dense_time_from_file_time(&properties->modified, &attributes->ftLastWriteTime); + properties->flags = os_w32_file_property_flags_from_dwFileAttributes(attributes->dwFileAttributes); +} //////////////////////////////// //~ 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); + void os_w32_date_time_from_system_time(DateTime* out, SYSTEMTIME* in); + void os_w32_system_time_from_date_time(SYSTEMTIME* out, DateTime* in); + void os_w32_dense_time_from_file_time (DenseTime* out, FILETIME* in); +MD_API U32 os_w32_sleep_ms_from_endt_us(U64 endt_us); + +inline void +os_w32_date_time_from_system_time(DateTime* out, SYSTEMTIME* in) +{ + out->year = in->wYear; + out->mon = in->wMonth - 1; + out->wday = in->wDayOfWeek; + out->day = in->wDay; + + out->hour = in->wHour; + out->min = in->wMinute; + out->sec = in->wSecond; + out->msec = in->wMilliseconds; +} + +inline void +os_w32_system_time_from_date_time(SYSTEMTIME* out, DateTime* in) +{ + out->wYear = (WORD)(in->year); + out->wMonth = in->mon + 1; + out->wDay = in->day; + + out->wHour = in->hour; + out->wMinute = in->min; + out->wSecond = in->sec; + out->wMilliseconds = in->msec; +} + +inline void +os_w32_dense_time_from_file_time(DenseTime* out, FILETIME* in) { + SYSTEMTIME systime = {0}; + DateTime date_time = {0}; + FileTimeToSystemTime(in, &systime); + os_w32_date_time_from_system_time(&date_time, &systime); + *out = dense_time_from_date_time(date_time); +} //////////////////////////////// //~ 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); +MD_API OS_W32_Entity* os_w32_entity_alloc (OS_W32_EntityKind kind); +MD_API void os_w32_entity_release(OS_W32_Entity* entity); + +inline void +os_w32_entity_release(OS_W32_Entity *entity) { + entity->kind = OS_W32_EntityKind_Null; + EnterCriticalSection(&os_w32_state.entity_mutex); + sll_stack_push(os_w32_state.entity_free, entity); + LeaveCriticalSection(&os_w32_state.entity_mutex); +} //////////////////////////////// //~ rjf: Thread Entry Point -internal DWORD os_w32_thread_entry_point(void *ptr); +MD_API DWORD os_w32_thread_entry_point(void* ptr); + +//////////////////////////////// +//~ rjf: @os_hooks System/Process Info (Implemented Per-OS) + +inline String8 +os_get_current_path(Arena* arena) { + String8 name; + TempArena scratch = scratch_begin(&arena, 1); + { + DWORD length = GetCurrentDirectoryW(0, 0); + U16* memory = push_array_no_zero(scratch.arena, U16, length + 1); + length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory); + name = str8_from_16(arena, str16(memory, length)); + } + scratch_end(scratch); + return name; +} + +//////////////////////////////// +//~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) + +//- rjf: basic + +force_inline void* os_reserve ( U64 size) { void* result = VirtualAlloc( 0, size, MEM_RESERVE, PAGE_READWRITE); return result; } +force_inline B32 os_commit (void* ptr, U64 size) { B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); return result; } +force_inline void os_decommit(void* ptr, U64 size) { VirtualFree (ptr, size, MEM_DECOMMIT); } + +inline void +os_release(void* ptr, U64 size) { + // NOTE(rjf): size not used - not necessary on Windows, but necessary for other OSes. + VirtualFree(ptr, 0, MEM_RELEASE); +} + +//- rjf: large pages + +inline void* +os_reserve_large(U64 size) { + // we commit on reserve because windows + void* result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE); + return result; +} + +inline B32 os_commit_large(void *ptr, U64 size) { return 1; } + +//////////////////////////////// +//~ rjf: @os_hooks Thread Info (Implemented Per-OS) + +inline U32 os_tid(void) { DWORD id = GetCurrentThreadId(); return (U32)id; } + +//////////////////////////////// +//~ rjf: @os_hooks Aborting (Implemented Per-OS) + +inline void os_abort(S32 exit_code) { ExitProcess(exit_code); } + -#endif // OS_CORE_WIN32_H