diff --git a/src/eval/eval_types.h b/src/eval/eval_types.h index 38c5c7aa..df66f01c 100644 --- a/src/eval/eval_types.h +++ b/src/eval/eval_types.h @@ -313,7 +313,7 @@ struct E_TypeState //////////////////////////////// //~ rjf: Globals -global read_only E_Member e_member_nil = {E_MemberKind_Null, zero_struct, {0}, {0}, 0, {0}}; +global read_only E_Member e_member_nil = {E_MemberKind_Null}; global read_only E_Type e_type_nil = {E_TypeKind_Null}; thread_static E_TypeState *e_type_state = 0; diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c index 2220b63e..5acd5cf8 100644 --- a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c @@ -150,9 +150,27 @@ os_get_current_path(Arena *arena) { char *cwdir = getcwd(0, 0); String8 string = push_str8_copy(arena, str8_cstring(cwdir)); + free(cwdir); return string; } +internal U32 +os_get_process_start_time_unix(void) +{ + Temp scratch = scratch_begin(0,0); + U64 start_time = 0; + pid_t pid = getpid(); + String8 path = push_str8f(scratch.arena, "/proc/%u", pid); + struct stat st; + int err = stat((char*)path.str, &st); + if(err == 0) + { + start_time = st.st_mtime; + } + scratch_end(scratch); + return (U32)start_time; +} + //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -162,6 +180,10 @@ internal void * os_reserve(U64 size) { void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if(result == MAP_FAILED) + { + result = 0; + } return result; } @@ -191,6 +213,10 @@ internal void * os_reserve_large(U64 size) { void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); + if(result == MAP_FAILED) + { + result = 0; + } return result; } @@ -207,12 +233,7 @@ os_commit_large(void *ptr, U64 size) internal U32 os_tid(void) { - U32 result = 0; -#if defined(SYS_gettid) - result = syscall(SYS_gettid); -#else - result = gettid(); -#endif + U32 result = gettid(); return result; } @@ -246,7 +267,7 @@ os_file_open(OS_AccessFlags flags, String8 path) Temp scratch = scratch_begin(0, 0); String8 path_copy = push_str8_copy(scratch.arena, path); int lnx_flags = 0; - if(flags & (OS_AccessFlag_Read|OS_AccessFlag_Write)) + if(flags & OS_AccessFlag_Read && flags & OS_AccessFlag_Write) { lnx_flags = O_RDWR; } @@ -262,7 +283,11 @@ os_file_open(OS_AccessFlags flags, String8 path) { lnx_flags |= O_APPEND; } - int fd = open((char *)path_copy.str, lnx_flags); + if(flags & (OS_AccessFlag_Write|OS_AccessFlag_Append)) + { + lnx_flags |= O_CREAT; + } + int fd = open((char *)path_copy.str, lnx_flags, 0755); OS_Handle handle = {0}; if(fd != -1) { @@ -285,16 +310,12 @@ os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) { if(os_handle_match(file, os_handle_zero())) { return 0; } int fd = (int)file.u64[0]; - if(rng.min != 0) - { - lseek(fd, rng.min, SEEK_SET); - } U64 total_num_bytes_to_read = dim_1u64(rng); U64 total_num_bytes_read = 0; U64 total_num_bytes_left_to_read = total_num_bytes_to_read; for(;total_num_bytes_left_to_read > 0;) { - int read_result = read(fd, (U8 *)out_data + total_num_bytes_read, total_num_bytes_left_to_read); + int read_result = pread(fd, (U8 *)out_data + total_num_bytes_read, total_num_bytes_left_to_read, rng.min + total_num_bytes_read); if(read_result >= 0) { total_num_bytes_read += read_result; @@ -313,16 +334,12 @@ os_file_write(OS_Handle file, Rng1U64 rng, void *data) { if(os_handle_match(file, os_handle_zero())) { return 0; } int fd = (int)file.u64[0]; - if(rng.min != 0) - { - lseek(fd, rng.min, SEEK_SET); - } U64 total_num_bytes_to_write = dim_1u64(rng); U64 total_num_bytes_written = 0; U64 total_num_bytes_left_to_write = total_num_bytes_to_write; for(;total_num_bytes_left_to_write > 0;) { - int write_result = write(fd, (U8 *)data + total_num_bytes_written, total_num_bytes_left_to_write); + int write_result = pwrite(fd, (U8 *)data + total_num_bytes_written, total_num_bytes_left_to_write, rng.min + total_num_bytes_written); if(write_result >= 0) { total_num_bytes_written += write_result; @@ -402,25 +419,23 @@ os_copy_file_path(String8 dst, String8 src) if(!os_handle_match(src_h, os_handle_zero()) && !os_handle_match(dst_h, os_handle_zero())) { + int src_fd = (int)src_h.u64[0]; + int dst_fd = (int)dst_h.u64[0]; 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) + off_t sendfile_off = total_bytes_copied; + int send_result = sendfile(dst_fd, src_fd, &sendfile_off, bytes_left_to_copy); + if(send_result <= 0) { break; } + U64 bytes_copied = (U64)send_result; + bytes_left_to_copy -= bytes_copied; + total_bytes_copied += bytes_copied; } } os_file_close(src_h); @@ -428,6 +443,12 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + // TODO(rjf) +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { @@ -455,6 +476,22 @@ os_file_path_exists(String8 path) return result; } +internal B32 +os_folder_path_exists(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 exists = 0; + String8 path_copy = push_str8_copy(scratch.arena, path); + DIR *handle = opendir((char*)path_copy.str); + if(handle) + { + closedir(handle); + exists = 1; + } + scratch_end(scratch); + return exists; +} + internal FileProperties os_properties_from_file_path(String8 path) { @@ -497,6 +534,10 @@ os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) 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); + if(base == MAP_FAILED) + { + base = 0; + } return base; } @@ -589,7 +630,7 @@ 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) + if(mkdir((char*)path_copy.str, 0755) != -1) { result = 1; } @@ -637,6 +678,10 @@ 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); + if(base == MAP_FAILED) + { + base = 0; + } return base; } @@ -744,10 +789,7 @@ os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) 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); + int pthread_result = pthread_create(&entity->thread.handle, 0, os_lnx_thread_entry_point, entity); if(pthread_result == -1) { os_lnx_entity_release(entity); @@ -1025,13 +1067,26 @@ os_condition_variable_broadcast(OS_Handle cv) internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { - NotImplemented; + OS_Handle result = {0}; + if (name.size > 0) { + // TODO: we need to allocate shared memory to store sem_t + NotImplemented; + } else { + sem_t *s = mmap(0, sizeof(*s), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + AssertAlways(s != MAP_FAILED); + int err = sem_init(s, 0, initial_count); + if (err == 0) { + result.u64[0] = (U64)s; + } + } + return result; } internal void os_semaphore_release(OS_Handle semaphore) { - NotImplemented; + int err = munmap((void*)semaphore.u64[0], sizeof(sem_t)); + AssertAlways(err == 0); } internal OS_Handle @@ -1049,13 +1104,37 @@ os_semaphore_close(OS_Handle semaphore) internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us) { - NotImplemented; + AssertAlways(endt_us == max_U64); + for (;;) { + int err = sem_wait((sem_t*)semaphore.u64[0]); + if (err == 0) { + break; + } else { + if (errno == EAGAIN) { + continue; + } + } + InvalidPath; + break; + } + return 1; } internal void os_semaphore_drop(OS_Handle semaphore) { - NotImplemented; + for (;;) { + int err = sem_post((sem_t*)semaphore.u64[0]); + if (err == 0) { + break; + } else { + if (errno == EAGAIN) { + continue; + } + } + InvalidPath; + break; + } } //////////////////////////////// @@ -1066,7 +1145,7 @@ 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); + void *so = dlopen(path_cstr, RTLD_LAZY|RTLD_LOCAL); OS_Handle lib = { (U64)so }; scratch_end(scratch); return lib; @@ -1130,14 +1209,11 @@ os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, v //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +internal 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 guid = {0}; + getrandom(guid.v, sizeof(guid.v), 0); guid.data3 &= 0x0fff; guid.data3 |= (4 << 12); guid.data4[0] &= 0x3f; @@ -1256,5 +1332,5 @@ main(int argc, char **argv) } //- rjf: call into "real" entry point - main_thread_base_entry_point(entry_point, argv, (U64)argc); + main_thread_base_entry_point(argc, argv); } diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h index 531c6af3..e7d2ba5a 100644 --- a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h @@ -8,24 +8,27 @@ //~ rjf: Includes #define _GNU_SOURCE +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +pid_t gettid(void); int pthread_setname_np(pthread_t thread, const char *name); int pthread_getname_np(pthread_t thread, char *name, size_t size); diff --git a/src/metagen/metagen_os/core/metagen_os_core.c b/src/metagen/metagen_os/core/metagen_os_core.c index a6718e32..21a0a413 100644 --- a/src/metagen/metagen_os/core/metagen_os_core.c +++ b/src/metagen/metagen_os/core/metagen_os_core.c @@ -152,22 +152,89 @@ os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) } //////////////////////////////// -//~ rjf: GUID Helpers (Helpers, Implemented Once) +//~ rjf: Process Launcher Helpers -internal String8 -os_string_from_guid(Arena *arena, OS_Guid guid) +internal OS_Handle +os_cmd_line_launch(String8 string) { - 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]); + Temp scratch = scratch_begin(0, 0); + U8 split_chars[] = {' '}; + String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0); + OS_Handle handle = {0}; + if(parts.node_count != 0) + { + // rjf: unpack exe part + String8 exe = parts.first->string; + String8 exe_folder = str8_chop_last_slash(exe); + if(exe_folder.size == 0) + { + exe_folder = os_get_current_path(scratch.arena); + } + + // rjf: find stdout delimiter + String8Node *stdout_delimiter_n = 0; + for(String8Node *n = parts.first; n != 0; n = n->next) + { + if(str8_match(n->string, str8_lit(">"), 0)) + { + stdout_delimiter_n = n; + break; + } + } + + // rjf: read stdout path + String8 stdout_path = {0}; + if(stdout_delimiter_n && stdout_delimiter_n->next) + { + stdout_path = stdout_delimiter_n->next->string; + } + + // rjf: open stdout handle + OS_Handle stdout_handle = {0}; + if(stdout_path.size != 0) + { + OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, stdout_path); + os_file_close(file); + stdout_handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, stdout_path); + } + + // rjf: form command line + String8List cmdline = {0}; + for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next) + { + str8_list_push(scratch.arena, &cmdline, n->string); + } + + // rjf: launch + OS_ProcessLaunchParams params = {0}; + params.cmd_line = cmdline; + params.path = exe_folder; + params.inherit_env = 1; + params.stdout_file = stdout_handle; + handle = os_process_launch(¶ms); + + // rjf: close stdout handle + { + if(stdout_path.size != 0) + { + os_file_close(stdout_handle); + } + } + } + scratch_end(scratch); + return handle; +} + +internal OS_Handle +os_cmd_line_launchf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + OS_Handle result = os_cmd_line_launch(string); + va_end(args); + scratch_end(scratch); return result; } + diff --git a/src/metagen/metagen_os/core/metagen_os_core.h b/src/metagen/metagen_os/core/metagen_os_core.h index dcfb900d..e3a02048 100644 --- a/src/metagen/metagen_os/core/metagen_os_core.h +++ b/src/metagen/metagen_os/core/metagen_os_core.h @@ -24,6 +24,7 @@ typedef struct OS_ProcessInfo OS_ProcessInfo; struct OS_ProcessInfo { U32 pid; + B32 large_pages_allowed; String8 binary_path; String8 initial_path; String8 user_program_data_path; @@ -37,12 +38,13 @@ struct OS_ProcessInfo typedef U32 OS_AccessFlags; enum { - OS_AccessFlag_Read = (1<<0), - OS_AccessFlag_Write = (1<<1), - OS_AccessFlag_Execute = (1<<2), - OS_AccessFlag_Append = (1<<3), - OS_AccessFlag_ShareRead = (1<<4), - OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Read = (1<<0), + OS_AccessFlag_Write = (1<<1), + OS_AccessFlag_Execute = (1<<2), + OS_AccessFlag_Append = (1<<3), + OS_AccessFlag_ShareRead = (1<<4), + OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Inherited = (1<<6), }; //////////////////////////////// @@ -78,19 +80,6 @@ struct OS_FileID U64 v[3]; }; -//////////////////////////////// -//~ rjf: Process Launch Parameters - -typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams; -struct OS_ProcessLaunchParams -{ - String8List cmd_line; - String8 path; - String8List env; - B32 inherit_env; - B32 consoleless; -}; - //////////////////////////////// //~ rjf: Handle Type @@ -123,17 +112,21 @@ struct OS_HandleArray }; //////////////////////////////// -//~ rjf: Globally Unique IDs +//~ rjf: Process Launch Parameters -typedef struct OS_Guid OS_Guid; -struct OS_Guid +typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams; +struct OS_ProcessLaunchParams { - U32 data1; - U16 data2; - U16 data3; - U8 data4[8]; + String8List cmd_line; + String8 path; + String8List env; + B32 inherit_env; + B32 debug_subprocesses; + B32 consoleless; + OS_Handle stdout_file; + OS_Handle stderr_file; + OS_Handle stdin_file; }; -StaticAssert(sizeof(OS_Guid) == 16, os_guid_check); //////////////////////////////// //~ rjf: Thread Types @@ -165,16 +158,18 @@ internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); //////////////////////////////// -//~ rjf: GUID Helpers (Helpers, Implemented Once) +//~ rjf: Process Launcher Helpers -internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); +internal OS_Handle os_cmd_line_launch(String8 string); +internal OS_Handle os_cmd_line_launchf(char *fmt, ...); //////////////////////////////// //~ rjf: @os_hooks System/Process Info (Implemented Per-OS) -internal OS_SystemInfo *os_get_system_info(void); +internal OS_SystemInfo *os_get_system_info(void); internal OS_ProcessInfo *os_get_process_info(void); -internal String8 os_get_current_path(Arena *arena); +internal String8 os_get_current_path(Arena *arena); +internal U32 os_get_process_start_time_unix(void); //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -207,14 +202,18 @@ internal void os_abort(S32 exit_code); 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); +#define os_file_read_struct(f, off, ptr) os_file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr)) 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_file_reserve_size(OS_Handle file, U64 size); internal B32 os_delete_file_at_path(String8 path); internal B32 os_copy_file_path(String8 dst, String8 src); +internal B32 os_move_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 B32 os_folder_path_exists(String8 path); internal FileProperties os_properties_from_file_path(String8 path); //- rjf: file maps @@ -320,7 +319,7 @@ internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *f //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid os_make_guid(void); +internal Guid os_make_guid(void); //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c index 876f0d91..6cc494f0 100644 --- a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c @@ -90,6 +90,18 @@ os_w32_sleep_ms_from_endt_us(U64 endt_us) return sleep_ms; } +internal U32 +os_w32_unix_time_from_file_time(FILETIME file_time) +{ + U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; + U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); + + Assert(unix_time64 <= max_U32); + U32 unix_time32 = (U32)unix_time64; + + return unix_time32; +} + //////////////////////////////// //~ rjf: Entity Functions @@ -167,6 +179,21 @@ os_get_current_path(Arena *arena) return name; } +internal U32 +os_get_process_start_time_unix(void) +{ + HANDLE handle = GetCurrentProcess(); + FILETIME start_time = {0}; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + if(GetProcessTimes(handle, &start_time, &exit_time, &kernel_time, &user_time)) + { + return os_w32_unix_time_from_file_time(start_time); + } + return 0; +} + //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -293,14 +320,19 @@ os_file_open(OS_AccessFlags flags, String8 path) DWORD access_flags = 0; DWORD share_mode = 0; DWORD creation_disposition = OPEN_EXISTING; - if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} - if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} - if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} - if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} - if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} - if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} - if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS;} - HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), 0, 0}; + if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} + if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} + if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} + if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} + if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} + if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} + if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS; access_flags |= FILE_APPEND_DATA; } + if(flags & OS_AccessFlag_Inherited) + { + security_attributes.bInheritHandle = 1; + } + HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, &security_attributes, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); if(file != INVALID_HANDLE_VALUE) { result.u64[0] = (U64)file; @@ -361,27 +393,29 @@ os_file_write(OS_Handle file, Rng1U64 rng, void *data) HANDLE win_handle = (HANDLE)file.u64[0]; U64 src_off = 0; U64 dst_off = rng.min; - U64 bytes_to_write_total = rng.max-rng.min; - U64 total_bytes_written = 0; - for(;src_off < bytes_to_write_total;) + U64 total_write_size = dim_1u64(rng); + for(;;) { - void *bytes_src = (void *)((U8 *)data + src_off); - U64 bytes_to_write_64 = (bytes_to_write_total-src_off); - U32 bytes_to_write_32 = u32_from_u64_saturate(bytes_to_write_64); - U32 bytes_written = 0; + void *bytes_src = (U8 *)data + src_off; + U64 bytes_left = total_write_size - src_off; + DWORD write_size = Min(MB(1), bytes_left); + DWORD bytes_written = 0; OVERLAPPED overlapped = {0}; - overlapped.Offset = (dst_off&0x00000000ffffffffull); + overlapped.Offset = (dst_off&0x00000000ffffffffull); overlapped.OffsetHigh = (dst_off&0xffffffff00000000ull) >> 32; - BOOL success = WriteFile(win_handle, bytes_src, bytes_to_write_32, (DWORD *)&bytes_written, &overlapped); + BOOL success = WriteFile(win_handle, bytes_src, write_size, &bytes_written, &overlapped); if(success == 0) { break; } src_off += bytes_written; dst_off += bytes_written; - total_bytes_written += bytes_written; + if(bytes_left == 0) + { + break; + } } - return total_bytes_written; + return src_off; } internal B32 @@ -435,6 +469,19 @@ os_id_from_file(OS_Handle file) return result; } +internal B32 +os_file_reserve_size(OS_Handle file, U64 size) +{ + HANDLE handle = (HANDLE)file.u64[0]; + + FILE_ALLOCATION_INFO alloc_info = {0}; + alloc_info.AllocationSize.LowPart = size & max_U32; + alloc_info.AllocationSize.HighPart = (size >> 32) & max_U32; + + BOOL is_reserved = SetFileInformationByHandle(handle, FileAllocationInfo, &alloc_info, sizeof(alloc_info)); + return is_reserved; +} + internal B32 os_delete_file_at_path(String8 path) { @@ -456,15 +503,33 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + Temp scratch = scratch_begin(0, 0); + String16 dst16 = str16_from_8(scratch.arena, dst); + String16 src16 = str16_from_8(scratch.arena, src); + B32 result = MoveFileW((WCHAR*)src16.str, (WCHAR*)dst16.str); + scratch_end(scratch); + return result; +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { Temp 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)); + DWORD buffer_size = Max(MAX_PATH, path.size * 2) + 1; + String16 path16 = str16_from_8(scratch.arena, path); + WCHAR *buffer = push_array_no_zero(scratch.arena, WCHAR, buffer_size); + DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, buffer, NULL); + if(path16_size > buffer_size) + { + arena_pop(scratch.arena, buffer_size); + buffer_size = path16_size + 1; + buffer = push_array_no_zero(scratch.arena, WCHAR, buffer_size); + path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, buffer, NULL); + } + String8 full_path = str8_from_16(arena, str16((U16*)buffer, path16_size)); scratch_end(scratch); return full_path; } @@ -480,6 +545,17 @@ os_file_path_exists(String8 path) return exists; } +internal B32 +os_folder_path_exists(String8 path) +{ + Temp 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 os_properties_from_file_path(String8 path) { @@ -495,6 +571,28 @@ os_properties_from_file_path(String8 path) os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); } + else + { + Temp scratch = scratch_begin(0, 0); + WCHAR buffer[512] = {0}; + DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); + U64 last_slash_pos = 0; + for(;last_slash_pos < path.size; last_slash_pos = str8_find_needle(path, last_slash_pos+1, str8_lit("/"), StringMatchFlag_SlashInsensitive)); + String8 path_trimmed = str8_prefix(path, last_slash_pos); + 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(scratch.arena, next_drive_string_16); + next_drive_string = str8_chop_last_slash(next_drive_string); + if(str8_match(path_trimmed, next_drive_string, StringMatchFlag_CaseInsensitive)) + { + props.flags |= FilePropertyFlag_IsFolder; + break; + } + } + scratch_end(scratch); + } FindClose(handle); scratch_end(scratch); return props; @@ -704,7 +802,12 @@ internal void os_file_iter_end(OS_FileIter *iter) { OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - FindClose(w32_iter->handle); + HANDLE zero_handle; + MemoryZeroStruct(&zero_handle); + if(!MemoryMatchStruct(&zero_handle, &w32_iter->handle)) + { + FindClose(w32_iter->handle); + } } //- rjf: directory creation @@ -805,10 +908,8 @@ 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 unix_time = os_w32_unix_time_from_file_time(file_time); + return unix_time; } internal DateTime @@ -926,9 +1027,31 @@ os_process_launch(OS_ProcessLaunchParams *params) } //- rjf: launch + BOOL inherit_handles = 0; STARTUPINFOW startup_info = {sizeof(startup_info)}; + if(!os_handle_match(params->stdout_file, os_handle_zero())) + { + HANDLE stdout_handle = (HANDLE)params->stdout_file.u64[0]; + startup_info.hStdOutput = stdout_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } + if(!os_handle_match(params->stderr_file, os_handle_zero())) + { + HANDLE stderr_handle = (HANDLE)params->stderr_file.u64[0]; + startup_info.hStdError = stderr_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } + if(!os_handle_match(params->stdin_file, os_handle_zero())) + { + HANDLE stdin_handle = (HANDLE)params->stdin_file.u64[0]; + startup_info.hStdInput = stdin_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } 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)) + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, inherit_handles, 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); @@ -977,8 +1100,9 @@ os_thread_join(OS_Handle handle, U64 endt_us) if(entity != 0) { wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms); + CloseHandle(entity->thread.handle); + os_w32_entity_release(entity); } - os_w32_entity_release(entity); return (wait_result == WAIT_OBJECT_0); } @@ -986,7 +1110,11 @@ internal void os_thread_detach(OS_Handle thread) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]); - os_w32_entity_release(entity); + if(entity != 0) + { + CloseHandle(entity->thread.handle); + os_w32_entity_release(entity); + } } //////////////////////////////// @@ -1255,10 +1383,10 @@ os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, v //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +internal Guid os_make_guid(void) { - OS_Guid result; MemoryZeroStruct(&result); + Guid result; MemoryZeroStruct(&result); UUID uuid; RPC_STATUS rpc_status = UuidCreate(&uuid); if(rpc_status == RPC_S_OK) @@ -1344,8 +1472,12 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) HANDLE thread = GetCurrentThread(); CONTEXT* context = exception_ptrs->ContextRecord; + WCHAR module_path[MAX_PATH]; + GetModuleFileNameW(NULL, module_path, ArrayCount(module_path)); + PathRemoveFileSpecW(module_path); + dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - if(dbg_SymInitializeW(process, L"", TRUE)) + if(dbg_SymInitializeW(process, module_path, TRUE)) { // check that raddbg.pdb file is good B32 raddbg_pdb_valid = 0; @@ -1384,7 +1516,7 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) frame.AddrStack.Offset = context->Sp; frame.AddrStack.Mode = AddrModeFlat; #else -# error Architecture not supported! +# error Arch not supported! #endif for(U32 idx=0; ;idx++) @@ -1488,129 +1620,60 @@ w32_entry_point_caller(int argc, WCHAR **wargv) { SetUnhandledExceptionFilter(&win32_exception_filter); - //- rjf: do OS layer initialization + //- rjf: dynamically load windows functions which are not guaranteed + // in all SDKs { - // 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 allow large pages if we can + B32 large_pages_allowed = 0; + { + HANDLE token; + if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { - 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)) { - 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); + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + large_pages_allowed = !!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) + } + + //- 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 = 1; - LARGE_INTEGER large_int_resolution; - if(QueryPerformanceFrequency(&large_int_resolution)) - { - os_w32_state.microsecond_resolution = large_int_resolution.QuadPart; - } + 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; - { - Temp 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); - { - Temp 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(); + } + { + 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->large_pages_allowed = large_pages_allowed; + info->pid = GetCurrentProcessId(); } //- rjf: extract arguments @@ -1620,13 +1683,89 @@ w32_entry_point_caller(int argc, WCHAR **wargv) { String16 arg16 = str16_cstring((U16 *)wargv[i]); String8 arg8 = str8_from_16(args_arena, arg16); - if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) + if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive) || + str8_match(arg8, str8_lit("-quiet"), StringMatchFlag_CaseInsensitive)) { win32_g_is_quiet = 1; } + if(str8_match(arg8, str8_lit("--large_pages"), StringMatchFlag_CaseInsensitive) || + str8_match(arg8, str8_lit("-large_pages"), StringMatchFlag_CaseInsensitive)) + { + arena_default_flags = ArenaFlag_LargePages; + arena_default_reserve_size = Max(MB(64), os_w32_state.system_info.large_page_size); + arena_default_commit_size = arena_default_reserve_size; + } argv[i] = (char *)arg8.str; } + //- 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; + { + Temp 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); + { + Temp 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: call into "real" entry point main_thread_base_entry_point(argc, argv); } diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h index a8c031fd..9a8f0d12 100644 --- a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h @@ -7,7 +7,6 @@ //////////////////////////////// //~ rjf: Includes / Libraries -#define WIN32_LEAN_AND_MEAN #include #include #include diff --git a/src/metagen/metagen_os/metagen_os_inc.h b/src/metagen/metagen_os/metagen_os_inc.h index f8c8e06c..b2d96f02 100644 --- a/src/metagen/metagen_os/metagen_os_inc.h +++ b/src/metagen/metagen_os/metagen_os_inc.h @@ -8,10 +8,6 @@ # define OS_FEATURE_GRAPHICAL 0 #endif -#if !defined(OS_GFX_STUB) -# define OS_GFX_STUB 0 -#endif - #include "metagen/metagen_os/core/metagen_os_core.h" #if OS_WINDOWS diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index bfd12c55..6cc494f0 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -473,11 +473,11 @@ internal B32 os_file_reserve_size(OS_Handle file, U64 size) { HANDLE handle = (HANDLE)file.u64[0]; - + FILE_ALLOCATION_INFO alloc_info = {0}; alloc_info.AllocationSize.LowPart = size & max_U32; alloc_info.AllocationSize.HighPart = (size >> 32) & max_U32; - + BOOL is_reserved = SetFileInformationByHandle(handle, FileAllocationInfo, &alloc_info, sizeof(alloc_info)); return is_reserved; } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index becfdf4e..a44b4bfd 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -4335,6 +4335,9 @@ rd_view_ui(Rng2F32 rect) // rjf: commit edited cell string switch(cell->kind) { + case RD_WatchCellKind_ViewUI: + case RD_WatchCellKind_CallStackFrame: + {}break; case RD_WatchCellKind_Expr: { RD_Cfg *cfg = row_info.group_cfg_child; @@ -10269,7 +10272,7 @@ rd_window_frame(void) } // rjf: draw sides - if(b->flags & UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight) + if(b->flags & (UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight)) { Vec4F32 border_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("border")); Rng2F32 r = b->rect;