From e61dfd793a56d31988cb917ed8c129f76a61430d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 15 Oct 2024 12:20:25 -0700 Subject: [PATCH] stdout redirection support in os command line launch helper; do rdi dumps in determinism test --- src/os/core/os_core.c | 38 +++++++++++- src/os/core/os_core.h | 28 ++++----- src/os/core/win32/os_core_win32.c | 19 +++++- src/tester/tester_main.c | 96 +++++++++++++++++++------------ 4 files changed, 128 insertions(+), 53 deletions(-) diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index 01b130dc..5613951a 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -163,16 +163,52 @@ os_cmd_line_launch(String8 string) 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) + { + 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 = parts; + params.cmd_line = cmdline; params.path = exe_folder; params.inherit_env = 1; + params.stdout_file = stdout_handle; handle = os_process_launch(¶ms); } scratch_end(scratch); diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index e062f5f5..4eed8c03 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -44,6 +44,7 @@ enum OS_AccessFlag_Append = (1<<3), OS_AccessFlag_ShareRead = (1<<4), OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Inherited = (1<<6), }; //////////////////////////////// @@ -79,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,6 +111,20 @@ struct OS_HandleArray U64 count; }; +//////////////////////////////// +//~ 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; + OS_Handle stdout_file; +}; + //////////////////////////////// //~ rjf: Globally Unique IDs diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 2bc1c8c3..c5f70c0d 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -293,14 +293,19 @@ os_file_open(OS_AccessFlags flags, String8 path) DWORD access_flags = 0; DWORD share_mode = 0; DWORD creation_disposition = OPEN_EXISTING; + 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;} - HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + 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; @@ -926,9 +931,17 @@ 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; + } 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); diff --git a/src/tester/tester_main.c b/src/tester/tester_main.c index 576acc0e..2f373718 100644 --- a/src/tester/tester_main.c +++ b/src/tester/tester_main.c @@ -44,59 +44,83 @@ entry_point(CmdLine *cmdline) B32 good = 1; String8List out = {0}; { - name = str8_lit("PDB -> RDI determinism"); - OS_HandleList processes = {0}; - String8List rdi_paths = {0}; + name = str8_lit("pdb2rdi_determinism"); U64 num_repeats_per_pdb = 4; String8 pdb_paths[] = { str8_lit_comp("odintest/test.pdb"), + str8_lit_comp("mule_main.pdb"), }; for EachElement(pdb_idx, pdb_paths) { + // rjf: unpack paths, make output directory String8 pdb_path = path_normalized_from_string(arena, pdb_paths[pdb_idx]); String8 pdb_folder = str8_chop_last_slash(pdb_path); - String8 repeat_folder = push_str8f(arena, "%S/pdb2rdi_determinism", pdb_folder); + String8 repeat_folder = push_str8f(arena, "%S/%S", pdb_folder, name); os_make_directory(repeat_folder); - for EachIndex(repeat_idx, num_repeats_per_pdb) + + // rjf: generate all RDIs + String8List rdi_paths = {0}; { - String8 rdi_path = push_str8f(arena, "%S/repeat_%I64u.rdi", repeat_folder, repeat_idx); - str8_list_push(arena, &rdi_paths, rdi_path); - os_handle_list_push(arena, &processes, os_cmd_line_launchf("rdi_from_pdb --pdb:%S --out:%S", pdb_path, rdi_path)); + OS_HandleList processes = {0}; + for EachIndex(repeat_idx, num_repeats_per_pdb) + { + String8 rdi_path = push_str8f(arena, "%S/repeat_%I64u.rdi", repeat_folder, repeat_idx); + str8_list_push(arena, &rdi_paths, rdi_path); + os_handle_list_push(arena, &processes, os_cmd_line_launchf("rdi_from_pdb --pdb:%S --out:%S", pdb_path, rdi_path)); + } + for(OS_HandleNode *n = processes.first; n != 0; n = n->next) + { + os_process_join(n->v, max_U64); + } } - }; - for(OS_HandleNode *n = processes.first; n != 0; n = n->next) - { - os_process_join(n->v, max_U64); - } - U64 hashes_count = rdi_paths.node_count; - U128 *hashes = push_array(arena, U128, hashes_count); - String8 *paths = push_array(arena, String8, hashes_count); - { - U64 idx = 0; - for(String8Node *n = rdi_paths.first; n != 0; n = n->next, idx += 1) + + // rjf: generate all dumps { - String8 path = n->string; - String8 data = os_data_from_file_path(arena, path); - hashes[idx] = hs_hash_from_data(data); - paths[idx] = path; + OS_HandleList processes = {0}; + for(String8Node *n = rdi_paths.first; n != 0; n = n->next) + { + String8 rdi_path = n->string; + String8 dump_path = push_str8f(arena, "%S.dump", rdi_path); + os_handle_list_push(arena, &processes, os_cmd_line_launchf("rdi_dump %S > %S", rdi_path, dump_path)); + } } - } - B32 matches = 1; - for EachIndex(idx, hashes_count) - { - if(!u128_match(hashes[idx], hashes[0])) + + // rjf: gather all hashes/paths + U64 hashes_count = rdi_paths.node_count; + U128 *hashes = push_array(arena, U128, hashes_count); + String8 *paths = push_array(arena, String8, hashes_count); { - matches = 0; - break; + U64 idx = 0; + for(String8Node *n = rdi_paths.first; n != 0; n = n->next, idx += 1) + { + String8 path = n->string; + String8 data = os_data_from_file_path(arena, path); + hashes[idx] = hs_hash_from_data(data); + paths[idx] = path; + } } - } - if(!matches) - { - good = 0; + + // rjf: determine if all hashes match + B32 matches = 1; for EachIndex(idx, hashes_count) { - str8_list_pushf(arena, &out, " [%I64u] (%S): 0x%I64x:%I64x\n", idx, paths[idx], hashes[idx].u64[0], hashes[idx].u64[1]); + if(!u128_match(hashes[idx], hashes[0])) + { + matches = 0; + break; + } + } + + // rjf: output bad case info + if(!matches) + { + good = 0; + str8_list_pushf(arena, &out, " pdb[%I64u] \"%S\"\n", pdb_idx, pdb_path); + for EachIndex(idx, hashes_count) + { + str8_list_pushf(arena, &out, " rdi[%I64u] \"%S\": 0x%I64x:%I64x\n", idx, paths[idx], hashes[idx].u64[0], hashes[idx].u64[1]); + } } } } @@ -104,7 +128,7 @@ entry_point(CmdLine *cmdline) ////////////////////////////// //- rjf: dump results // - fprintf(stderr, "[%s] %.*s\n", good ? "." : "X", str8_varg(name)); + fprintf(stderr, "[%s] \"%.*s\"\n", good ? "." : "X", str8_varg(name)); if(!good) { for(String8Node *n = out.first; n != 0; n = n->next)