diff --git a/.vscode/settings.json b/.vscode/settings.json index 15d3e03..ab5b18d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -52,7 +52,20 @@ "os_win32.h": "c", "windows.h": "c", "base.h": "c", - "os_linux.h": "c" + "os_linux.h": "c", + "array": "c", + "vector": "c", + "dbghelp.h": "c", + "namespace.h": "c", + "space.h": "c", + "logger.h": "c", + "entry_point.h": "c", + "markup.h": "c", + "generic_macros.h": "c", + "profiling.h": "c", + "ring.h": "c", + "debug.h": "c", + "arena.h": "c" }, "workbench.colorCustomizations": { "activityBar.activeBackground": "#713fb8", diff --git a/code/base/context_cracking.h b/code/base/context_cracking.h index 4503481..0002328 100644 --- a/code/base/context_cracking.h +++ b/code/base/context_cracking.h @@ -13,6 +13,53 @@ # define BUILD_SUPPLEMENTARY_UNIT 0 #endif +#if !defined(BUILD_ENTRY_DEFINING_UNIT) +# define BUILD_ENTRY_DEFINING_UNIT 0 +#endif + +#if !defined(BUILD_CONSOLE_INTERFACE) +# define BUILD_CONSOLE_INTERFACE 0 +#endif + +#if !defined(BUILD_VERSION_MAJOR) +# define BUILD_VERSION_MAJOR 0 +#endif + +#if !defined(BUILD_VERSION_MINOR) +# define BUILD_VERSION_MINOR 1 +#endif + +#if !defined(BUILD_VERSION_PATCH) +# define BUILD_VERSION_PATCH 0 +#endif + +#define BUILD_VERSION_STRING_LITERAL stringify(BUILD_VERSION_MAJOR) "." stringify(BUILD_VERSION_MINOR) "." stringify(BUILD_VERSION_PATCH) + +#if BUILD_DEBUG +# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]" +#else +# define BUILD_MODE_STRING_LITERAL_APPEND "" +#endif +#if defined(BUILD_GIT_HASH) +# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]" +#else +# define BUILD_GIT_HASH_STRING_LITERAL_APPEND "" +#endif + +#if !defined(BUILD_TITLE) +# define BUILD_TITLE "Untitled" +#endif + +#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL) +# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#endif + +#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL) +# define BUILD_ISSUES_LINK_STRING_LITERAL "ADD_BUILD_ISSUES_LINK" +#endif + +#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND + #pragma region Compiler Vendor #if defined( _MSC_VER ) diff --git a/code/base/debug.h b/code/base/debug.h index 6b5a607..e31281c 100644 --- a/code/base/debug.h +++ b/code/base/debug.h @@ -28,7 +28,7 @@ { \ if ( ! ( cond ) ) \ { \ - assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \ + assert_handler( #cond, __FILE__, __func__, scast( S64, __LINE__ ), msg, ##__VA_ARGS__ ); \ GEN_DEBUG_TRAP(); \ } \ } while ( 0 ) diff --git a/code/base/platform.h b/code/base/platform.h index f706363..b854883 100644 --- a/code/base/platform.h +++ b/code/base/platform.h @@ -10,7 +10,6 @@ # include # include # include - #endif #if LANG_C diff --git a/code/base/strings.c b/code/base/strings.c index a17be74..1363273 100644 --- a/code/base/strings.c +++ b/code/base/strings.c @@ -287,6 +287,18 @@ str8_is_integer(String8 string, U32 radix){ return(result); } +U64 +u64_from_str8(String8 string, U32 radix) { + U64 x = 0; + if (1 < radix && radix <= 16) { + for (U64 i = 0; i < string.size; i += 1) { + x *= radix; + x += integer_symbol_reverse[string.str[i]&0x7F]; + } + } + return(x); +} + B32 try_u64_from_str8_c_rules(String8 string, U64 *x) { diff --git a/code/base/strings.h b/code/base/strings.h index b4b27f7..22c264a 100644 --- a/code/base/strings.h +++ b/code/base/strings.h @@ -349,18 +349,6 @@ MD_API String8 str8_from_allocator_size(AllocatorInfo ainfo, U64 z); MD_API String8 str8_from_allocator_u64 (AllocatorInfo ainfo, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); MD_API String8 str8_from_alloctor_s64 (AllocatorInfo ainfo, S64 u64, U32 radix, U8 min_digits, U8 digit_group_separator); -inline U64 -u64_from_str8(String8 string, U32 radix) { - U64 x = 0; - if (1 < radix && radix <= 16) { - for (U64 i = 0; i < string.size; i += 1) { - x *= radix; - x += integer_symbol_reverse[string.str[i]&0x7F]; - } - } - return(x); -} - inline S64 s64_from_str8(String8 string, U32 radix) { S64 sign = sign_from_str8(string, &string); diff --git a/code/metagen/Readme.md b/code/metagen/Readme.md new file mode 100644 index 0000000..84104ae --- /dev/null +++ b/code/metagen/Readme.md @@ -0,0 +1,3 @@ +# Metagen + + diff --git a/code/os/linux/os_linux.c b/code/os/linux/os_linux.c index afdc0e0..f8f9c4f 100644 --- a/code/os/linux/os_linux.c +++ b/code/os/linux/os_linux.c @@ -45,7 +45,7 @@ os_lnx_entity_release(OS_LNX_Entity *entity) { //////////////////////////////// //~ rjf: Thread Entry Point -internal void * +void* os_lnx_thread_entry_point(void *ptr) { OS_LNX_Entity* entity = (OS_LNX_Entity *)ptr; @@ -87,6 +87,11 @@ os_set_thread_name(String8 name) scratch_end(scratch); } +//////////////////////////////// +//~ rjf: @os_hooks Aborting (Implemented Per-OS) + +void os_abort(S32 exit_code) { exit(exit_code); } + //////////////////////////////// //~ rjf: @os_hooks File System (Implemented Per-OS) @@ -115,8 +120,7 @@ os_file_open(OS_AccessFlags flags, String8 path) } void -os_file_close(OS_Handle file) -{ +os_file_close(OS_Handle file) { if (os_handle_match(file, os_handle_zero())) { return; } int fd = (int)file.u64[0]; close(fd); @@ -189,433 +193,435 @@ os_file_set_times(OS_Handle file, DateTime date_time) return good; } -internal FileProperties +FileProperties os_properties_from_file(OS_Handle file) { - if(os_handle_match(file, os_handle_zero())) { return (FileProperties){0}; } - int fd = (int)file.u64[0]; - struct stat fd_stat = {0}; - int fstat_result = fstat(fd, &fd_stat); - FileProperties props = {0}; - if(fstat_result != -1) - { - props = os_lnx_file_properties_from_stat(&fd_stat); - } - return props; + if(os_handle_match(file, os_handle_zero())) { return (FileProperties){0}; } + + int fd = (int)file.u64[0]; + struct stat fd_stat = {0}; + int fstat_result = fstat(fd, &fd_stat); + FileProperties props = {0}; + if (fstat_result != -1) { + props = os_lnx_file_properties_from_stat(&fd_stat); + } + return props; } -internal OS_FileID +OS_FileID os_id_from_file(OS_Handle file) { - if(os_handle_match(file, os_handle_zero())) { return (OS_FileID){0}; } - int fd = (int)file.u64[0]; - struct stat fd_stat = {0}; - int fstat_result = fstat(fd, &fd_stat); - OS_FileID id = {0}; - if(fstat_result != -1) - { - id.v[0] = fd_stat.st_dev; - id.v[1] = fd_stat.st_ino; - } - return id; + if (os_handle_match(file, os_handle_zero())) { return (OS_FileID){0}; } + int fd = (int)file.u64[0]; + struct stat fd_stat = {0}; + int fstat_result = fstat(fd, &fd_stat); + OS_FileID id = {0}; + if(fstat_result != -1) { + id.v[0] = fd_stat.st_dev; + id.v[1] = fd_stat.st_ino; + } + return id; } -internal B32 +B32 os_delete_file_at_path(String8 path) { - Temp scratch = scratch_begin(0, 0); - B32 result = 0; - String8 path_copy = push_str8_copy(scratch.arena, path); - if(remove((char*)path_copy.str) != -1) - { - result = 1; - } - scratch_end(scratch); - return result; + TempArena scratch = scratch_begin(0, 0); + B32 result = 0; + String8 path_copy = push_str8_copy(scratch.arena, path); + if (remove((char*)path_copy.str) != -1) { + result = 1; + } + scratch_end(scratch); + return result; } -internal B32 +B32 os_copy_file_path(String8 dst, String8 src) { - B32 result = 0; - OS_Handle src_h = os_file_open(OS_AccessFlag_Read, src); - OS_Handle dst_h = os_file_open(OS_AccessFlag_Write, dst); - if(!os_handle_match(src_h, os_handle_zero()) && - !os_handle_match(dst_h, os_handle_zero())) - { - FileProperties src_props = os_properties_from_file(src_h); - U64 size = src_props.size; - U64 total_bytes_copied = 0; - U64 bytes_left_to_copy = size; - for(;bytes_left_to_copy > 0;) - { - Temp scratch = scratch_begin(0, 0); - U64 buffer_size = Min(bytes_left_to_copy, MB(8)); - U8 *buffer = push_array_no_zero(scratch.arena, U8, buffer_size); - U64 bytes_read = os_file_read(src_h, r1u64(total_bytes_copied, total_bytes_copied+buffer_size), buffer); - U64 bytes_written = os_file_write(dst_h, r1u64(total_bytes_copied, total_bytes_copied+bytes_read), buffer); - U64 bytes_copied = Min(bytes_read, bytes_written); - bytes_left_to_copy -= bytes_copied; - total_bytes_copied += bytes_copied; - scratch_end(scratch); - if(bytes_copied == 0) - { - break; - } - } - } - os_file_close(src_h); - os_file_close(dst_h); - return result; + B32 result = 0; + OS_Handle src_h = os_file_open(OS_AccessFlag_Read, src); + OS_Handle dst_h = os_file_open(OS_AccessFlag_Write, dst); + if ( !os_handle_match(src_h, os_handle_zero()) && + !os_handle_match(dst_h, os_handle_zero()) ) + { + FileProperties src_props = os_properties_from_file(src_h); + + U64 size = src_props.size; + U64 total_bytes_copied = 0; + U64 bytes_left_to_copy = size; + for (;bytes_left_to_copy > 0;) + { + TempArena scratch = scratch_begin(0, 0); + + U64 buffer_size = Min(bytes_left_to_copy, MB(8)); + U8 *buffer = push_array_no_zero(scratch.arena, U8, buffer_size); + U64 bytes_read = os_file_read (src_h, r1u64(total_bytes_copied, total_bytes_copied+buffer_size), buffer); + U64 bytes_written = os_file_write(dst_h, r1u64(total_bytes_copied, total_bytes_copied+bytes_read), buffer); + U64 bytes_copied = Min(bytes_read, bytes_written); + bytes_left_to_copy -= bytes_copied; + total_bytes_copied += bytes_copied; + + scratch_end(scratch); + if(bytes_copied == 0) { + break; + } + } + } + os_file_close(src_h); + os_file_close(dst_h); + return result; } -internal String8 -os_full_path_from_path(Arena *arena, String8 path) +String8 +os_full_path_from_path(Arena* arena, String8 path) { - Temp scratch = scratch_begin(&arena, 1); - String8 path_copy = push_str8_copy(scratch.arena, path); - char buffer[PATH_MAX] = {0}; - realpath((char *)path_copy.str, buffer); - String8 result = push_str8_copy(arena, str8_cstring(buffer)); - scratch_end(scratch); - return result; + char buffer[PATH_MAX] = {0}; + TempArena scratch = scratch_begin(&arena, 1); { + String8 path_copy = push_str8_copy(scratch.arena, path); + realpath((char *)path_copy.str, buffer); + } + scratch_end(scratch); + String8 result = push_str8_copy(arena, str8_cstring(buffer)); + return result; } -internal B32 +String8 +os_full_path_from_path_alloc(AllocatorInfo ainfo, String8 path) +{ + char buffer[PATH_MAX] = {0}; + TempArena scratch = scratch_begin(0, 0); { + String8 path_copy = push_str8_copy(scratch.arena, path); + realpath((char *)path_copy.str, buffer); + } + scratch_end(scratch); + String8 result = str8_copy(ainfo, str8_cstring(buffer)); + return result; +} + +B32 os_file_path_exists(String8 path) { - Temp scratch = scratch_begin(0, 0); - String8 path_copy = push_str8_copy(scratch.arena, path); - int access_result = access((char *)path_copy.str, F_OK); - B32 result = 0; - if(access_result == 0) - { - result = 1; - } - scratch_end(scratch); - return result; + B32 result = 0; + TempArena scratch = scratch_begin(0, 0); + String8 path_copy = push_str8_copy(scratch.arena, path); + int access_result = access((char *)path_copy.str, F_OK); + if (access_result == 0) { + result = 1; + } + scratch_end(scratch); + return result; } internal FileProperties os_properties_from_file_path(String8 path) { - Temp scratch = scratch_begin(0, 0); - String8 path_copy = push_str8_copy(scratch.arena, path); - struct stat f_stat = {0}; - int stat_result = stat((char *)path_copy.str, &f_stat); - FileProperties props = {0}; - if(stat_result != -1) - { - props = os_lnx_file_properties_from_stat(&f_stat); - } - scratch_end(scratch); - return props; + FileProperties props = {0}; + TempArena scratch = scratch_begin(0, 0); + String8 path_copy = push_str8_copy(scratch.arena, path); + struct stat f_stat = {0}; + int stat_result = stat((char *)path_copy.str, &f_stat); + if (stat_result != -1) { + props = os_lnx_file_properties_from_stat(&f_stat); + } + scratch_end(scratch); + return props; } //- rjf: file maps -internal OS_Handle -os_file_map_open(OS_AccessFlags flags, OS_Handle file) -{ - OS_Handle map = file; - return map; +OS_Handle +os_file_map_open(OS_AccessFlags flags, OS_Handle file) { + OS_Handle map = file; + return map; } -internal void -os_file_map_close(OS_Handle map) -{ - // NOTE(rjf): nothing to do; `map` handles are the same as `file` handles in - // the linux implementation (on Windows they require separate handles) +void +os_file_map_close(OS_Handle map) { + // NOTE(rjf): nothing to do; `map` handles are the same as `file` handles in + // the linux implementation (on Windows they require separate handles) } -internal void * +void* os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) { - if(os_handle_match(map, os_handle_zero())) { return 0; } - int fd = (int)map.u64[0]; - int prot_flags = 0; - if(flags & OS_AccessFlag_Write) { prot_flags |= PROT_WRITE; } - if(flags & OS_AccessFlag_Read) { prot_flags |= PROT_READ; } - int map_flags = MAP_PRIVATE; - void *base = mmap(0, dim_1u64(range), prot_flags, map_flags, fd, range.min); - return base; + if (os_handle_match(map, os_handle_zero())) { return 0; } + int prot_flags = 0; + if (flags & OS_AccessFlag_Write) { prot_flags |= PROT_WRITE; } + if (flags & OS_AccessFlag_Read) { prot_flags |= PROT_READ; } + int fd = (int)map.u64[0]; + int map_flags = MAP_PRIVATE; + void* base = mmap(0, dim_1u64(range), prot_flags, map_flags, fd, range.min); + return base; } -internal void -os_file_map_view_close(OS_Handle map, void *ptr, Rng1U64 range) -{ - munmap(ptr, dim_1u64(range)); +void +os_file_map_view_close(OS_Handle map, void* ptr, Rng1U64 range) { + munmap(ptr, dim_1u64(range)); } //- rjf: directory iteration -internal OS_FileIter * -os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +OS_FileIter* +os_file_iter_begin(Arena* arena, String8 path, OS_FileIterFlags flags) { - OS_FileIter *base_iter = push_array(arena, OS_FileIter, 1); - base_iter->flags = flags; - OS_LNX_FileIter *iter = (OS_LNX_FileIter *)base_iter->memory; - { - String8 path_copy = push_str8_copy(arena, path); - iter->dir = opendir((char *)path_copy.str); - iter->path = path_copy; - } - return base_iter; + OS_FileIter* + base_iter = push_array(arena, OS_FileIter, 1); + base_iter->flags = flags; + + OS_LNX_FileIter* iter = (OS_LNX_FileIter*)base_iter->memory; + { + String8 path_copy = push_str8_copy(arena, path); + iter->dir = opendir((char*)path_copy.str); + iter->path = path_copy; + } + return base_iter; } -internal B32 -os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +B32 +os_file_iter_next(Arena* arena, OS_FileIter* iter, OS_FileInfo* info_out) { - B32 good = 0; - OS_LNX_FileIter *lnx_iter = (OS_LNX_FileIter *)iter->memory; - for(;;) - { - // rjf: get next entry - lnx_iter->dp = readdir(lnx_iter->dir); - good = (lnx_iter->dp != 0); + B32 good = 0; + OS_LNX_FileIter* lnx_iter = (OS_LNX_FileIter*)iter->memory; + for(;;) + { + // rjf: get next entry + lnx_iter->dp = readdir(lnx_iter->dir); + good = (lnx_iter->dp != 0); - // rjf: unpack entry info - struct stat st = {0}; - int stat_result = 0; - if(good) - { - Temp scratch = scratch_begin(&arena, 1); - String8 full_path = push_str8f(scratch.arena, "%S/%s", lnx_iter->path, lnx_iter->dp->d_name); - stat_result = stat((char *)full_path.str, &st); - scratch_end(scratch); - } + // rjf: unpack entry info + struct stat st = {0}; + int stat_result = 0; + if(good) + { + TempArena scratch = scratch_begin(&arena, 1); + String8 full_path = push_str8f(scratch.arena, "%S/%s", lnx_iter->path, lnx_iter->dp->d_name); + stat_result = stat((char *)full_path.str, &st); + scratch_end(scratch); + } - // rjf: determine if filtered - B32 filtered = 0; - if(good) - { - filtered = ((st.st_mode == S_IFDIR && iter->flags & OS_FileIterFlag_SkipFolders) || - (st.st_mode == S_IFREG && iter->flags & OS_FileIterFlag_SkipFiles) || - (lnx_iter->dp->d_name[0] == '.' && lnx_iter->dp->d_name[1] == 0) || - (lnx_iter->dp->d_name[0] == '.' && lnx_iter->dp->d_name[1] == '.' && lnx_iter->dp->d_name[2] == 0)); - } + // rjf: determine if filtered + B32 filtered = 0; + if(good) + { + filtered = ((st.st_mode == S_IFDIR && iter->flags & OS_FileIterFlag_SkipFolders) || + (st.st_mode == S_IFREG && iter->flags & OS_FileIterFlag_SkipFiles) || + (lnx_iter->dp->d_name[0] == '.' && lnx_iter->dp->d_name[1] == 0) || + (lnx_iter->dp->d_name[0] == '.' && lnx_iter->dp->d_name[1] == '.' && lnx_iter->dp->d_name[2] == 0)); + } - // rjf: output & exit, if good & unfiltered - if(good && !filtered) - { - info_out->name = push_str8_copy(arena, str8_cstring(lnx_iter->dp->d_name)); - if(stat_result != -1) - { - info_out->props = os_lnx_file_properties_from_stat(&st); - } - break; - } + // rjf: output & exit, if good & unfiltered + if (good && !filtered) + { + info_out->name = push_str8_copy(arena, str8_cstring(lnx_iter->dp->d_name)); + if (stat_result != -1) { + info_out->props = os_lnx_file_properties_from_stat(&st); + } + break; + } - // rjf: exit if not good - if(!good) - { - break; - } - } - return good; + // rjf: exit if not good + if (!good) + { + break; + } + } + return good; } -internal void -os_file_iter_end(OS_FileIter *iter) -{ - OS_LNX_FileIter *lnx_iter = (OS_LNX_FileIter *)iter->memory; - closedir(lnx_iter->dir); +void +os_file_iter_end(OS_FileIter* iter) { + OS_LNX_FileIter* lnx_iter = (OS_LNX_FileIter*)iter->memory; + closedir(lnx_iter->dir); } //- rjf: directory creation -internal B32 +B32 os_make_directory(String8 path) { - Temp scratch = scratch_begin(0, 0); - B32 result = 0; - String8 path_copy = push_str8_copy(scratch.arena, path); - if(mkdir((char*)path_copy.str, 0777) != -1) - { - result = 1; - } - scratch_end(scratch); - return result; + B32 result = 0; + TempArena scratch = scratch_begin(0, 0); + String8 path_copy = push_str8_copy(scratch.arena, path); + if (mkdir((char*)path_copy.str, 0777) != -1) { + result = 1; + } + scratch_end(scratch); + return result; } //////////////////////////////// //~ rjf: @os_hooks Shared Memory (Implemented Per-OS) -internal OS_Handle +OS_Handle os_shared_memory_alloc(U64 size, String8 name) { - Temp scratch = scratch_begin(0, 0); - String8 name_copy = push_str8_copy(scratch.arena, name); - int id = shm_open((char *)name_copy.str, O_RDWR, 0); - ftruncate(id, size); - OS_Handle result = {(U64)id}; - scratch_end(scratch); - return result; + TempArena scratch = scratch_begin(0, 0); + String8 name_copy = push_str8_copy(scratch.arena, name); + int id = shm_open((char *)name_copy.str, O_RDWR, 0); + ftruncate(id, size); + scratch_end(scratch); + OS_Handle result = {(U64)id}; + return result; } -internal OS_Handle +OS_Handle os_shared_memory_open(String8 name) { - Temp scratch = scratch_begin(0, 0); - String8 name_copy = push_str8_copy(scratch.arena, name); - int id = shm_open((char *)name_copy.str, O_RDWR, 0); - OS_Handle result = {(U64)id}; - scratch_end(scratch); - return result; + TempArena scratch = scratch_begin(0, 0); + String8 name_copy = push_str8_copy(scratch.arena, name); + int id = shm_open((char *)name_copy.str, O_RDWR, 0); + scratch_end(scratch); + OS_Handle result = {(U64)id}; + return result; } -internal void -os_shared_memory_close(OS_Handle handle) -{ - if(os_handle_match(handle, os_handle_zero())){return;} +void +os_shared_memory_close(OS_Handle handle) { + if (os_handle_match(handle, os_handle_zero())) { return; } int id = (int)handle.u64[0]; close(id); } -internal void * -os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) -{ - if(os_handle_match(handle, os_handle_zero())){return 0;} - int id = (int)handle.u64[0]; - void *base = mmap(0, dim_1u64(range), PROT_READ|PROT_WRITE, MAP_SHARED, id, range.min); - return base; +void* +os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) { + if (os_handle_match(handle, os_handle_zero())) { return 0; } + int id = (int)handle.u64[0]; + void* base = mmap(0, dim_1u64(range), PROT_READ|PROT_WRITE, MAP_SHARED, id, range.min); + return base; } -internal void -os_shared_memory_view_close(OS_Handle handle, void *ptr, Rng1U64 range) -{ - if(os_handle_match(handle, os_handle_zero())){return;} - munmap(ptr, dim_1u64(range)); +void +os_shared_memory_view_close(OS_Handle handle, void* ptr, Rng1U64 range) { + if (os_handle_match(handle, os_handle_zero())) { return; } + munmap(ptr, dim_1u64(range)); } //////////////////////////////// //~ rjf: @os_hooks Time (Implemented Per-OS) -internal U64 -os_now_microseconds(void) -{ - struct timespec t; - clock_gettime(CLOCK_MONOTONIC, &t); - U64 result = t.tv_sec*Million(1) + (t.tv_nsec/Thousand(1)); - return result; +U64 +os_now_microseconds(void) { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + U64 result = t.tv_sec * million(1) + (t.tv_nsec / thousand(1)); + return result; } -internal U32 -os_now_unix(void) -{ - time_t t = time(0); - return (U32)t; +U32 +os_now_unix(void) { + time_t t = time(0); + return (U32)t; } -internal DateTime +DateTime os_now_universal_time(void) { - time_t t = 0; - time(&t); - struct tm universal_tm = {0}; - gmtime_r(&t, &universal_tm); - DateTime result = os_lnx_date_time_from_tm(universal_tm, 0); - return result; + time_t t = 0; + time(&t); + struct tm universal_tm = {0}; + gmtime_r(&t, &universal_tm); + DateTime result = os_lnx_date_time_from_tm(universal_tm, 0); + return result; } -internal DateTime -os_universal_time_from_local(DateTime *date_time) +DateTime +os_universal_time_from_local(DateTime* date_time) { - // rjf: local DateTime -> universal time_t - tm local_tm = os_lnx_tm_from_date_time(*date_time); - local_tm.tm_isdst = -1; - time_t universal_t = mktime(&local_tm); + // rjf: local DateTime -> universal time_t + tm local_tm = os_lnx_tm_from_date_time(*date_time); + local_tm.tm_isdst = -1; + time_t universal_t = mktime(&local_tm); - // rjf: universal time_t -> DateTime - tm universal_tm = {0}; - gmtime_r(&universal_t, &universal_tm); - DateTime result = os_lnx_date_time_from_tm(universal_tm, 0); - return result; + // rjf: universal time_t -> DateTime + tm universal_tm = {0}; + gmtime_r(&universal_t, &universal_tm); + DateTime result = os_lnx_date_time_from_tm(universal_tm, 0); + return result; } -internal DateTime -os_local_time_from_universal(DateTime *date_time) +DateTime +os_local_time_from_universal(DateTime* date_time) { - // rjf: universal DateTime -> local time_t - tm universal_tm = os_lnx_tm_from_date_time(*date_time); - universal_tm.tm_isdst = -1; - time_t universal_t = timegm(&universal_tm); - tm local_tm = {0}; - localtime_r(&universal_t, &local_tm); - - // rjf: local tm -> DateTime - DateTime result = os_lnx_date_time_from_tm(local_tm, 0); - return result; + // rjf: universal DateTime -> local time_t + tm universal_tm = os_lnx_tm_from_date_time(*date_time); + universal_tm.tm_isdst = -1; + time_t universal_t = timegm(&universal_tm); + tm local_tm = {0}; + localtime_r(&universal_t, &local_tm); + + // rjf: local tm -> DateTime + DateTime result = os_lnx_date_time_from_tm(local_tm, 0); + return result; } -internal void -os_sleep_milliseconds(U32 msec) -{ - usleep(msec*Thousand(1)); +void +os_sleep_milliseconds(U32 msec) { + usleep(msec * thousand(1)); } //////////////////////////////// //~ rjf: @os_hooks Child Processes (Implemented Per-OS) -internal OS_Handle -os_process_launch(OS_ProcessLaunchParams *params) +OS_Handle +os_process_launch(OS_ProcessLaunchParams* params) { - NotImplemented; + NotImplemented; } -internal B32 +B32 os_process_join(OS_Handle handle, U64 endt_us) { - NotImplemented; + NotImplemented; } -internal void +void os_process_detach(OS_Handle handle) { - NotImplemented; + NotImplemented; } //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle -os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) +OS_Handle +os_thread_launch(OS_ThreadFunctionType* func, void* ptr, void* params) { - OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread); - entity->thread.func = func; - entity->thread.ptr = ptr; - { - pthread_attr_t attr; - pthread_attr_init(&attr); - int pthread_result = pthread_create(&entity->thread.handle, &attr, os_lnx_thread_entry_point, entity); - pthread_attr_destroy(&attr); - if(pthread_result == -1) - { - os_lnx_entity_release(entity); - entity = 0; - } - } - OS_Handle handle = {(U64)entity}; - return handle; + OS_LNX_Entity* entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread); + entity->thread.func = func; + entity->thread.ptr = ptr; + { + pthread_attr_t attr; + pthread_attr_init(&attr); + + int pthread_result = pthread_create(&entity->thread.handle, &attr, os_lnx_thread_entry_point, entity); + pthread_attr_destroy(&attr); + if (pthread_result == -1) + { + os_lnx_entity_release(entity); + entity = 0; + } + } + OS_Handle handle = {(U64)entity}; + return handle; } -internal B32 +B32 os_thread_join(OS_Handle handle, U64 endt_us) { - if(os_handle_match(handle, os_handle_zero())) { return 0; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0]; - int join_result = pthread_join(entity->thread.handle, 0); - B32 result = (join_result == 0); - os_lnx_entity_release(entity); - return result; + if (os_handle_match(handle, os_handle_zero())) { return 0; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)handle.u64[0]; + int join_result = pthread_join(entity->thread.handle, 0); + B32 result = (join_result == 0); + os_lnx_entity_release(entity); + return result; } -internal void -os_thread_detach(OS_Handle handle) -{ - if(os_handle_match(handle, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0]; - os_lnx_entity_release(entity); +void +os_thread_detach(OS_Handle handle) { + if(os_handle_match(handle, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)handle.u64[0]; + os_lnx_entity_release(entity); } //////////////////////////////// @@ -623,479 +629,477 @@ os_thread_detach(OS_Handle handle) //- rjf: mutexes -internal OS_Handle +OS_Handle os_mutex_alloc(void) { - OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Mutex); - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - int init_result = pthread_mutex_init(&entity->mutex_handle, &attr); - pthread_mutexattr_destroy(&attr); - if(init_result == -1) - { - os_lnx_entity_release(entity); - entity = 0; - } - OS_Handle handle = {(U64)entity}; - return handle; + OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Mutex); + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + int init_result = pthread_mutex_init(&entity->mutex_handle, &attr); + pthread_mutexattr_destroy(&attr); + + if (init_result == -1) { + os_lnx_entity_release(entity); + entity = 0; + } + OS_Handle handle = {(U64)entity}; + return handle; } -internal void -os_mutex_release(OS_Handle mutex) -{ - if(os_handle_match(mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; - pthread_mutex_destroy(&entity->mutex_handle); - os_lnx_entity_release(entity); +void +os_mutex_release(OS_Handle mutex) { + if (os_handle_match(mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity *)mutex.u64[0]; + pthread_mutex_destroy(&entity->mutex_handle); + os_lnx_entity_release(entity); } -internal void -os_mutex_take(OS_Handle mutex) -{ - if(os_handle_match(mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; - pthread_mutex_lock(&entity->mutex_handle); +void +os_mutex_take(OS_Handle mutex) { + if (os_handle_match(mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity *)mutex.u64[0]; + pthread_mutex_lock(&entity->mutex_handle); } -internal void -os_mutex_drop(OS_Handle mutex) -{ - if(os_handle_match(mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0]; - pthread_mutex_unlock(&entity->mutex_handle); +void +os_mutex_drop(OS_Handle mutex) { + if (os_handle_match(mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity *)mutex.u64[0]; + pthread_mutex_unlock(&entity->mutex_handle); } //- rjf: reader/writer mutexes -internal OS_Handle +OS_Handle os_rw_mutex_alloc(void) { - OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_RWMutex); - int init_result = pthread_rwlock_init(&entity->rwmutex_handle, 0); - if(init_result == -1) - { - os_lnx_entity_release(entity); - entity = 0; - } - OS_Handle handle = {(U64)entity}; - return handle; + OS_LNX_Entity* entity = os_lnx_entity_alloc(OS_LNX_EntityKind_RWMutex); + int init_result = pthread_rwlock_init(&entity->rwmutex_handle, 0); + if (init_result == -1) { + os_lnx_entity_release(entity); + entity = 0; + } + OS_Handle handle = {(U64)entity}; + return handle; } -internal void -os_rw_mutex_release(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_destroy(&entity->rwmutex_handle); - os_lnx_entity_release(entity); +void +os_rw_mutex_release(OS_Handle rw_mutex) { + if (os_handle_match(rw_mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)rw_mutex.u64[0]; + pthread_rwlock_destroy(&entity->rwmutex_handle); + os_lnx_entity_release(entity); } -internal void -os_rw_mutex_take_r(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_rdlock(&entity->rwmutex_handle); +void +os_rw_mutex_take_r(OS_Handle rw_mutex) { + if (os_handle_match(rw_mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)rw_mutex.u64[0]; + pthread_rwlock_rdlock(&entity->rwmutex_handle); } -internal void -os_rw_mutex_drop_r(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_unlock(&entity->rwmutex_handle); +void +os_rw_mutex_drop_r(OS_Handle rw_mutex) { + if (os_handle_match(rw_mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)rw_mutex.u64[0]; + pthread_rwlock_unlock(&entity->rwmutex_handle); } -internal void -os_rw_mutex_take_w(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_wrlock(&entity->rwmutex_handle); +void +os_rw_mutex_take_w(OS_Handle rw_mutex) { + if (os_handle_match(rw_mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)rw_mutex.u64[0]; + pthread_rwlock_wrlock(&entity->rwmutex_handle); } -internal void -os_rw_mutex_drop_w(OS_Handle rw_mutex) -{ - if(os_handle_match(rw_mutex, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0]; - pthread_rwlock_unlock(&entity->rwmutex_handle); +void +os_rw_mutex_drop_w(OS_Handle rw_mutex) { + if (os_handle_match(rw_mutex, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity*)rw_mutex.u64[0]; + pthread_rwlock_unlock(&entity->rwmutex_handle); } //- rjf: condition variables -internal OS_Handle +OS_Handle os_condition_variable_alloc(void) { - OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_ConditionVariable); - int init_result = pthread_cond_init(&entity->cv.cond_handle, 0); - if(init_result == -1) - { - os_lnx_entity_release(entity); - entity = 0; - } - int init2_result = 0; - if(entity) - { - init2_result = pthread_mutex_init(&entity->cv.rwlock_mutex_handle, 0); - } - if(init2_result == -1) - { - pthread_cond_destroy(&entity->cv.cond_handle); - os_lnx_entity_release(entity); - entity = 0; - } - OS_Handle handle = {(U64)entity}; - return handle; + OS_LNX_Entity* entity = os_lnx_entity_alloc(OS_LNX_EntityKind_ConditionVariable); + int init_result = pthread_cond_init(&entity->cv.cond_handle, 0); + if (init_result == -1) { + os_lnx_entity_release(entity); + entity = 0; + } + int init2_result = 0; + if (entity) { + init2_result = pthread_mutex_init(&entity->cv.rwlock_mutex_handle, 0); + } + if (init2_result == -1) { + pthread_cond_destroy(&entity->cv.cond_handle); + os_lnx_entity_release(entity); + entity = 0; + } + OS_Handle handle = {(U64)entity}; + return handle; } -internal void -os_condition_variable_release(OS_Handle cv) -{ - if(os_handle_match(cv, os_handle_zero())) { return; } - OS_LNX_Entity *entity = (OS_LNX_Entity *)cv.u64[0]; - pthread_cond_destroy(&entity->cv.cond_handle); - pthread_mutex_destroy(&entity->cv.rwlock_mutex_handle); - os_lnx_entity_release(entity); +void +os_condition_variable_release(OS_Handle cv) { + if (os_handle_match(cv, os_handle_zero())) { return; } + OS_LNX_Entity* entity = (OS_LNX_Entity *)cv.u64[0]; + pthread_cond_destroy(&entity->cv.cond_handle); + pthread_mutex_destroy(&entity->cv.rwlock_mutex_handle); + os_lnx_entity_release(entity); } -internal B32 +B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) { - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex, os_handle_zero())) { return 0; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - OS_LNX_Entity *mutex_entity = (OS_LNX_Entity *)mutex.u64[0]; - struct timespec endt_timespec; - endt_timespec.tv_sec = endt_us/Million(1); - endt_timespec.tv_nsec = Thousand(1) * (endt_us - (endt_us/Million(1))*Million(1)); - int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &mutex_entity->mutex_handle, &endt_timespec); - B32 result = (wait_result != ETIMEDOUT); - return result; + if (os_handle_match(cv, os_handle_zero())) { return 0; } + if (os_handle_match(mutex, os_handle_zero())) { return 0; } + + OS_LNX_Entity* cv_entity = (OS_LNX_Entity*)cv.u64[0]; + OS_LNX_Entity* mutex_entity = (OS_LNX_Entity*)mutex.u64[0]; + + struct timespec endt_timespec; + endt_timespec.tv_sec = endt_us / million(1); + endt_timespec.tv_nsec = thousand(1) * (endt_us - (endt_us / million(1)) * million(1)); + + int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &mutex_entity->mutex_handle, &endt_timespec); + B32 result = (wait_result != ETIMEDOUT); + return result; } -internal B32 +B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { - // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack - // this together, but this would probably just be a lot better if we just - // implemented the primitives ourselves with e.g. futexes - // - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0]; - struct timespec endt_timespec; - endt_timespec.tv_sec = endt_us/Million(1); - endt_timespec.tv_nsec = Thousand(1) * (endt_us - (endt_us/Million(1))*Million(1)); - B32 result = 0; - for(;;) - { - pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle); - int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); - if(wait_result != ETIMEDOUT) - { - pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); - pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); - result = 1; - break; - } - pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); - if(wait_result == ETIMEDOUT) - { - break; - } - } - return result; + // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack + // this together, but this would probably just be a lot better if we just + // implemented the primitives ourselves with e.g. futexes + // + if(os_handle_match(cv, os_handle_zero())) { return 0; } + if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; } + + OS_LNX_Entity* cv_entity = (OS_LNX_Entity*)cv.u64[0]; + OS_LNX_Entity* rw_mutex_entity = (OS_LNX_Entity*)mutex_rw.u64[0]; + + struct timespec endt_timespec; + endt_timespec.tv_sec = endt_us / million(1); + endt_timespec.tv_nsec = thousand(1) * (endt_us - (endt_us / million(1)) * million(1)); + + B32 result = 0; + for(;;) + { + pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle); + int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); + if (wait_result != ETIMEDOUT) + { + pthread_rwlock_rdlock(&rw_mutex_entity->rwmutex_handle); + pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); + result = 1; + break; + } + + pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); + if (wait_result == ETIMEDOUT) + { + break; + } + } + return result; } -internal B32 +B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { - // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack - // this together, but this would probably just be a lot better if we just - // implemented the primitives ourselves with e.g. futexes - // - if(os_handle_match(cv, os_handle_zero())) { return 0; } - if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0]; - struct timespec endt_timespec; - endt_timespec.tv_sec = endt_us/Million(1); - endt_timespec.tv_nsec = Thousand(1) * (endt_us - (endt_us/Million(1))*Million(1)); - B32 result = 0; - for(;;) - { - pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle); - int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); - if(wait_result != ETIMEDOUT) - { - pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); - pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); - result = 1; - break; - } - pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); - if(wait_result == ETIMEDOUT) - { - break; - } - } - return result; + // TODO(rjf): because pthread does not supply cv/rw natively, I had to hack + // this together, but this would probably just be a lot better if we just + // implemented the primitives ourselves with e.g. futexes + // + if (os_handle_match(cv, os_handle_zero())) { return 0; } + if (os_handle_match(mutex_rw, os_handle_zero())) { return 0; } + + OS_LNX_Entity* cv_entity = (OS_LNX_Entity*)cv.u64[0]; + OS_LNX_Entity* rw_mutex_entity = (OS_LNX_Entity*)mutex_rw.u64[0]; + + struct timespec endt_timespec; + endt_timespec.tv_sec = endt_us / million(1); + endt_timespec.tv_nsec = thousand(1) * (endt_us - (endt_us / million(1)) * million(1)); + + B32 result = 0; + for(;;) + { + pthread_mutex_lock(&cv_entity->cv.rwlock_mutex_handle); + int wait_result = pthread_cond_timedwait(&cv_entity->cv.cond_handle, &cv_entity->cv.rwlock_mutex_handle, &endt_timespec); + if (wait_result != ETIMEDOUT) + { + pthread_rwlock_wrlock(&rw_mutex_entity->rwmutex_handle); + pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); + result = 1; + break; + } + + pthread_mutex_unlock(&cv_entity->cv.rwlock_mutex_handle); + if (wait_result == ETIMEDOUT) + { + break; + } + } + return result; } -internal void -os_condition_variable_signal(OS_Handle cv) -{ - if(os_handle_match(cv, os_handle_zero())) { return; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - pthread_cond_signal(&cv_entity->cv.cond_handle); +void +os_condition_variable_signal(OS_Handle cv) { + if (os_handle_match(cv, os_handle_zero())) { return; } + OS_LNX_Entity* cv_entity = (OS_LNX_Entity *)cv.u64[0]; + pthread_cond_signal(&cv_entity->cv.cond_handle); } -internal void -os_condition_variable_broadcast(OS_Handle cv) -{ - if(os_handle_match(cv, os_handle_zero())) { return; } - OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0]; - pthread_cond_broadcast(&cv_entity->cv.cond_handle); +void +os_condition_variable_broadcast(OS_Handle cv) { + if (os_handle_match(cv, os_handle_zero())) { return; } + OS_LNX_Entity* cv_entity = (OS_LNX_Entity *)cv.u64[0]; + pthread_cond_broadcast(&cv_entity->cv.cond_handle); } //- rjf: cross-process semaphores -internal OS_Handle +OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { - NotImplemented; + NotImplemented; } -internal void +void os_semaphore_release(OS_Handle semaphore) { - NotImplemented; + NotImplemented; } -internal OS_Handle +OS_Handle os_semaphore_open(String8 name) { - NotImplemented; + NotImplemented; } -internal void +void os_semaphore_close(OS_Handle semaphore) { - NotImplemented; + NotImplemented; } -internal B32 +B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us) { - NotImplemented; + NotImplemented; } -internal void +void os_semaphore_drop(OS_Handle semaphore) { - NotImplemented; + NotImplemented; } //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) -internal OS_Handle -os_library_open(String8 path) -{ - Temp scratch = scratch_begin(0, 0); - char *path_cstr = (char *)push_str8_copy(scratch.arena, path).str; - void *so = dlopen(path_cstr, RTLD_LAZY); - OS_Handle lib = { (U64)so }; - scratch_end(scratch); - return lib; +OS_Handle +os_library_open(String8 path) { + TempArena scratch = scratch_begin(0, 0); + char* path_cstr = (char *)push_str8_copy(scratch.arena, path).str; + void* so = dlopen(path_cstr, RTLD_LAZY); + OS_Handle lib = { (U64)so }; + scratch_end(scratch); + return lib; } -internal VoidProc* -os_library_load_proc(OS_Handle lib, String8 name) -{ - Temp scratch = scratch_begin(0, 0); - void *so = (void *)lib.u64; - char *name_cstr = (char *)push_str8_copy(scratch.arena, name).str; - VoidProc *proc = (VoidProc *)dlsym(so, name_cstr); - scratch_end(scratch); - return proc; +VoidProc* +os_library_load_proc(OS_Handle lib, String8 name) { + TempArena scratch = scratch_begin(0, 0); + void* so = (void*)lib.u64; + char* name_cstr = (char*)push_str8_copy(scratch.arena, name).str; + VoidProc* proc = (VoidProc*)dlsym(so, name_cstr); + scratch_end(scratch); + return proc; } -internal void -os_library_close(OS_Handle lib) -{ - void *so = (void *)lib.u64; - dlclose(so); +void +os_library_close(OS_Handle lib) { + void* so = (void*)lib.u64; + dlclose(so); } //////////////////////////////// //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) -internal void -os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr) +void +os_safe_call(OS_ThreadFunctionType* func, OS_ThreadFunctionType* fail_handler, void* ptr) { - // rjf: push handler to chain - OS_LNX_SafeCallChain chain = {0}; - SLLStackPush(os_lnx_safe_call_chain, &chain); - chain.fail_handler = fail_handler; - chain.ptr = ptr; + // rjf: push handler to chain + OS_LNX_SafeCallChain chain = {0}; + SLLStackPush(os_lnx_safe_call_chain, &chain); + chain.fail_handler = fail_handler; + chain.ptr = ptr; - // rjf: set up sig handler info - struct sigaction new_act = {0}; - new_act.sa_handler = os_lnx_safe_call_sig_handler; - int signals_to_handle[] = - { - SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, - }; - struct sigaction og_act[ArrayCount(signals_to_handle)] = {0}; + // rjf: set up sig handler info + struct sigaction new_act = {0}; + new_act.sa_handler = os_lnx_safe_call_sig_handler; + int signals_to_handle[] = { + SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, + }; + struct sigaction og_act[ArrayCount(signals_to_handle)] = {0}; - // rjf: attach handler info for all signals - for(U32 i = 0; i < ArrayCount(signals_to_handle); i += 1) - { - sigaction(signals_to_handle[i], &new_act, &og_act[i]); - } + // rjf: attach handler info for all signals + for(U32 i = 0; i < ArrayCount(signals_to_handle); i += 1) { + sigaction(signals_to_handle[i], &new_act, &og_act[i]); + } - // rjf: call function - func(ptr); + // rjf: call function + func(ptr); - // rjf: reset handler info for all signals - for(U32 i = 0; i < ArrayCount(signals_to_handle); i += 1) - { - sigaction(signals_to_handle[i], &og_act[i], 0); - } + // rjf: reset handler info for all signals + for (U32 i = 0; i < ArrayCount(signals_to_handle); i += 1) { + sigaction(signals_to_handle[i], &og_act[i], 0); + } } //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +OS_Guid os_make_guid(void) { - U8 random_bytes[16] = {0}; - StaticAssert(sizeof(random_bytes) == sizeof(OS_Guid), os_lnx_guid_size_check); - getrandom(random_bytes, sizeof(random_bytes), 0); - OS_Guid guid = {0}; - MemoryCopy(&guid, random_bytes, sizeof(random_bytes)); - guid.data3 &= 0x0fff; - guid.data3 |= (4 << 12); - guid.data4[0] &= 0x3f; - guid.data4[0] |= 0x80; - return guid; + U8 random_bytes[16] = {0}; + md_static_assert(sizeof(random_bytes) == sizeof(OS_Guid), os_lnx_guid_size_check); + getrandom(random_bytes, sizeof(random_bytes), 0); + + OS_Guid guid = {0}; + memory_copy(&guid, random_bytes, sizeof(random_bytes)); + guid.data3 &= 0x0fff; + guid.data3 |= (4 << 12); + guid.data4[0] &= 0x3f; + guid.data4[0] |= 0x80; + return guid; } //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) +#if BUILD_ENTRY_DEFINING_UNIT || 1 + int main(int argc, char **argv) { - //- rjf: set up OS layer - { - //- rjf: get statically-allocated system/process info - { - OS_SystemInfo *info = &os_lnx_state.system_info; - info->logical_processor_count = (U32)get_nprocs(); - info->page_size = (U64)getpagesize(); - info->large_page_size = MB(2); - info->allocation_granularity = info->page_size; - } - { - OS_ProcessInfo *info = &os_lnx_state.process_info; - info->pid = (U32)getpid(); - } + //- rjf: set up OS layer + { + //- rjf: get statically-allocated system/process info + { + OS_SystemInfo *info = &os_lnx_state.system_info; + info->logical_processor_count = (U32)get_nprocs(); + info->page_size = (U64)getpagesize(); + info->large_page_size = MB(2); + info->allocation_granularity = info->page_size; + } + { + OS_ProcessInfo *info = &os_lnx_state.process_info; + info->pid = (U32)getpid(); + } - //- rjf: set up thread context - local_persist TCTX tctx; - tctx_init_and_equip(&tctx); + //- rjf: set up thread context + local_persist TCTX tctx; + tctx_init_and_equip(&tctx); - //- rjf: set up dynamically allocated state - os_lnx_state.arena = arena_alloc(); - os_lnx_state.entity_arena = arena_alloc(); - pthread_mutex_init(&os_lnx_state.entity_mutex, 0); + //- rjf: set up dynamically allocated state + os_lnx_state.arena = arena_alloc(); + os_lnx_state.entity_arena = arena_alloc(); + pthread_mutex_init(&os_lnx_state.entity_mutex, 0); - //- rjf: grab dynamically allocated system info - { - Temp scratch = scratch_begin(0, 0); - OS_SystemInfo *info = &os_lnx_state.system_info; + //- rjf: grab dynamically allocated system info + { + TempArena scratch = scratch_begin(0, 0); + OS_SystemInfo* info = &os_lnx_state.system_info; - // rjf: get machine name - B32 got_final_result = 0; - U8 *buffer = 0; - int size = 0; - for(S64 cap = 4096, r = 0; r < 4; cap *= 2, r += 1) - { - scratch_end(scratch); - buffer = push_array_no_zero(scratch.arena, U8, cap); - size = gethostname((char*)buffer, cap); - if(size < cap) - { - got_final_result = 1; - break; - } - } + // rjf: get machine name + B32 got_final_result = 0; + U8* buffer = 0; + int size = 0; + for (S64 cap = 4096, r = 0; r < 4; cap *= 2, r += 1) + { + scratch_end(scratch); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = gethostname((char*)buffer, cap); + if (size < cap) + { + got_final_result = 1; + break; + } + } - // rjf: save name to info - if(got_final_result && size > 0) - { - info->machine_name.size = size; - info->machine_name.str = push_array_no_zero(os_lnx_state.arena, U8, info->machine_name.size + 1); - MemoryCopy(info->machine_name.str, buffer, info->machine_name.size); - info->machine_name.str[info->machine_name.size] = 0; - } + // rjf: save name to info + if (got_final_result && size > 0) + { + info->machine_name.size = size; + info->machine_name.str = push_array_no_zero(os_lnx_state.arena, U8, info->machine_name.size + 1); + MemoryCopy(info->machine_name.str, buffer, info->machine_name.size); + info->machine_name.str[info->machine_name.size] = 0; + } - scratch_end(scratch); - } + scratch_end(scratch); + } - //- rjf: grab dynamically allocated process info - { - Temp scratch = scratch_begin(0, 0); - OS_ProcessInfo *info = &os_lnx_state.process_info; + //- rjf: grab dynamically allocated process info + { + TempArena scratch = scratch_begin(0, 0); + OS_ProcessInfo* info = &os_lnx_state.process_info; - // rjf: grab binary path - { - // rjf: get self string - B32 got_final_result = 0; - U8 *buffer = 0; - int size = 0; - for(S64 cap = PATH_MAX, r = 0; r < 4; cap *= 2, r += 1) - { - scratch_end(scratch); - buffer = push_array_no_zero(scratch.arena, U8, cap); - size = readlink("/proc/self/exe", (char*)buffer, cap); - if(size < cap) - { - got_final_result = 1; - break; - } - } - - // rjf: save - if(got_final_result && size > 0) - { - String8 full_name = str8(buffer, size); - String8 name_chopped = str8_chop_last_slash(full_name); - info->binary_path = push_str8_copy(os_lnx_state.arena, name_chopped); - } - } + // rjf: grab binary path + { + // rjf: get self string + B32 got_final_result = 0; + U8* buffer = 0; + int size = 0; + for (S64 cap = PATH_MAX, r = 0; r < 4; cap *= 2, r += 1) + { + scratch_end(scratch); + buffer = push_array_no_zero(scratch.arena, U8, cap); + size = readlink("/proc/self/exe", (char*)buffer, cap); + if (size < cap) + { + got_final_result = 1; + break; + } + } + + // rjf: save + if (got_final_result && size > 0) + { + String8 full_name = str8(buffer, size); + String8 name_chopped = str8_chop_last_slash(full_name); + info->binary_path = push_str8_copy(os_lnx_state.arena, name_chopped); + } + } - // rjf: grab initial directory - { - info->initial_path = os_get_current_path(os_lnx_state.arena); - } + // rjf: grab initial directory + { + info->initial_path = os_get_current_path(os_lnx_state.arena); + } - // rjf: grab home directory - { - char *home = getenv("HOME"); - info->user_program_data_path = str8_cstring(home); - } + // rjf: grab home directory + { + char *home = getenv("HOME"); + info->user_program_data_path = str8_cstring(home); + } - scratch_end(scratch); - } - } + scratch_end(scratch); + } + } - //- rjf: call into "real" entry point - main_thread_base_entry_point(entry_point, argv, (U64)argc); + //- rjf: call into "real" entry point + main_thread_base_entry_point(entry_point, argv, (U64)argc); } + +// BUILD_ENTRY_POINT +#endif diff --git a/code/os/linux/os_linux.h b/code/os/linux/os_linux.h index 991ca74..db90212 100644 --- a/code/os/linux/os_linux.h +++ b/code/os/linux/os_linux.h @@ -191,23 +191,30 @@ os_lnx_safe_call_sig_handler(int x) { //~ rjf: Entities MD_API OS_LNX_Entity* os_lnx_entity_alloc (OS_LNX_EntityKind kind); -MD_API void os_lnx_entity_release(OS_LNX_Entity* entity); +MD_API void os_lnx_entity_release(OS_LNX_Entity* entity); //////////////////////////////// //~ rjf: Thread Entry Point -void* os_lnx_thread_entry_point(void* ptr); +MD_API void* os_lnx_thread_entry_point(void* ptr); //////////////////////////////// //~ rjf: @os_hooks System/Process Info (Implemented Per-OS) -String8 +inline String8 os_get_current_path(Arena* arena) { char* cwdir = getcwd(0, 0); String8 string = push_str8_copy(arena, str8_cstring(cwdir)); return string; } +inline String8 +os_get_current_path(AllocatorInfo ainfo) { + char* cwdir = getcwd(0, 0); + String8 string = str8_copy(ainfo, str8_cstring(cwdir)); + return string; +} + //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -236,10 +243,3 @@ os_tid(void) { #endif return result; } - -//////////////////////////////// -//~ rjf: @os_hooks Aborting (Implemented Per-OS) - -inline void os_abort(S32 exit_code) { exit(exit_code); } - - diff --git a/code/os/os.h b/code/os/os.h index c37cc2a..82c2fa1 100644 --- a/code/os/os.h +++ b/code/os/os.h @@ -231,6 +231,17 @@ os_string_list_from_argcv(Arena* arena, int argc, char** argv) { return result; } +inline String8List +os_string_list_from_argcv(AllocatorInfo ainfo, int argc, char** argv) { + String8List result = {0}; + for(int i = 0; i < argc; i += 1) + { + String8 str = str8_cstring(argv[i]); + str8_list_alloc(ainfo, &result, str); + } + return result; +} + //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, Implemented Once) @@ -285,173 +296,195 @@ inline S64 os_file_id_compare(OS_FileID a, OS_FileID b) { S64 cmp = memory_compa 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; + 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; +} + +inline String8 +os_string_from_guid(AllocatorInfo ainfo, OS_Guid guid) { + String8 result = str8f(ainfo, + "%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) -internal OS_SystemInfo* os_get_system_info(void); -internal OS_ProcessInfo* os_get_process_info(void); -internal String8 os_get_current_path(Arena *arena); +MD_API OS_SystemInfo* os_get_system_info (void); +MD_API OS_ProcessInfo* os_get_process_info(void); + +String8 os_get_current_path(Arena* arena); //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) //- rjf: basic -internal void *os_reserve(U64 size); -internal B32 os_commit(void *ptr, U64 size); -internal void os_decommit(void *ptr, U64 size); -internal void os_release(void *ptr, U64 size); +void* os_reserve ( U64 size); +B32 os_commit (void* ptr, U64 size); +void os_decommit(void* ptr, U64 size); +void os_release (void* ptr, U64 size); //- rjf: large pages -internal void *os_reserve_large(U64 size); -internal B32 os_commit_large(void *ptr, U64 size); +void* os_reserve_large( U64 size); +B32 os_commit_large (void* ptr, U64 size); //////////////////////////////// //~ rjf: @os_hooks Thread Info (Implemented Per-OS) -internal U32 os_tid(void); -internal void os_set_thread_name(String8 string); + U32 os_tid (void); +MD_API void os_set_thread_name(String8 string); //////////////////////////////// //~ rjf: @os_hooks Aborting (Implemented Per-OS) -internal void os_abort(S32 exit_code); +MD_API void os_abort(S32 exit_code); //////////////////////////////// //~ rjf: @os_hooks File System (Implemented Per-OS) //- rjf: files -internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); -internal void os_file_close(OS_Handle file); -internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data); -internal U64 os_file_write(OS_Handle file, Rng1U64 rng, void *data); -internal B32 os_file_set_times(OS_Handle file, DateTime time); -internal FileProperties os_properties_from_file(OS_Handle file); -internal OS_FileID os_id_from_file(OS_Handle file); -internal B32 os_delete_file_at_path(String8 path); -internal B32 os_copy_file_path(String8 dst, String8 src); -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); +MD_API OS_Handle os_file_open (OS_AccessFlags flags, String8 path); +MD_API void os_file_close (OS_Handle file); +MD_API U64 os_file_read (OS_Handle file, Rng1U64 rng, void *out_data); +MD_API U64 os_file_write (OS_Handle file, Rng1U64 rng, void *data); +MD_API B32 os_file_set_times (OS_Handle file, DateTime time); +MD_API FileProperties os_properties_from_file (OS_Handle file); +MD_API OS_FileID os_id_from_file (OS_Handle file); +MD_API B32 os_delete_file_at_path (String8 path); +MD_API B32 os_copy_file_path (String8 dst, String8 src); +MD_API String8 os_full_path_from_path (Arena* arena, String8 path); +MD_API B32 os_file_path_exists (String8 path); +MD_API 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_close(OS_Handle map, void *ptr, Rng1U64 range); +MD_API OS_Handle os_file_map_open (OS_AccessFlags flags, OS_Handle file); +MD_API void os_file_map_close (OS_Handle map); +MD_API void* os_file_map_view_open (OS_Handle map, OS_AccessFlags flags, Rng1U64 range); +MD_API 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 B32 os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out); -internal void os_file_iter_end(OS_FileIter *iter); +MD_API OS_FileIter* os_file_iter_begin(Arena* arena, String8 path, OS_FileIterFlags flags); +MD_API B32 os_file_iter_next (Arena* arena, OS_FileIter* iter, OS_FileInfo* info_out); +MD_API void os_file_iter_end ( OS_FileIter* iter); //- rjf: directory creation -internal B32 os_make_directory(String8 path); +MD_API B32 os_make_directory(String8 path); //////////////////////////////// //~ rjf: @os_hooks Shared Memory (Implemented Per-OS) -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_close(OS_Handle handle, void *ptr, Rng1U64 range); +MD_API OS_Handle os_shared_memory_alloc (U64 size, String8 name); +MD_API OS_Handle os_shared_memory_open (String8 name); +MD_API void os_shared_memory_close (OS_Handle handle); +MD_API void* os_shared_memory_view_open (OS_Handle handle, Rng1U64 range); +MD_API void os_shared_memory_view_close(OS_Handle handle, void* ptr, Rng1U64 range); //////////////////////////////// //~ rjf: @os_hooks Time (Implemented Per-OS) -internal U64 os_now_microseconds(void); -internal U32 os_now_unix(void); -internal DateTime os_now_universal_time(void); -internal DateTime os_universal_time_from_local(DateTime *local_time); -internal DateTime os_local_time_from_universal(DateTime *universal_time); -internal void os_sleep_milliseconds(U32 msec); +MD_API U64 os_now_microseconds (void); +MD_API U32 os_now_unix (void); +MD_API DateTime os_now_universal_time (void); +MD_API DateTime os_universal_time_from_local(DateTime* local_time); +MD_API DateTime os_local_time_from_universal(DateTime* universal_time); +MD_API void os_sleep_milliseconds (U32 msec); //////////////////////////////// //~ rjf: @os_hooks Child Processes (Implemented Per-OS) -internal OS_Handle os_process_launch(OS_ProcessLaunchParams *params); -internal B32 os_process_join(OS_Handle handle, U64 endt_us); -internal void os_process_detach(OS_Handle handle); +MD_API OS_Handle os_process_launch(OS_ProcessLaunchParams* params); +MD_API B32 os_process_join (OS_Handle handle, U64 endt_us); +MD_API void os_process_detach(OS_Handle handle); //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params); -internal B32 os_thread_join(OS_Handle handle, U64 endt_us); -internal void os_thread_detach(OS_Handle handle); +MD_API OS_Handle os_thread_launch(OS_ThreadFunctionType* func, void* ptr, void* params); +MD_API B32 os_thread_join (OS_Handle handle, U64 endt_us); +MD_API void os_thread_detach(OS_Handle handle); //////////////////////////////// //~ rjf: @os_hooks Synchronization Primitives (Implemented Per-OS) //- rjf: recursive mutexes -internal OS_Handle os_mutex_alloc(void); -internal void os_mutex_release(OS_Handle mutex); -internal void os_mutex_take(OS_Handle mutex); -internal void os_mutex_drop(OS_Handle mutex); +MD_API OS_Handle os_mutex_alloc (void); +MD_API void os_mutex_release(OS_Handle mutex); +MD_API void os_mutex_take (OS_Handle mutex); +MD_API void os_mutex_drop (OS_Handle mutex); //- rjf: reader/writer mutexes -internal OS_Handle os_rw_mutex_alloc(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); -internal void os_rw_mutex_take_w(OS_Handle mutex); -internal void os_rw_mutex_drop_w(OS_Handle mutex); +MD_API OS_Handle os_rw_mutex_alloc(void); +MD_API void os_rw_mutex_release(OS_Handle rw_mutex); +MD_API void os_rw_mutex_take_r(OS_Handle mutex); +MD_API void os_rw_mutex_drop_r(OS_Handle mutex); +MD_API void os_rw_mutex_take_w(OS_Handle mutex); +MD_API void os_rw_mutex_drop_w(OS_Handle mutex); //- rjf: condition variables -internal OS_Handle os_condition_variable_alloc(void); -internal void os_condition_variable_release(OS_Handle cv); +MD_API OS_Handle os_condition_variable_alloc (void); +MD_API void os_condition_variable_release(OS_Handle cv); // 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 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); -internal void os_condition_variable_signal(OS_Handle cv); -internal void os_condition_variable_broadcast(OS_Handle cv); +MD_API B32 os_condition_variable_wait (OS_Handle cv, OS_Handle mutex, U64 endt_us); +MD_API B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +MD_API B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us); +MD_API void os_condition_variable_signal (OS_Handle cv); +MD_API 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); +MD_API OS_Handle os_semaphore_alloc (U32 initial_count, U32 max_count, String8 name); +MD_API void os_semaphore_release(OS_Handle semaphore); +MD_API OS_Handle os_semaphore_open (String8 name); +MD_API void os_semaphore_close (OS_Handle semaphore); +MD_API B32 os_semaphore_take (OS_Handle semaphore, U64 endt_us); +MD_API void os_semaphore_drop (OS_Handle semaphore); //- rjf: scope macros -#define OS_MutexScope(mutex) DeferLoop(os_mutex_take(mutex), os_mutex_drop(mutex)) -#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)) -#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))) +#define OS_MutexScope(mutex) defer_loop( os_mutex_take (mutex), os_mutex_drop (mutex)) +#define OS_MutexScopeR(mutex) defer_loop( os_rw_mutex_take_r(mutex), os_rw_mutex_drop_r(mutex)) +#define OS_MutexScopeW(mutex) defer_loop( os_rw_mutex_take_w(mutex), os_rw_mutex_drop_w(mutex)) +#define OS_MutexScopeRWPromote(mutex) defer_loop((os_rw_mutex_drop_r(mutex), os_rw_mutex_take_w(mutex)), (os_rw_mutex_drop_w(mutex), os_rw_mutex_take_r(mutex))) //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) -internal OS_Handle os_library_open(String8 path); -internal void os_library_close(OS_Handle lib); -internal VoidProc *os_library_load_proc(OS_Handle lib, String8 name); +MD_API OS_Handle os_library_open (String8 path); +MD_API void os_library_close (OS_Handle lib); +MD_API VoidProc* os_library_load_proc(OS_Handle lib, String8 name); //////////////////////////////// //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) -internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr); +MD_API 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); +MD_API OS_Guid os_make_guid(void); //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) @@ -461,5 +494,5 @@ internal OS_Guid os_make_guid(void); // into the standard codebase program entry points, named "entry_point". #if BUILD_ENTRY_DEFINING_UNIT -internal void entry_point(CmdLine *cmdline); +void entry_point(CmdLine* cmdline); #endif diff --git a/code/os/win32/os_win32.c b/code/os/win32/os_win32.c index 4f40e5e..719f176 100644 --- a/code/os/win32/os_win32.c +++ b/code/os/win32/os_win32.c @@ -152,6 +152,11 @@ os_set_thread_name(String8 name) scratch_end(scratch); } +//////////////////////////////// +//~ rjf: @os_hooks Aborting (Implemented Per-OS) + +void os_abort(S32 exit_code) { ExitProcess(exit_code); } + //////////////////////////////// //~ rjf: @os_hooks File System (Implemented Per-OS) @@ -203,7 +208,7 @@ os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) // rjf: clamp range by file size U64 size = 0; GetFileSizeEx(handle, (LARGE_INTEGER *)&size); - Rng1U64 rng_clamped = r1u64(ClampTop(rng.min, size), ClampTop(rng.max, size)); + Rng1U64 rng_clamped = r1u64(clamp_top(rng.min, size), clamp_top(rng.max, size)); U64 total_read_size = 0; // rjf: read loop @@ -281,558 +286,566 @@ os_file_set_times(OS_Handle file, DateTime time) return result; } -internal FileProperties +FileProperties os_properties_from_file(OS_Handle file) { - if(os_handle_match(file, os_handle_zero())) { FileProperties r = {0}; return r; } - FileProperties props = {0}; - HANDLE handle = (HANDLE)file.u64[0]; - BY_HANDLE_FILE_INFORMATION info; - BOOL info_good = GetFileInformationByHandle(handle, &info); - if(info_good) - { - U32 size_lo = info.nFileSizeLow; - U32 size_hi = info.nFileSizeHigh; - props.size = (U64)size_lo | (((U64)size_hi)<<32); - os_w32_dense_time_from_file_time(&props.modified, &info.ftLastWriteTime); - os_w32_dense_time_from_file_time(&props.created, &info.ftCreationTime); - props.flags = os_w32_file_property_flags_from_dwFileAttributes(info.dwFileAttributes); - } - return props; + if (os_handle_match(file, os_handle_zero())) { FileProperties r = {0}; return r; } + FileProperties props = {0}; + + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL info_good = GetFileInformationByHandle(handle, &info); + if (info_good) + { + U32 size_lo = info.nFileSizeLow; + U32 size_hi = info.nFileSizeHigh; + props.size = (U64)size_lo | (((U64)size_hi)<<32); + os_w32_dense_time_from_file_time(&props.modified, &info.ftLastWriteTime); + os_w32_dense_time_from_file_time(&props.created, &info.ftCreationTime); + props.flags = os_w32_file_property_flags_from_dwFileAttributes(info.dwFileAttributes); + } + return props; } -internal OS_FileID +OS_FileID os_id_from_file(OS_Handle file) { if(os_handle_match(file, os_handle_zero())) { OS_FileID r = {0}; return r; } OS_FileID result = {0}; - HANDLE handle = (HANDLE)file.u64[0]; - BY_HANDLE_FILE_INFORMATION info; - BOOL is_ok = GetFileInformationByHandle(handle, &info); - if(is_ok) - { - result.v[0] = info.dwVolumeSerialNumber; - result.v[1] = info.nFileIndexLow; - result.v[2] = info.nFileIndexHigh; - } - return result; + + HANDLE handle = (HANDLE)file.u64[0]; + BY_HANDLE_FILE_INFORMATION info; + BOOL is_ok = GetFileInformationByHandle(handle, &info); + if (is_ok) + { + result.v[0] = info.dwVolumeSerialNumber; + result.v[1] = info.nFileIndexLow; + result.v[2] = info.nFileIndexHigh; + } + return result; } -internal B32 +B32 os_delete_file_at_path(String8 path) { - TempArena scratch = scratch_begin(0, 0); - String16 path16 = str16_from_8(scratch.arena, path); - B32 result = DeleteFileW((WCHAR*)path16.str); - scratch_end(scratch); - return result; + TempArena scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + B32 result = DeleteFileW((WCHAR*)path16.str); + scratch_end(scratch); + return result; } -internal B32 +B32 os_copy_file_path(String8 dst, String8 src) { - 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); - scratch_end(scratch); - return result; + 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); + scratch_end(scratch); + return result; } -internal String8 -os_full_path_from_path(Arena *arena, String8 path) +String8 +os_full_path_from_path(Arena* arena, String8 path) { 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); - DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, (WCHAR*)buffer, NULL); - String8 full_path = str8_from_16(arena, str16(buffer, path16_size)); - scratch_end(scratch); - return full_path; + 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); + DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, (WCHAR*)buffer, NULL); + String8 full_path = str8_from_16(arena, str16(buffer, path16_size)); + scratch_end(scratch); + return full_path; } -internal B32 +B32 os_file_path_exists(String8 path) { - 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); - scratch_end(scratch); - return exists; + 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); + scratch_end(scratch); + return exists; } -internal FileProperties +FileProperties os_properties_from_file_path(String8 path) { - WIN32_FIND_DATAW find_data = {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}; - if(handle != INVALID_HANDLE_VALUE) - { - props.size = Compose64Bit(find_data.nFileSizeHigh, find_data.nFileSizeLow); - os_w32_dense_time_from_file_time(&props.created, &find_data.ftCreationTime); - os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); - props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); - } - FindClose(handle); - scratch_end(scratch); - return props; + FileProperties props = {0}; + WIN32_FIND_DATAW find_data = {0}; + TempArena scratch = scratch_begin(0, 0); + String16 path16 = str16_from_8(scratch.arena, path); + HANDLE handle = FindFirstFileW((WCHAR *)path16.str, &find_data); + if (handle != INVALID_HANDLE_VALUE) + { + props.size = compose_64bit(find_data.nFileSizeHigh, find_data.nFileSizeLow); + os_w32_dense_time_from_file_time(&props.created, &find_data.ftCreationTime); + os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); + props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); + } + FindClose(handle); + scratch_end(scratch); + return props; } //- rjf: file maps -internal OS_Handle +OS_Handle os_file_map_open(OS_AccessFlags flags, OS_Handle file) { - OS_Handle map = {0}; - { - HANDLE file_handle = (HANDLE)file.u64[0]; - DWORD protect_flags = 0; - { - switch(flags) - { - default:{}break; - case OS_AccessFlag_Read: - {protect_flags = PAGE_READONLY;}break; - case OS_AccessFlag_Write: - case OS_AccessFlag_Read|OS_AccessFlag_Write: - {protect_flags = PAGE_READWRITE;}break; - case OS_AccessFlag_Execute: - case OS_AccessFlag_Read|OS_AccessFlag_Execute: - {protect_flags = PAGE_EXECUTE_READ;}break; - case OS_AccessFlag_Execute|OS_AccessFlag_Write|OS_AccessFlag_Read: - case OS_AccessFlag_Execute|OS_AccessFlag_Write: - {protect_flags = PAGE_EXECUTE_READWRITE;}break; - } - } - HANDLE map_handle = CreateFileMappingA(file_handle, 0, protect_flags, 0, 0, 0); - map.u64[0] = (U64)map_handle; - } - return map; + OS_Handle map = {0}; + { + HANDLE file_handle = (HANDLE)file.u64[0]; + DWORD protect_flags = 0; + { + switch(flags) + { + default: {} break; + + case OS_AccessFlag_Read: + { protect_flags = PAGE_READONLY; } + break; + + case OS_AccessFlag_Write: + case OS_AccessFlag_Read|OS_AccessFlag_Write: + { protect_flags = PAGE_READWRITE; } + break; + + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read|OS_AccessFlag_Execute: + { protect_flags = PAGE_EXECUTE_READ; } + break; + + case OS_AccessFlag_Execute|OS_AccessFlag_Write|OS_AccessFlag_Read: + case OS_AccessFlag_Execute|OS_AccessFlag_Write: + { protect_flags = PAGE_EXECUTE_READWRITE; } + break; + } + } + HANDLE map_handle = CreateFileMappingA(file_handle, 0, protect_flags, 0, 0, 0); + map.u64[0] = (U64)map_handle; + } + return map; } -internal void +void os_file_map_close(OS_Handle map) { - HANDLE handle = (HANDLE)map.u64[0]; - BOOL result = CloseHandle(handle); - (void)result; + HANDLE handle = (HANDLE)map.u64[0]; + BOOL result = CloseHandle(handle); + (void)result; } -internal void * +void* os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) { - HANDLE handle = (HANDLE)map.u64[0]; - U32 off_lo = (U32)((range.min&0x00000000ffffffffull)>>0); - U32 off_hi = (U32)((range.min&0xffffffff00000000ull)>>32); - U64 size = dim_1u64(range); - DWORD access_flags = 0; - { - switch(flags) - { - default:{}break; - case OS_AccessFlag_Read: - { - access_flags = FILE_MAP_READ; - }break; - case OS_AccessFlag_Write: - { - access_flags = FILE_MAP_WRITE; - }break; - case OS_AccessFlag_Read|OS_AccessFlag_Write: - { - access_flags = FILE_MAP_ALL_ACCESS; - }break; - case OS_AccessFlag_Execute: - case OS_AccessFlag_Read|OS_AccessFlag_Execute: - case OS_AccessFlag_Write|OS_AccessFlag_Execute: - case OS_AccessFlag_Read|OS_AccessFlag_Write|OS_AccessFlag_Execute: - { - access_flags = FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE; - }break; - } - } - void *result = MapViewOfFile(handle, access_flags, off_hi, off_lo, size); - return result; + HANDLE handle = (HANDLE)map.u64[0]; + U32 off_lo = (U32)((range.min&0x00000000ffffffffull)>>0); + U32 off_hi = (U32)((range.min&0xffffffff00000000ull)>>32); + U64 size = dim_1u64(range); + DWORD access_flags = 0; + { + switch(flags) + { + default:{}break; + case OS_AccessFlag_Read: { access_flags = FILE_MAP_READ; } break; + case OS_AccessFlag_Write: { access_flags = FILE_MAP_WRITE; } break; + case OS_AccessFlag_Read | OS_AccessFlag_Write: { access_flags = FILE_MAP_ALL_ACCESS; } break; + + case OS_AccessFlag_Execute: + case OS_AccessFlag_Read | OS_AccessFlag_Execute: + case OS_AccessFlag_Write| OS_AccessFlag_Execute: + case OS_AccessFlag_Read | OS_AccessFlag_Write | OS_AccessFlag_Execute: + { + access_flags = FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE; + } + break; + } + } + void* result = MapViewOfFile(handle, access_flags, off_hi, off_lo, size); + return result; } -internal void -os_file_map_view_close(OS_Handle map, void *ptr, Rng1U64 range) -{ - BOOL result = UnmapViewOfFile(ptr); - (void)result; +void +os_file_map_view_close(OS_Handle map, void* ptr, Rng1U64 range) { + BOOL result = UnmapViewOfFile(ptr); + (void)result; } //- rjf: directory iteration -internal OS_FileIter * -os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) +OS_FileIter* +os_file_iter_begin(Arena* arena, String8 path, OS_FileIterFlags flags) { 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); - iter->flags = flags; - OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - if(path.size == 0) - { - w32_iter->is_volume_iter = 1; - WCHAR buffer[512] = {0}; - DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); - String8List drive_strings = {0}; - for(U64 off = 0; off < (U64)length;) - { - String16 next_drive_string_16 = str16_cstring((U16 *)buffer+off); - off += next_drive_string_16.size+1; - String8 next_drive_string = str8_from_16(arena, next_drive_string_16); - next_drive_string = str8_chop_last_slash(next_drive_string); - str8_list_push(scratch.arena, &drive_strings, next_drive_string); - } - w32_iter->drive_strings = str8_array_from_list(arena, &drive_strings); - w32_iter->drive_strings_iter_idx = 0; - } - else - { - w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); - } - scratch_end(scratch); - return iter; + + 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); + iter->flags = flags; + + OS_W32_FileIter* w32_iter = (OS_W32_FileIter*)iter->memory; + if (path.size == 0) + { + w32_iter->is_volume_iter = 1; + + WCHAR buffer[512] = {0}; + DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); + + String8List drive_strings = {0}; + for(U64 off = 0; off < (U64)length;) + { + String16 next_drive_string_16 = str16_cstring((U16*)buffer + off); + off += next_drive_string_16.size + 1; + String8 next_drive_string = str8_from_16(arena, next_drive_string_16); + next_drive_string = str8_chop_last_slash(next_drive_string); + str8_list_push(scratch.arena, &drive_strings, next_drive_string); + } + w32_iter->drive_strings = str8_array_from_list(arena, &drive_strings); + w32_iter->drive_strings_iter_idx = 0; + } + else + { + w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); + } + scratch_end(scratch); + return iter; } -internal B32 -os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) +B32 +os_file_iter_next(Arena* arena, OS_FileIter* iter, OS_FileInfo* info_out) { - B32 result = 0; - OS_FileIterFlags flags = iter->flags; - OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - switch(w32_iter->is_volume_iter) - { - //- rjf: file iteration - default: - case 0: - { - if (!(flags & OS_FileIterFlag_Done) && w32_iter->handle != INVALID_HANDLE_VALUE) - { - do - { - // check is usable - B32 usable_file = 1; - - WCHAR *file_name = w32_iter->find_data.cFileName; - DWORD attributes = w32_iter->find_data.dwFileAttributes; - if (file_name[0] == '.'){ - if (flags & OS_FileIterFlag_SkipHiddenFiles){ - usable_file = 0; - } - else if (file_name[1] == 0){ - usable_file = 0; - } - else if (file_name[1] == '.' && file_name[2] == 0){ - usable_file = 0; - } - } - if (attributes & FILE_ATTRIBUTE_DIRECTORY){ - if (flags & OS_FileIterFlag_SkipFolders){ - usable_file = 0; - } - } - else{ - if (flags & OS_FileIterFlag_SkipFiles){ - usable_file = 0; - } - } - - // emit if usable - if (usable_file){ - info_out->name = str8_from_16(arena, str16_cstring((U16*)file_name)); - info_out->props.size = (U64)w32_iter->find_data.nFileSizeLow | (((U64)w32_iter->find_data.nFileSizeHigh)<<32); - os_w32_dense_time_from_file_time(&info_out->props.created, &w32_iter->find_data.ftCreationTime); - os_w32_dense_time_from_file_time(&info_out->props.modified, &w32_iter->find_data.ftLastWriteTime); - info_out->props.flags = os_w32_file_property_flags_from_dwFileAttributes(attributes); - result = 1; - if (!FindNextFileW(w32_iter->handle, &w32_iter->find_data)){ - iter->flags |= OS_FileIterFlag_Done; - } - break; - } - }while(FindNextFileW(w32_iter->handle, &w32_iter->find_data)); - } - }break; - - //- rjf: volume iteration - case 1: - { - result = w32_iter->drive_strings_iter_idx < w32_iter->drive_strings.count; - if(result != 0) - { - MemoryZeroStruct(info_out); - info_out->name = w32_iter->drive_strings.v[w32_iter->drive_strings_iter_idx]; - info_out->props.flags |= FilePropertyFlag_IsFolder; - w32_iter->drive_strings_iter_idx += 1; - } - }break; - } - if(!result) - { - iter->flags |= OS_FileIterFlag_Done; - } - return result; + B32 result = 0; + + OS_FileIterFlags flags = iter->flags; + OS_W32_FileIter* w32_iter = (OS_W32_FileIter*)iter->memory; + switch (w32_iter->is_volume_iter) + { + //- rjf: file iteration + default: + + case 0: + { + if (!(flags & OS_FileIterFlag_Done) && w32_iter->handle != INVALID_HANDLE_VALUE) + { + do + { + // check is usable + B32 usable_file = 1; + + WCHAR* file_name = w32_iter->find_data.cFileName; + DWORD attributes = w32_iter->find_data.dwFileAttributes; + if (file_name[0] == '.') + { + if (flags & OS_FileIterFlag_SkipHiddenFiles) { + usable_file = 0; + } + else if (file_name[1] == 0){ + usable_file = 0; + } + else if (file_name[1] == '.' && file_name[2] == 0) { + usable_file = 0; + } + } + if (attributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (flags & OS_FileIterFlag_SkipFolders) { + usable_file = 0; + } + } + else + { + if (flags & OS_FileIterFlag_SkipFiles) { + usable_file = 0; + } + } + + // emit if usable + if (usable_file) + { + info_out->name = str8_from_16(arena, str16_cstring((U16*)file_name)); + info_out->props.size = (U64)w32_iter->find_data.nFileSizeLow | (((U64)w32_iter->find_data.nFileSizeHigh) << 32); + os_w32_dense_time_from_file_time(&info_out->props.created, &w32_iter->find_data.ftCreationTime); + os_w32_dense_time_from_file_time(&info_out->props.modified, &w32_iter->find_data.ftLastWriteTime); + info_out->props.flags = os_w32_file_property_flags_from_dwFileAttributes(attributes); + + result = 1; + if (!FindNextFileW(w32_iter->handle, &w32_iter->find_data)) { + iter->flags |= OS_FileIterFlag_Done; + } + + break; + } + } + while (FindNextFileW(w32_iter->handle, &w32_iter->find_data)); + } + } + break; + + //- rjf: volume iteration + case 1: + { + result = w32_iter->drive_strings_iter_idx < w32_iter->drive_strings.count; + if (result != 0) + { + memory_zero_struct(info_out); + info_out->name = w32_iter->drive_strings.v[w32_iter->drive_strings_iter_idx]; + info_out->props.flags |= FilePropertyFlag_IsFolder; + w32_iter->drive_strings_iter_idx += 1; + } + } + break; + } + if (!result) + { + iter->flags |= OS_FileIterFlag_Done; + } + return result; } -internal void -os_file_iter_end(OS_FileIter *iter) -{ - OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - FindClose(w32_iter->handle); +void +os_file_iter_end(OS_FileIter* iter) { + OS_W32_FileIter* w32_iter = (OS_W32_FileIter*)iter->memory; + FindClose(w32_iter->handle); } //- rjf: directory creation -internal B32 +B32 os_make_directory(String8 path) { - B32 result = 0; - Temp scratch = scratch_begin(0, 0); - String16 name16 = str16_from_8(scratch.arena, path); - WIN32_FILE_ATTRIBUTE_DATA attributes = {0}; - GetFileAttributesExW((WCHAR*)name16.str, GetFileExInfoStandard, &attributes); - if(attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - result = 1; - } - else if(CreateDirectoryW((WCHAR*)name16.str, 0)) - { - result = 1; - } - scratch_end(scratch); - return(result); + B32 result = 0; + TempArena scratch = scratch_begin(0, 0); + { + String16 name16 = str16_from_8(scratch.arena, path); + WIN32_FILE_ATTRIBUTE_DATA attributes = {0}; + GetFileAttributesExW((WCHAR*)name16.str, GetFileExInfoStandard, &attributes); + if (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + result = 1; + } + else if (CreateDirectoryW((WCHAR*)name16.str, 0)) { + result = 1; + } + } + scratch_end(scratch); + return(result); } //////////////////////////////// //~ rjf: @os_hooks Shared Memory (Implemented Per-OS) -internal OS_Handle +OS_Handle os_shared_memory_alloc(U64 size, String8 name) { - Temp scratch = scratch_begin(0, 0); - String16 name16 = str16_from_8(scratch.arena, name); - HANDLE file = CreateFileMappingW(INVALID_HANDLE_VALUE, - 0, - PAGE_READWRITE, - (U32)((size & 0xffffffff00000000) >> 32), - (U32)((size & 0x00000000ffffffff)), - (WCHAR *)name16.str); - OS_Handle result = {(U64)file}; - scratch_end(scratch); - return result; + TempArena scratch = scratch_begin(0, 0); + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = CreateFileMappingW(INVALID_HANDLE_VALUE, + 0, + PAGE_READWRITE, + (U32)((size & 0xffffffff00000000) >> 32), + (U32)((size & 0x00000000ffffffff)), + (WCHAR *)name16.str + ); + scratch_end(scratch); + OS_Handle result = {(U64)file}; + return result; } -internal OS_Handle +OS_Handle os_shared_memory_open(String8 name) { 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}; - scratch_end(scratch); - return result; + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE file = OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, (WCHAR *)name16.str); + scratch_end(scratch); + OS_Handle result = {(U64)file}; + return result; } -internal void -os_shared_memory_close(OS_Handle handle) -{ - HANDLE file = (HANDLE)(handle.u64[0]); - CloseHandle(file); +void +os_shared_memory_close(OS_Handle handle) { + HANDLE file = (HANDLE)(handle.u64[0]); + CloseHandle(file); } -internal void * +void* os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) { - HANDLE file = (HANDLE)(handle.u64[0]); - U64 offset = range.min; - U64 size = range.max-range.min; - void *ptr = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, - (U32)((offset & 0xffffffff00000000) >> 32), - (U32)((offset & 0x00000000ffffffff)), - size); - return ptr; + HANDLE file = (HANDLE)(handle.u64[0]); + U64 offset = range.min; + U64 size = range.max-range.min; + void* ptr = MapViewOfFile(file, FILE_MAP_ALL_ACCESS, + (U32)((offset & 0xffffffff00000000) >> 32), + (U32)((offset & 0x00000000ffffffff)), + size + ); + return ptr; } -internal void -os_shared_memory_view_close(OS_Handle handle, void *ptr, Rng1U64 range) -{ - UnmapViewOfFile(ptr); +void +os_shared_memory_view_close(OS_Handle handle, void *ptr, Rng1U64 range) { + UnmapViewOfFile(ptr); } //////////////////////////////// //~ rjf: @os_hooks Time (Implemented Per-OS) -internal U64 -os_now_microseconds(void) -{ - U64 result = 0; - LARGE_INTEGER large_int_counter; - if(QueryPerformanceCounter(&large_int_counter)) - { - result = (large_int_counter.QuadPart*Million(1))/os_w32_state.microsecond_resolution; - } - return result; +U64 +os_now_microseconds(void) { + U64 result = 0; + LARGE_INTEGER large_int_counter; + if (QueryPerformanceCounter(&large_int_counter)) { + result = (large_int_counter.QuadPart * million(1)) / os_w32_state.microsecond_resolution; + } + return result; } -internal U32 -os_now_unix(void) -{ - FILETIME file_time; - GetSystemTimeAsFileTime(&file_time); - U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; - U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); - U32 unix_time32 = (U32)unix_time64; - return unix_time32; +U32 +os_now_unix(void) { + FILETIME file_time; + GetSystemTimeAsFileTime(&file_time); + U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; + U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); + U32 unix_time32 = (U32)unix_time64; + return unix_time32; } -internal DateTime -os_now_universal_time(void) -{ - SYSTEMTIME systime = {0}; - GetSystemTime(&systime); - DateTime result = {0}; - os_w32_date_time_from_system_time(&result, &systime); - return result; +DateTime +os_now_universal_time(void) { + SYSTEMTIME systime = {0}; + GetSystemTime(&systime); + DateTime result = {0}; + os_w32_date_time_from_system_time(&result, &systime); + return result; } -internal DateTime -os_universal_time_from_local(DateTime *date_time) +DateTime +os_universal_time_from_local(DateTime* date_time) { - SYSTEMTIME systime = {0}; - os_w32_system_time_from_date_time(&systime, date_time); - FILETIME ftime = {0}; - SystemTimeToFileTime(&systime, &ftime); - FILETIME ftime_local = {0}; - LocalFileTimeToFileTime(&ftime, &ftime_local); - FileTimeToSystemTime(&ftime_local, &systime); - DateTime result = {0}; - os_w32_date_time_from_system_time(&result, &systime); - return result; + SYSTEMTIME systime = {0}; + os_w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + LocalFileTimeToFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + os_w32_date_time_from_system_time(&result, &systime); + return result; } -internal DateTime -os_local_time_from_universal(DateTime *date_time) +DateTime +os_local_time_from_universal(DateTime* date_time) { - SYSTEMTIME systime = {0}; - os_w32_system_time_from_date_time(&systime, date_time); - FILETIME ftime = {0}; - SystemTimeToFileTime(&systime, &ftime); - FILETIME ftime_local = {0}; - FileTimeToLocalFileTime(&ftime, &ftime_local); - FileTimeToSystemTime(&ftime_local, &systime); - DateTime result = {0}; - os_w32_date_time_from_system_time(&result, &systime); - return result; + SYSTEMTIME systime = {0}; + os_w32_system_time_from_date_time(&systime, date_time); + FILETIME ftime = {0}; + SystemTimeToFileTime(&systime, &ftime); + FILETIME ftime_local = {0}; + FileTimeToLocalFileTime(&ftime, &ftime_local); + FileTimeToSystemTime(&ftime_local, &systime); + DateTime result = {0}; + os_w32_date_time_from_system_time(&result, &systime); + return result; } -internal void -os_sleep_milliseconds(U32 msec) -{ - Sleep(msec); +void +os_sleep_milliseconds(U32 msec) { + Sleep(msec); } //////////////////////////////// //~ rjf: @os_hooks Child Processes (Implemented Per-OS) -internal OS_Handle -os_process_launch(OS_ProcessLaunchParams *params) +OS_Handle +os_process_launch(OS_ProcessLaunchParams* params) { - OS_Handle result = {0}; - TempArena scratch = scratch_begin(0, 0); + OS_Handle result = {0}; + TempArena scratch = scratch_begin(0, 0); - //- rjf: form full command string - String8 cmd = {0}; - { - StringJoin join_params = {0}; - join_params.pre = str8_lit("\""); - join_params.sep = str8_lit("\" \""); - join_params.post = str8_lit("\""); - cmd = str8_list_join(scratch.arena, ¶ms->cmd_line, &join_params); - } + //- rjf: form full command string + String8 cmd = {0}; + { + StringJoin + join_params = {0}; + join_params.pre = str8_lit("\""); + join_params.sep = str8_lit("\" \""); + join_params.post = str8_lit("\""); + cmd = str8_list_join(scratch.arena, ¶ms->cmd_line, &join_params); + } - //- rjf: form environment - B32 use_null_env_arg = 0; - String8 env = {0}; - { - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8List all_opts = params->env; - if(params->inherit_env != 0) - { - if(all_opts.node_count != 0) - { - MemoryZeroStruct(&all_opts); - for(String8Node *n = params->env.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - for(String8Node *n = os_w32_state.process_info.environment.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - } - else - { - use_null_env_arg = 1; - } - } - if(use_null_env_arg == 0) - { - env = str8_list_join(scratch.arena, &all_opts, &join_params2); - } - } + //- rjf: form environment + B32 use_null_env_arg = 0; + String8 env = {0}; + { + StringJoin + join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + + String8List all_opts = params->env; + if (params->inherit_env != 0) + { + if (all_opts.node_count != 0) + { + memory_zero_struct(&all_opts); + for (String8Node *n = params->env.first; n != 0; n = n->next) { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for (String8Node *n = os_w32_state.process_info.environment.first; n != 0; n = n->next) { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + else { + use_null_env_arg = 1; + } + } + if (use_null_env_arg == 0) { + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + } - //- rjf: utf-8 -> utf-16 - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, params->path); - String16 env16 = {0}; - if(use_null_env_arg == 0) - { - env16 = str16_from_8(scratch.arena, env); - } + //- rjf: utf-8 -> utf-16 + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, params->path); + String16 env16 = {0}; + if (use_null_env_arg == 0) { + env16 = str16_from_8(scratch.arena, env); + } - //- rjf: determine creation flags - DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT; - if(params->consoleless) - { - creation_flags |= CREATE_NO_WINDOW; - } + //- rjf: determine creation flags + DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT; + if (params->consoleless) { + creation_flags |= CREATE_NO_WINDOW; + } - //- rjf: launch - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) - { - result.u64[0] = (U64)process_info.hProcess; - CloseHandle(process_info.hThread); - } + //- rjf: launch + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + { + result.u64[0] = (U64)process_info.hProcess; + CloseHandle(process_info.hThread); + } - scratch_end(scratch); - return result; + scratch_end(scratch); + return result; } -internal B32 -os_process_join(OS_Handle handle, U64 endt_us) -{ +B32 +os_process_join(OS_Handle handle, U64 endt_us) { HANDLE process = (HANDLE)(handle.u64[0]); DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); DWORD result = WaitForSingleObject(process, sleep_ms); return (result == WAIT_OBJECT_0); } -internal void -os_process_detach(OS_Handle handle) -{ +void +os_process_detach(OS_Handle handle) { HANDLE process = (HANDLE)(handle.u64[0]); CloseHandle(process); } @@ -840,36 +853,33 @@ os_process_detach(OS_Handle handle) //////////////////////////////// //~ rjf: @os_hooks Threads (Implemented Per-OS) -internal OS_Handle -os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) -{ - OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Thread); - entity->thread.func = func; - entity->thread.ptr = ptr; - entity->thread.handle = CreateThread(0, 0, os_w32_thread_entry_point, entity, 0, &entity->thread.tid); - OS_Handle result = {IntFromPtr(entity)}; - return result; +OS_Handle +os_thread_launch(OS_ThreadFunctionType* func, void* ptr, void* params) { + OS_W32_Entity* entity = os_w32_entity_alloc(OS_W32_EntityKind_Thread); + entity->thread.func = func; + entity->thread.ptr = ptr; + entity->thread.handle = CreateThread(0, 0, os_w32_thread_entry_point, entity, 0, &entity->thread.tid); + OS_Handle result = {IntFromPtr(entity)}; + return result; } -internal B32 +B32 os_thread_join(OS_Handle handle, U64 endt_us) { - DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - OS_W32_Entity *entity = (OS_W32_Entity *)PtrFromInt(handle.u64[0]); - DWORD wait_result = WAIT_OBJECT_0; - if(entity != 0) - { - wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms); - } - os_w32_entity_release(entity); - return (wait_result == WAIT_OBJECT_0); + DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(handle.u64[0]); + DWORD wait_result = WAIT_OBJECT_0; + if (entity != 0) { + wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms); + } + os_w32_entity_release(entity); + return (wait_result == WAIT_OBJECT_0); } -internal void -os_thread_detach(OS_Handle thread) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]); - os_w32_entity_release(entity); +void +os_thread_detach(OS_Handle thread) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]); + os_w32_entity_release(entity); } //////////////////////////////// @@ -877,30 +887,27 @@ os_thread_detach(OS_Handle thread) //- rjf: mutexes -internal OS_Handle -os_mutex_alloc(void) -{ - OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Mutex); - InitializeCriticalSection(&entity->mutex); - OS_Handle result = {IntFromPtr(entity)}; - return result; +OS_Handle +os_mutex_alloc(void) { + OS_W32_Entity* entity = os_w32_entity_alloc(OS_W32_EntityKind_Mutex); + InitializeCriticalSection(&entity->mutex); + OS_Handle result = {IntFromPtr(entity)}; + return result; } -internal void -os_mutex_release(OS_Handle mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); - os_w32_entity_release(entity); +void +os_mutex_release(OS_Handle mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); + os_w32_entity_release(entity); } -internal void -os_mutex_take(OS_Handle mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); - EnterCriticalSection(&entity->mutex); +void +os_mutex_take(OS_Handle mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); + EnterCriticalSection(&entity->mutex); } -internal void +void os_mutex_drop(OS_Handle mutex) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); @@ -909,621 +916,609 @@ os_mutex_drop(OS_Handle mutex) //- rjf: reader/writer mutexes -internal OS_Handle -os_rw_mutex_alloc(void) -{ - OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_RWMutex); - InitializeSRWLock(&entity->rw_mutex); - OS_Handle result = {IntFromPtr(entity)}; - return result; +OS_Handle +os_rw_mutex_alloc(void) { + OS_W32_Entity* entity = os_w32_entity_alloc(OS_W32_EntityKind_RWMutex); + InitializeSRWLock(&entity->rw_mutex); + OS_Handle result = {IntFromPtr(entity)}; + return result; } -internal void -os_rw_mutex_release(OS_Handle rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - os_w32_entity_release(entity); +void +os_rw_mutex_release(OS_Handle rw_mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + os_w32_entity_release(entity); } -internal void -os_rw_mutex_take_r(OS_Handle rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - AcquireSRWLockShared(&entity->rw_mutex); +void +os_rw_mutex_take_r(OS_Handle rw_mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockShared(&entity->rw_mutex); } -internal void -os_rw_mutex_drop_r(OS_Handle rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - ReleaseSRWLockShared(&entity->rw_mutex); +void +os_rw_mutex_drop_r(OS_Handle rw_mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockShared(&entity->rw_mutex); } -internal void -os_rw_mutex_take_w(OS_Handle rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - AcquireSRWLockExclusive(&entity->rw_mutex); +void +os_rw_mutex_take_w(OS_Handle rw_mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + AcquireSRWLockExclusive(&entity->rw_mutex); } -internal void -os_rw_mutex_drop_w(OS_Handle rw_mutex) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); - ReleaseSRWLockExclusive(&entity->rw_mutex); +void +os_rw_mutex_drop_w(OS_Handle rw_mutex) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(rw_mutex.u64[0]); + ReleaseSRWLockExclusive(&entity->rw_mutex); } //- rjf: condition variables -internal OS_Handle -os_condition_variable_alloc(void) -{ - OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_ConditionVariable); - InitializeConditionVariable(&entity->cv); - OS_Handle result = {IntFromPtr(entity)}; - return result; +OS_Handle +os_condition_variable_alloc(void) { + OS_W32_Entity* entity = os_w32_entity_alloc(OS_W32_EntityKind_ConditionVariable); + InitializeConditionVariable(&entity->cv); + OS_Handle result = {IntFromPtr(entity)}; + return result; } -internal void -os_condition_variable_release(OS_Handle cv) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - os_w32_entity_release(entity); +void +os_condition_variable_release(OS_Handle cv) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + os_w32_entity_release(entity); } -internal B32 -os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - BOOL result = 0; - if(sleep_ms > 0) - { - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); - result = SleepConditionVariableCS(&entity->cv, &mutex_entity->mutex, sleep_ms); - } - return result; +B32 +os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us) { + U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + OS_W32_Entity* mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]); + result = SleepConditionVariableCS(&entity->cv, &mutex_entity->mutex, sleep_ms); + } + return result; } -internal B32 -os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - BOOL result = 0; - if(sleep_ms > 0) - { - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); - result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, - CONDITION_VARIABLE_LOCKMODE_SHARED); - } - return result; +B32 +os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { + U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if (sleep_ms > 0) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + OS_W32_Entity* mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, CONDITION_VARIABLE_LOCKMODE_SHARED); + } + return result; } -internal B32 -os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - BOOL result = 0; - if(sleep_ms > 0) - { - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - OS_W32_Entity *mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); - result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0); - } - return result; +B32 +os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us) { + U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + BOOL result = 0; + if(sleep_ms > 0) + { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + OS_W32_Entity* mutex_entity = (OS_W32_Entity*)PtrFromInt(mutex_rw.u64[0]); + result = SleepConditionVariableSRW(&entity->cv, &mutex_entity->rw_mutex, sleep_ms, 0); + } + return result; } -internal void -os_condition_variable_signal(OS_Handle cv) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - WakeConditionVariable(&entity->cv); +void +os_condition_variable_signal(OS_Handle cv) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + WakeConditionVariable(&entity->cv); } -internal void -os_condition_variable_broadcast(OS_Handle cv) -{ - OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); - WakeAllConditionVariable(&entity->cv); +void +os_condition_variable_broadcast(OS_Handle cv) { + OS_W32_Entity* entity = (OS_W32_Entity*)PtrFromInt(cv.u64[0]); + WakeAllConditionVariable(&entity->cv); } //- rjf: cross-process semaphores -internal OS_Handle -os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) -{ +OS_Handle +os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { 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}; - scratch_end(scratch); - return result; + String16 name16 = str16_from_8(scratch.arena, name); + HANDLE handle = CreateSemaphoreW(0, initial_count, max_count, (WCHAR *)name16.str); + OS_Handle result = {(U64)handle}; + scratch_end(scratch); + return result; } -internal void -os_semaphore_release(OS_Handle semaphore) -{ - HANDLE handle = (HANDLE)semaphore.u64[0]; - CloseHandle(handle); +void +os_semaphore_release(OS_Handle semaphore) { + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); } -internal OS_Handle -os_semaphore_open(String8 name) -{ - 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}; - scratch_end(scratch); - return result; +OS_Handle +os_semaphore_open(String8 name) { + 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}; + scratch_end(scratch); + return result; } -internal void -os_semaphore_close(OS_Handle semaphore) -{ - HANDLE handle = (HANDLE)semaphore.u64[0]; - CloseHandle(handle); +void +os_semaphore_close(OS_Handle semaphore) { + HANDLE handle = (HANDLE)semaphore.u64[0]; + CloseHandle(handle); } -internal B32 -os_semaphore_take(OS_Handle semaphore, U64 endt_us) -{ - U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); - HANDLE handle = (HANDLE)semaphore.u64[0]; - DWORD wait_result = WaitForSingleObject(handle, sleep_ms); - B32 result = (wait_result == WAIT_OBJECT_0); - return result; +B32 +os_semaphore_take(OS_Handle semaphore, U64 endt_us) { + U32 sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us); + HANDLE handle = (HANDLE)semaphore.u64[0]; + DWORD wait_result = WaitForSingleObject(handle, sleep_ms); + B32 result = (wait_result == WAIT_OBJECT_0); + return result; } -internal void -os_semaphore_drop(OS_Handle semaphore) -{ - HANDLE handle = (HANDLE)semaphore.u64[0]; - ReleaseSemaphore(handle, 1, 0); +void +os_semaphore_drop(OS_Handle semaphore) { + HANDLE handle = (HANDLE)semaphore.u64[0]; + ReleaseSemaphore(handle, 1, 0); } //////////////////////////////// //~ rjf: @os_hooks Dynamically-Loaded Libraries (Implemented Per-OS) -internal OS_Handle +OS_Handle os_library_open(String8 path) { 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 }; - scratch_end(scratch); - return result; + String16 path16 = str16_from_8(scratch.arena, path); + HMODULE mod = LoadLibraryW((LPCWSTR)path16.str); + OS_Handle result = { (U64)mod }; + scratch_end(scratch); + return result; } -internal VoidProc* +VoidProc* os_library_load_proc(OS_Handle lib, String8 name) { 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); - scratch_end(scratch); - return result; + HMODULE mod = (HMODULE)lib.u64[0]; + name = push_str8_copy(scratch.arena, name); + VoidProc* result = (VoidProc*)GetProcAddress(mod, (LPCSTR)name.str); + scratch_end(scratch); + return result; } -internal void -os_library_close(OS_Handle lib) -{ - HMODULE mod = (HMODULE)lib.u64[0]; - FreeLibrary(mod); +void +os_library_close(OS_Handle lib) { + HMODULE mod = (HMODULE)lib.u64[0]; + FreeLibrary(mod); } //////////////////////////////// //~ rjf: @os_hooks Safe Calls (Implemented Per-OS) -internal void +void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, void *ptr) { - __try - { - func(ptr); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - if(fail_handler != 0) - { - fail_handler(ptr); - } - ExitProcess(1); - } + __try { + func(ptr); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + if (fail_handler != 0) + { + fail_handler(ptr); + } + ExitProcess(1); + } } //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +OS_Guid os_make_guid(void) { - OS_Guid result; MemoryZeroStruct(&result); - UUID uuid; - RPC_STATUS rpc_status = UuidCreate(&uuid); - if(rpc_status == RPC_S_OK) - { - result.data1 = uuid.Data1; - result.data2 = uuid.Data2; - result.data3 = uuid.Data3; - MemoryCopyArray(result.data4, uuid.Data4); - } - return result; + OS_Guid result; memory_zero_struct(&result); + UUID uuid; + RPC_STATUS rpc_status = UuidCreate(&uuid); + if (rpc_status == RPC_S_OK) + { + result.data1 = uuid.Data1; + result.data2 = uuid.Data2; + result.data3 = uuid.Data3; + memory_copy_array(result.data4, uuid.Data4); + } + return result; } //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) +#if BUILD_ENTRY_DEFINING_UNIT + #include #undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside #include -internal B32 win32_g_is_quiet = 0; +B32 win32_g_is_quiet = 0; -internal HRESULT WINAPI +HRESULT WINAPI win32_dialog_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LONG_PTR data) { - if(msg == TDN_HYPERLINK_CLICKED) - { - ShellExecuteW(NULL, L"open", (LPWSTR)lparam, NULL, NULL, SW_SHOWNORMAL); - } - return S_OK; + if (msg == TDN_HYPERLINK_CLICKED) + { + ShellExecuteW(NULL, L"open", (LPWSTR)lparam, NULL, NULL, SW_SHOWNORMAL); + } + return S_OK; } -internal LONG WINAPI +LONG WINAPI win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) { - if(win32_g_is_quiet) - { - ExitProcess(1); - } + if (win32_g_is_quiet) + { + ExitProcess(1); + } - static volatile LONG first = 0; - if(InterlockedCompareExchange(&first, 1, 0) != 0) - { - // prevent failures in other threads to popup same message box - // this handler just shows first thread that crashes - // we are terminating afterwards anyway - for (;;) Sleep(1000); - } + static volatile LONG first = 0; + if (InterlockedCompareExchange(&first, 1, 0) != 0) + { + // prevent failures in other threads to popup same message box + // this handler just shows first thread that crashes + // we are terminating afterwards anyway + for (;;) Sleep(1000); + } - WCHAR buffer[4096] = {0}; - int buflen = 0; + WCHAR buffer[4096] = {0}; + int buflen = 0; - DWORD exception_code = exception_ptrs->ExceptionRecord->ExceptionCode; - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"A fatal exception (code 0x%x) occurred. The process is terminating.\n", exception_code); + DWORD exception_code = exception_ptrs->ExceptionRecord->ExceptionCode; + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"A fatal exception (code 0x%x) occurred. The process is terminating.\n", exception_code); - // load dbghelp dynamically just in case if it is missing - HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); - if(dbghelp) - { - DWORD (WINAPI *dbg_SymSetOptions)(DWORD SymOptions); - BOOL (WINAPI *dbg_SymInitializeW)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess); - BOOL (WINAPI *dbg_StackWalk64)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); - PVOID (WINAPI *dbg_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); - DWORD64 (WINAPI *dbg_SymGetModuleBase64)(HANDLE hProcess, DWORD64 qwAddr); - BOOL (WINAPI *dbg_SymFromAddrW)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFOW Symbol); - BOOL (WINAPI *dbg_SymGetLineFromAddrW64)(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line); - BOOL (WINAPI *dbg_SymGetModuleInfoW64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo); + // load dbghelp dynamically just in case if it is missing + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + if(dbghelp) + { + DWORD (WINAPI * dbg_SymSetOptions )(DWORD SymOptions); + BOOL (WINAPI * dbg_SymInitializeW)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess); + BOOL (WINAPI * dbg_StackWalk64)( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ); + PVOID (WINAPI * dbg_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); + DWORD64 (WINAPI * dbg_SymGetModuleBase64 )(HANDLE hProcess, DWORD64 qwAddr); + BOOL (WINAPI * dbg_SymFromAddrW )(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFOW Symbol); + BOOL (WINAPI * dbg_SymGetLineFromAddrW64 )(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line); + BOOL (WINAPI * dbg_SymGetModuleInfoW64 )(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo); - *(FARPROC*)&dbg_SymSetOptions = GetProcAddress(dbghelp, "SymSetOptions"); - *(FARPROC*)&dbg_SymInitializeW = GetProcAddress(dbghelp, "SymInitializeW"); - *(FARPROC*)&dbg_StackWalk64 = GetProcAddress(dbghelp, "StackWalk64"); - *(FARPROC*)&dbg_SymFunctionTableAccess64 = GetProcAddress(dbghelp, "SymFunctionTableAccess64"); - *(FARPROC*)&dbg_SymGetModuleBase64 = GetProcAddress(dbghelp, "SymGetModuleBase64"); - *(FARPROC*)&dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW"); - *(FARPROC*)&dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64"); - *(FARPROC*)&dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64"); + * (FARPROC*) &dbg_SymSetOptions = GetProcAddress(dbghelp, "SymSetOptions"); + * (FARPROC*) &dbg_SymInitializeW = GetProcAddress(dbghelp, "SymInitializeW"); + * (FARPROC*) &dbg_StackWalk64 = GetProcAddress(dbghelp, "StackWalk64"); + * (FARPROC*) &dbg_SymFunctionTableAccess64 = GetProcAddress(dbghelp, "SymFunctionTableAccess64"); + * (FARPROC*) &dbg_SymGetModuleBase64 = GetProcAddress(dbghelp, "SymGetModuleBase64"); + * (FARPROC*) &dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW"); + * (FARPROC*) &dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64"); + * (FARPROC*) &dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64"); - if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64) - { - HANDLE process = GetCurrentProcess(); - HANDLE thread = GetCurrentThread(); - CONTEXT* context = exception_ptrs->ContextRecord; + if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64) + { + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + CONTEXT* context = exception_ptrs->ContextRecord; - dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - if(dbg_SymInitializeW(process, L"", TRUE)) - { - // check that raddbg.pdb file is good - B32 raddbg_pdb_valid = 0; - { - IMAGEHLP_MODULEW64 module = {0}; - module.SizeOfStruct = sizeof(module); - if(dbg_SymGetModuleInfoW64(process, (DWORD64)&win32_exception_filter, &module)) - { - raddbg_pdb_valid = (module.SymType == SymPdb); - } - } + dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + if(dbg_SymInitializeW(process, L"", TRUE)) + { + // check that raddbg.pdb file is good + B32 raddbg_pdb_valid = 0; + { + IMAGEHLP_MODULEW64 + module = {0}; + module.SizeOfStruct = sizeof(module); + if(dbg_SymGetModuleInfoW64(process, (DWORD64)&win32_exception_filter, &module)) { + raddbg_pdb_valid = (module.SymType == SymPdb); + } + } - if(!raddbg_pdb_valid) - { - buflen += wnsprintfW(buffer + buflen, sizeof(buffer) - buflen, - L"\nThe PDB debug information file for this executable is not valid or was not found. Please rebuild binary to get the call stack.\n"); - } - else - { - STACKFRAME64 frame = {0}; - DWORD image_type; -#if defined(_M_AMD64) - image_type = IMAGE_FILE_MACHINE_AMD64; - frame.AddrPC.Offset = context->Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context->Rbp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context->Rsp; - frame.AddrStack.Mode = AddrModeFlat; -#elif defined(_M_ARM64) - image_type = IMAGE_FILE_MACHINE_ARM64; - frame.AddrPC.Offset = context->Pc; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context->Fp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context->Sp; - frame.AddrStack.Mode = AddrModeFlat; -#else -# error Architecture not supported! -#endif + if(!raddbg_pdb_valid) + { + buflen += wnsprintfW(buffer + buflen, sizeof(buffer) - buflen, + L"\nThe PDB debug information file for this executable is not valid or was not found. Please rebuild binary to get the call stack.\n" + ); + } + else + { + STACKFRAME64 frame = {0}; + DWORD image_type; + #if defined(_M_AMD64) + image_type = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Offset = context->Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Rsp; + frame.AddrStack.Mode = AddrModeFlat; + #elif defined(_M_ARM64) + image_type = IMAGE_FILE_MACHINE_ARM64; + frame.AddrPC.Offset = context->Pc; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Fp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Sp; + frame.AddrStack.Mode = AddrModeFlat; + #else + # error Architecture not supported! + #endif - for(U32 idx=0; ;idx++) - { - const U32 max_frames = 32; - if(idx == max_frames) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"..."); - break; - } - - if(!dbg_StackWalk64(image_type, process, thread, &frame, context, 0, dbg_SymFunctionTableAccess64, dbg_SymGetModuleBase64, 0)) - { - break; - } - - U64 address = frame.AddrPC.Offset; - if(address == 0) - { - break; - } - - if(idx==0) - { -#if BUILD_CONSOLE_INTERFACE - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nCreate a new issue with this report at %S.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); -#else - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, - L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue at\n" - L"%S\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL); -#endif - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address); - - struct { - SYMBOL_INFOW info; - WCHAR name[MAX_SYM_NAME]; - } symbol = {0}; - - symbol.info.SizeOfStruct = sizeof(symbol.info); - symbol.info.MaxNameLen = MAX_SYM_NAME; - - DWORD64 displacement = 0; - if(dbg_SymFromAddrW(process, address, &displacement, &symbol.info)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s +%u", symbol.info.Name, (DWORD)displacement); - - IMAGEHLP_LINEW64 line = {0}; - line.SizeOfStruct = sizeof(line); - - DWORD line_displacement = 0; - if(dbg_SymGetLineFromAddrW64(process, address, &line_displacement, &line)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L", %s line %u", PathFindFileNameW(line.FileName), line.LineNumber); - } - } - else - { - IMAGEHLP_MODULEW64 module = {0}; - module.SizeOfStruct = sizeof(module); - if(dbg_SymGetModuleInfoW64(process, address, &module)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s", module.ModuleName); - } - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\n"); - } - } - } - } - } + for(U32 idx=0; ;idx++) + { + const U32 max_frames = 32; + if(idx == max_frames) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"..."); + break; + } + + if(!dbg_StackWalk64(image_type, process, thread, &frame, context, 0, dbg_SymFunctionTableAccess64, dbg_SymGetModuleBase64, 0)) + { + break; + } + + U64 address = frame.AddrPC.Offset; + if(address == 0) + { + break; + } + + if(idx==0) + { + #if BUILD_CONSOLE_INTERFACE + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nCreate a new issue with this report at %S.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); + #else + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, + L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue at\n" + L"%S\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL); + #endif + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address); + + struct + { + SYMBOL_INFOW info; + WCHAR name[MAX_SYM_NAME]; + } + symbol = {0}; + symbol.info.SizeOfStruct = sizeof(symbol.info); + symbol.info.MaxNameLen = MAX_SYM_NAME; + + DWORD64 displacement = 0; + if (dbg_SymFromAddrW(process, address, &displacement, &symbol.info)) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s +%u", symbol.info.Name, (DWORD)displacement); + + IMAGEHLP_LINEW64 + line = {0}; + line.SizeOfStruct = sizeof(line); + + DWORD line_displacement = 0; + if(dbg_SymGetLineFromAddrW64(process, address, &line_displacement, &line)) { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L", %s line %u", PathFindFileNameW(line.FileName), line.LineNumber); + } + } + else + { + IMAGEHLP_MODULEW64 + module = {0}; + module.SizeOfStruct = sizeof(module); + if (dbg_SymGetModuleInfoW64(process, address, &module)) { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s", module.ModuleName); + } + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\n"); + } + } + } + } + } - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND); + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND); -#if BUILD_CONSOLE_INTERFACE - fwprintf(stderr, L"\n--- Fatal Exception ---\n"); - fwprintf(stderr, L"%s\n\n", buffer); -#else - TASKDIALOGCONFIG dialog = {0}; - dialog.cbSize = sizeof(dialog); - dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION; - dialog.pszMainIcon = TD_ERROR_ICON; - dialog.dwCommonButtons = TDCBF_CLOSE_BUTTON; - dialog.pszWindowTitle = L"Fatal Exception"; - dialog.pszContent = buffer; - dialog.pfCallback = &win32_dialog_callback; - TaskDialogIndirect(&dialog, 0, 0, 0); -#endif - - ExitProcess(1); + #if BUILD_CONSOLE_INTERFACE + fwprintf(stderr, L"\n--- Fatal Exception ---\n"); + fwprintf(stderr, L"%s\n\n", buffer); + #else + TASKDIALOGCONFIG dialog = {0}; + dialog.cbSize = sizeof(dialog); + dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION; + dialog.pszMainIcon = TD_ERROR_ICON; + dialog.dwCommonButtons = TDCBF_CLOSE_BUTTON; + dialog.pszWindowTitle = L"Fatal Exception"; + dialog.pszContent = buffer; + dialog.pfCallback = &win32_dialog_callback; + TaskDialogIndirect(&dialog, 0, 0, 0); + #endif + + ExitProcess(1); } #undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside #define OS_WINDOWS 1 -internal void -w32_entry_point_caller(int argc, WCHAR **wargv) +void +w32_entry_point_caller(int argc, WCHAR** wargv) { - SetUnhandledExceptionFilter(&win32_exception_filter); + SetUnhandledExceptionFilter(&win32_exception_filter); + //- rjf: do OS layer initialization + { + // rjf: dynamically load windows functions which are not guaranteed + // in all SDKs + { + HMODULE module = LoadLibraryA("kernel32.dll"); + w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription"); + FreeLibrary(module); + } + + // rjf: try to enable large pages if we can + { + HANDLE token; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) + { + LUID luid; + if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) + { + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0); + } + CloseHandle(token); + } + } + + // rjf: get system info + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + + // rjf: set up non-dynamically-alloc'd state + // + // (we need to set up some basics before this layer can supply + // memory allocation primitives) + { + os_w32_state.microsecond_resolution = 1; + LARGE_INTEGER large_int_resolution; + if (QueryPerformanceFrequency(&large_int_resolution)) + { + os_w32_state.microsecond_resolution = large_int_resolution.QuadPart; + } + } + { + OS_SystemInfo* info = &os_w32_state.system_info; + info->logical_processor_count = (U64)sysinfo.dwNumberOfProcessors; + info->page_size = sysinfo.dwPageSize; + info->large_page_size = GetLargePageMinimum(); + info->allocation_granularity = sysinfo.dwAllocationGranularity; + } + { + OS_ProcessInfo* info = &os_w32_state.process_info; + info->pid = GetCurrentProcessId(); + } + + // rjf: set up thread context + local_persist TCTX tctx; + tctx_init_and_equip(&tctx); + + // rjf: set up dynamically-alloc'd state + Arena* arena = arena_alloc(.backing = varena_alloc(0)); + { + os_w32_state.arena = arena; + { + OS_SystemInfo* info = &os_w32_state.system_info; + U8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD size = MAX_COMPUTERNAME_LENGTH + 1; + if(GetComputerNameA((char*)buffer, &size)) + { + info->machine_name = push_str8_copy(arena, str8(buffer, size)); + } + } + } + { + OS_ProcessInfo* info = &os_w32_state.process_info; + { + 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); + String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); + String8 name_chopped = str8_chop_last_slash(name8); + info->binary_path = push_str8_copy(arena, name_chopped); + scratch_end(scratch); + } + + info->initial_path = os_get_current_path(arena); + { + 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))) { + info->user_program_data_path = str8_from_16(arena, str16_cstring(buffer)); + } + scratch_end(scratch); + } + { + WCHAR* this_proc_env = GetEnvironmentStringsW(); + U64 start_idx = 0; + for (U64 idx = 0;; idx += 1) + { + if (this_proc_env[idx] == 0) + { + if (start_idx == idx) + { + break; + } + else + { + String16 string16 = str16((U16 *)this_proc_env + start_idx, idx - start_idx); + String8 string = str8_from_16(arena, string16); + str8_list_push(arena, &info->environment, string); + start_idx = idx+1; + } + } + } + } + } + + // rjf: set up entity storage + InitializeCriticalSection(&os_w32_state.entity_mutex); + os_w32_state.entity_arena = arena_alloc(.backing = varena_alloc(0)); + } - //- rjf: do OS layer initialization - { - // rjf: dynamically load windows functions which are not guaranteed - // in all SDKs - { - HMODULE module = LoadLibraryA("kernel32.dll"); - w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription"); - FreeLibrary(module); - } - - // rjf: try to enable large pages if we can - { - HANDLE token; - if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) - { - LUID luid; - if(LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) - { - TOKEN_PRIVILEGES priv; - priv.PrivilegeCount = 1; - priv.Privileges[0].Luid = luid; - priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0); - } - CloseHandle(token); - } - } - - // rjf: get system info - SYSTEM_INFO sysinfo = {0}; - GetSystemInfo(&sysinfo); - - // rjf: set up non-dynamically-alloc'd state - // - // (we need to set up some basics before this layer can supply - // memory allocation primitives) - { - os_w32_state.microsecond_resolution = 1; - LARGE_INTEGER large_int_resolution; - if(QueryPerformanceFrequency(&large_int_resolution)) - { - os_w32_state.microsecond_resolution = large_int_resolution.QuadPart; - } - } - { - OS_SystemInfo *info = &os_w32_state.system_info; - info->logical_processor_count = (U64)sysinfo.dwNumberOfProcessors; - info->page_size = sysinfo.dwPageSize; - info->large_page_size = GetLargePageMinimum(); - info->allocation_granularity = sysinfo.dwAllocationGranularity; - } - { - OS_ProcessInfo *info = &os_w32_state.process_info; - info->pid = GetCurrentProcessId(); - } - - // rjf: set up thread context - local_persist TCTX tctx; - tctx_init_and_equip(&tctx); - - // rjf: set up dynamically-alloc'd state - Arena *arena = arena_alloc(); - { - os_w32_state.arena = arena; - { - OS_SystemInfo *info = &os_w32_state.system_info; - U8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; - DWORD size = MAX_COMPUTERNAME_LENGTH + 1; - if(GetComputerNameA((char*)buffer, &size)) - { - info->machine_name = push_str8_copy(arena, str8(buffer, size)); - } - } - } - { - OS_ProcessInfo *info = &os_w32_state.process_info; - { - 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); - String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); - String8 name_chopped = str8_chop_last_slash(name8); - info->binary_path = push_str8_copy(arena, name_chopped); - scratch_end(scratch); - } - info->initial_path = os_get_current_path(arena); - { - 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))) - { - info->user_program_data_path = str8_from_16(arena, str16_cstring(buffer)); - } - scratch_end(scratch); - } - { - WCHAR *this_proc_env = GetEnvironmentStringsW(); - U64 start_idx = 0; - for(U64 idx = 0;; idx += 1) - { - if(this_proc_env[idx] == 0) - { - if(start_idx == idx) - { - break; - } - else - { - String16 string16 = str16((U16 *)this_proc_env + start_idx, idx - start_idx); - String8 string = str8_from_16(arena, string16); - str8_list_push(arena, &info->environment, string); - start_idx = idx+1; - } - } - } - } - } - - // rjf: set up entity storage - InitializeCriticalSection(&os_w32_state.entity_mutex); - os_w32_state.entity_arena = arena_alloc(); - } + //- rjf: extract arguments + Arena* args_arena = arena_alloc(.backing = varena_alloc(.reserve_size = MB(1), .commit_size = KB(32))); + char** argv = push_array(args_arena, char*, argc); + for (int i = 0; i < argc; i += 1) + { + String16 arg16 = str16_cstring((U16 *)wargv[i]); + String8 arg8 = str8_from_16(args_arena, arg16); + if (str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) + { + win32_g_is_quiet = 1; + } + argv[i] = (char *)arg8.str; + } - //- rjf: extract arguments - Arena *args_arena = arena_alloc(.reserve_size = MB(1), .commit_size = KB(32)); - char **argv = push_array(args_arena, char *, argc); - for(int i = 0; i < argc; i += 1) - { - String16 arg16 = str16_cstring((U16 *)wargv[i]); - String8 arg8 = str8_from_16(args_arena, arg16); - if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) - { - win32_g_is_quiet = 1; - } - argv[i] = (char *)arg8.str; - } - - //- rjf: call into "real" entry point - main_thread_base_entry_point(entry_point, argv, (U64)argc); + //- rjf: call into "real" entry point + main_thread_base_entry_point(entry_point, argv, (U64)argc); } #if BUILD_CONSOLE_INTERFACE -int wmain(int argc, WCHAR **argv) +int wmain(int argc, WCHAR** argv) { - w32_entry_point_caller(argc, argv); - return 0; + w32_entry_point_caller(argc, argv); + return 0; } #else int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) { - w32_entry_point_caller(__argc, __wargv); - return 0; + w32_entry_point_caller(__argc, __wargv); + return 0; } #endif + +// BUILD_ENTRY_POINT +#endif diff --git a/code/os/win32/os_win32.h b/code/os/win32/os_win32.h index 229649c..1ed5681 100644 --- a/code/os/win32/os_win32.h +++ b/code/os/win32/os_win32.h @@ -154,14 +154,14 @@ os_w32_date_time_from_system_time(DateTime* out, SYSTEMTIME* in) 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->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; + out->wHour = in->hour; + out->wMinute = in->min; + out->wSecond = in->sec; + out->wMilliseconds = in->msec; } inline void @@ -201,28 +201,43 @@ os_get_current_path(Arena* arena) { return name; } +inline String8 +os_get_current_path(AllocatorInfo ainfo) { + String8 name; + // TODO(Ed): Review + TempArena scratch = scratch_begin(0, 0); + { + 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_alloc(ainfo, 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_reserve ( U64 size) { void* result = VirtualAlloc( 0, size, MEM_RESERVE, PAGE_READWRITE); return result; } +inline B32 os_commit (void* ptr, U64 size) { B32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); return result; } +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); + // 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; + // 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; } @@ -231,14 +246,3 @@ 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); } - -//////////////////////////////// -//~ rjf: @os_hooks File System (Implemented Per-OS) - -//- rjf: files -