From be9867e70d1c201525573babe1051e7b9b890f60 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 10 Nov 2022 15:31:16 -0800 Subject: [PATCH 01/34] Started the draft for the watch tower. --- .../cpp-corerun-watch-tower/CMakeLists.txt | 4 + src/native/cpp-corerun-watch-tower/Makefile | 178 ++++++++++++++++++ .../cpp-corerun-watch-tower/watchy-tower.cpp | 38 ++++ 3 files changed, 220 insertions(+) create mode 100644 src/native/cpp-corerun-watch-tower/CMakeLists.txt create mode 100644 src/native/cpp-corerun-watch-tower/Makefile create mode 100644 src/native/cpp-corerun-watch-tower/watchy-tower.cpp diff --git a/src/native/cpp-corerun-watch-tower/CMakeLists.txt b/src/native/cpp-corerun-watch-tower/CMakeLists.txt new file mode 100644 index 0000000000000..3418ff47c127b --- /dev/null +++ b/src/native/cpp-corerun-watch-tower/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.6.2) +project(WatchTower) +set(CMAKE_CXX_STANDARD 11) +add_executable(WatchTower watchy-tower.cpp) diff --git a/src/native/cpp-corerun-watch-tower/Makefile b/src/native/cpp-corerun-watch-tower/Makefile new file mode 100644 index 0000000000000..01d273efb01d7 --- /dev/null +++ b/src/native/cpp-corerun-watch-tower/Makefile @@ -0,0 +1,178 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.16 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E remove -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles/progress.marks + $(MAKE) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named WatchTower + +# Build rule for target. +WatchTower: cmake_check_build_system + $(MAKE) -f CMakeFiles/Makefile2 WatchTower +.PHONY : WatchTower + +# fast build rule for target. +WatchTower/fast: + $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/build +.PHONY : WatchTower/fast + +watchy-tower.o: watchy-tower.cpp.o + +.PHONY : watchy-tower.o + +# target to build an object file +watchy-tower.cpp.o: + $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.o +.PHONY : watchy-tower.cpp.o + +watchy-tower.i: watchy-tower.cpp.i + +.PHONY : watchy-tower.i + +# target to preprocess a source file +watchy-tower.cpp.i: + $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.i +.PHONY : watchy-tower.cpp.i + +watchy-tower.s: watchy-tower.cpp.s + +.PHONY : watchy-tower.s + +# target to generate assembly for a file +watchy-tower.cpp.s: + $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.s +.PHONY : watchy-tower.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... rebuild_cache" + @echo "... edit_cache" + @echo "... WatchTower" + @echo "... watchy-tower.o" + @echo "... watchy-tower.i" + @echo "... watchy-tower.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp new file mode 100644 index 0000000000000..b9117f25bc7ed --- /dev/null +++ b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp @@ -0,0 +1,38 @@ +// File: watchy-tower.cpp + +// Will replace these includes with Microsoft .NET's ones if necessary afterwards :) +#include +#include + +static void display_usage(); +static bool parse_args(const int, const char *[]); + +int main(const int argc, const char *argv[]) +{ + if (!parse_args(argc, argv)) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static void display_usage() +{ + fprintf(stderr, "Help will go here.\n"); + return ; +} + +static bool parse_args(const int argc, const char *argv[]) +{ + if (argc < 2) + { + display_usage(); + return false; + } + + for (int i = 1; i < argc; i++) + { + printf("%s\n", argv[i]); + } + + return true; +} From e79ae6678d68dfbcb2dc5417912c2efaf7694e9d Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 10 Nov 2022 16:47:54 -0800 Subject: [PATCH 02/34] Parsing command-line arguments done. --- .../cpp-corerun-watch-tower/watchy-tower.cpp | 72 +++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp index b9117f25bc7ed..0af2a8a3f4d82 100644 --- a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp +++ b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp @@ -3,15 +3,30 @@ // Will replace these includes with Microsoft .NET's ones if necessary afterwards :) #include #include +#include + +struct configuration +{ + configuration() = default; + + long int timeout; + const char *corerun_path; + const char *corerun_args; +}; static void display_usage(); -static bool parse_args(const int, const char *[]); +static bool parse_args(const int, const char *[], configuration&); int main(const int argc, const char *argv[]) { - if (!parse_args(argc, argv)) + configuration config {}; + + if (!parse_args(argc, argv, config)) return EXIT_FAILURE; + printf("Timeout Given: %ld\n", config.timeout); + printf("Corerun Path Given: %s\n", config.corerun_path); + printf("Corerun Arguments Given: %s\n", config.corerun_args); return EXIT_SUCCESS; } @@ -21,7 +36,7 @@ static void display_usage() return ; } -static bool parse_args(const int argc, const char *argv[]) +static bool parse_args(const int argc, const char *argv[], configuration& config) { if (argc < 2) { @@ -31,7 +46,56 @@ static bool parse_args(const int argc, const char *argv[]) for (int i = 1; i < argc; i++) { - printf("%s\n", argv[i]); + const char *arg = argv[i]; + // printf("%s\n", argv[i]); + + if (strcmp(arg, "-timeout") == 0 || strcmp(arg, "--timeout") == 0) + { + if (++i < argc) + { + config.timeout = strtol(argv[i], nullptr, 10); + } + else + { + fprintf(stderr, "Option '%s': Missing value in seconds.\n", arg); + return false; + } + } + else if (strcmp(arg, "-corerun") == 0 || strcmp(arg, "--corerun") == 0) + { + if (++i < argc) + { + config.corerun_path = argv[i]; + } + else + { + fprintf(stderr, "Option '%s': Missing path to corerun executable.\n", arg); + return false; + } + } + else if (strcmp(arg, "-args") == 0 || strcmp(arg, "--args") == 0) + { + if (++i < argc) + { + config.corerun_args = argv[i]; + } + else + { + fprintf(stderr, "Option '%s': Missing arguments for corerun.\n", arg); + return false; + } + } + else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--h") == 0 || strcmp(arg, "-?") == 0) + { + display_usage(); + return true; + } + else + { + fprintf(stderr, "Unknown option '%s'.\n", arg); + return false; + } + } return true; From b17eef22b2ac89853d1c7704eb285d09308b99b0 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 10 Nov 2022 16:50:11 -0800 Subject: [PATCH 03/34] Removed auto-generated file. --- src/native/cpp-corerun-watch-tower/Makefile | 178 -------------------- 1 file changed, 178 deletions(-) delete mode 100644 src/native/cpp-corerun-watch-tower/Makefile diff --git a/src/native/cpp-corerun-watch-tower/Makefile b/src/native/cpp-corerun-watch-tower/Makefile deleted file mode 100644 index 01d273efb01d7..0000000000000 --- a/src/native/cpp-corerun-watch-tower/Makefile +++ /dev/null @@ -1,178 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.16 - -# Default target executed when no arguments are given to make. -default_target: all - -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - - -# Remove some rules from gmake that .SUFFIXES does not remove. -SUFFIXES = - -.SUFFIXES: .hpux_make_needs_suffix_list - - -# Suppress display of executed commands. -$(VERBOSE).SILENT: - - -# A target that is always out of date. -cmake_force: - -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /usr/bin/cmake - -# The command to remove a file. -RM = /usr/bin/cmake -E remove -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." - /usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache - -.PHONY : rebuild_cache/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." - /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache - -.PHONY : edit_cache/fast - -# The main all target -all: cmake_check_build_system - $(CMAKE_COMMAND) -E cmake_progress_start /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles/progress.marks - $(MAKE) -f CMakeFiles/Makefile2 all - $(CMAKE_COMMAND) -E cmake_progress_start /media/ivdiazsa/DataDrive/Development/repos/for-experiments/cpp-corerun-watch-tower/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - $(MAKE) -f CMakeFiles/Makefile2 clean -.PHONY : clean - -# The main clean target -clean/fast: clean - -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - $(MAKE) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - $(MAKE) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -#============================================================================= -# Target rules for targets named WatchTower - -# Build rule for target. -WatchTower: cmake_check_build_system - $(MAKE) -f CMakeFiles/Makefile2 WatchTower -.PHONY : WatchTower - -# fast build rule for target. -WatchTower/fast: - $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/build -.PHONY : WatchTower/fast - -watchy-tower.o: watchy-tower.cpp.o - -.PHONY : watchy-tower.o - -# target to build an object file -watchy-tower.cpp.o: - $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.o -.PHONY : watchy-tower.cpp.o - -watchy-tower.i: watchy-tower.cpp.i - -.PHONY : watchy-tower.i - -# target to preprocess a source file -watchy-tower.cpp.i: - $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.i -.PHONY : watchy-tower.cpp.i - -watchy-tower.s: watchy-tower.cpp.s - -.PHONY : watchy-tower.s - -# target to generate assembly for a file -watchy-tower.cpp.s: - $(MAKE) -f CMakeFiles/WatchTower.dir/build.make CMakeFiles/WatchTower.dir/watchy-tower.cpp.s -.PHONY : watchy-tower.cpp.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... rebuild_cache" - @echo "... edit_cache" - @echo "... WatchTower" - @echo "... watchy-tower.o" - @echo "... watchy-tower.i" - @echo "... watchy-tower.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - From d40ad9eaee4ae284dfdf78185a35f329e445e735 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 11 Nov 2022 16:32:40 -0800 Subject: [PATCH 04/34] Added an example I made on how to run processes from C/C++ :) --- .../cpp-corerun-watch-tower/watchy-tower.cpp | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp index 0af2a8a3f4d82..ca2d9d73f8212 100644 --- a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp +++ b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp @@ -95,8 +95,90 @@ static bool parse_args(const int argc, const char *argv[], configuration& config fprintf(stderr, "Unknown option '%s'.\n", arg); return false; } + } + return true; +} + +/* Little example of forking a child process, and finishing it instantly if it + * takes longer than a certain amount of time. + +#include +#include +#include +#include +#include +#include +#include + +int run_timed_process(const long, const int, const char *[]); + +int main(const int argc, const char *argv[]) +{ + int result = run_timed_process(3000L, argc-1, &argv[1]); + printf("App Exit Code: %d\n", result); + return 0; +} + +int run_timed_process(const long timeout_ms, const int program_argc, const char *program_argv[]) +{ +// for (int i = 0; i < program_argc; i++) +// printf("Argv[%d] = %s\n", i, program_argv[i]); +// + const int check_interval = 1000; + int check_count = 0; + char *args[program_argc]; + + pid_t child_pid; + int child_status; + int w; + + for (int i = 0; i < program_argc; i++) + { + args[i] = (char *)program_argv[i]; + } + + printf("Forking!\n"); + child_pid = fork(); + + if (child_pid < 0) + { + // Fork failed. No memory remaining available :( + printf("Fork failed... Returning ENOMEM.\n"); + return ENOMEM; + } + else if (child_pid == 0) + { + // Instructions for child process! + printf("Fork successful! Running child process now...\n"); + execv(args[0], &args[0]); + _exit(EXIT_FAILURE); + } + else + { + do + { + // Instructions for the parent process! + w = waitpid(child_pid, &child_status, WNOHANG); + + if (w == -1) + return EINVAL; + + usleep(check_interval * 1000); + if (w) + { + if (WIFEXITED(child_status)) + { + printf("Child process exited by signal %d.\n", WEXITSTATUS(child_status)); + return WEXITSTATUS(child_status); + } + } + } while (check_count++ < (timeout_ms / check_interval)); } - return true; + printf("Child process took too long. Timed out... Exiting...\n"); + kill(child_pid, SIGKILL); + return ETIMEDOUT; } + +*/ From 6cc9e9eabe707e995ff164074b745e283c764b67 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 15 Nov 2022 16:20:20 -0800 Subject: [PATCH 05/34] Perfect arg parsing done! --- .../cpp-corerun-watch-tower/watchy-tower.cpp | 106 +++++++++--------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp index ca2d9d73f8212..5fd7be88e7365 100644 --- a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp +++ b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp @@ -4,6 +4,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include struct configuration { @@ -11,11 +17,12 @@ struct configuration long int timeout; const char *corerun_path; - const char *corerun_args; + std::vector corerun_argv; }; static void display_usage(); static bool parse_args(const int, const char *[], configuration&); +static int run_timed_process(configuration&); int main(const int argc, const char *argv[]) { @@ -24,9 +31,13 @@ int main(const int argc, const char *argv[]) if (!parse_args(argc, argv, config)) return EXIT_FAILURE; + // These printf's are just for general info during development. They will + // be removed before merging the PR. printf("Timeout Given: %ld\n", config.timeout); printf("Corerun Path Given: %s\n", config.corerun_path); - printf("Corerun Arguments Given: %s\n", config.corerun_args); + printf("Corerun Arguments Given:\n"); + int r = run_timed_process(config); + printf("%d\n", r); return EXIT_SUCCESS; } @@ -75,14 +86,13 @@ static bool parse_args(const int argc, const char *argv[], configuration& config } else if (strcmp(arg, "-args") == 0 || strcmp(arg, "--args") == 0) { - if (++i < argc) + // The args flag has to come last, since we can't know beforehand + // how many of the following arguments belong to this flag. So, making + // it last-only, we can assume it's until we're done processing + // the argument vector. + while (++i < argc) { - config.corerun_args = argv[i]; - } - else - { - fprintf(stderr, "Option '%s': Missing arguments for corerun.\n", arg); - return false; + config.corerun_argv.push_back(argv[i]); } } else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--h") == 0 || strcmp(arg, "-?") == 0) @@ -99,86 +109,82 @@ static bool parse_args(const int argc, const char *argv[], configuration& config return true; } -/* Little example of forking a child process, and finishing it instantly if it - * takes longer than a certain amount of time. - -#include -#include -#include -#include -#include -#include -#include - -int run_timed_process(const long, const int, const char *[]); - -int main(const int argc, const char *argv[]) -{ - int result = run_timed_process(3000L, argc-1, &argv[1]); - printf("App Exit Code: %d\n", result); - return 0; -} - -int run_timed_process(const long timeout_ms, const int program_argc, const char *program_argv[]) +static int run_timed_process(configuration& config) { -// for (int i = 0; i < program_argc; i++) -// printf("Argv[%d] = %s\n", i, program_argv[i]); -// - const int check_interval = 1000; + const int check_interval_ms = 1000; int check_count = 0; - char *args[program_argc]; + int corerun_argc = config.corerun_argv.size(); + + // Since our corerun_argv only contains the actual arguments to corerun, + // but the execv() call expects a list including the name of the executable, + // we make an additional slot in our list to add it. + char *program_args[corerun_argc + 1]; + program_args[0] = (char *) config.corerun_path; pid_t child_pid; int child_status; int w; - for (int i = 0; i < program_argc; i++) + // The calls to execute child processes require a char * array. + for (int i = 0; i < corerun_argc; i++) { - args[i] = (char *)program_argv[i]; + // We're using index+1 to account for the corerun executable path stored + // at index 0. + program_args[i+1] = (char *) config.corerun_argv.at(i); } - printf("Forking!\n"); + for (int j = 0; j <= corerun_argc; j++) + printf("At [%d]: %s\n", j, program_args[j]); + return 100; + child_pid = fork(); if (child_pid < 0) { - // Fork failed. No memory remaining available :( - printf("Fork failed... Returning ENOMEM.\n"); + // Fork failed. No memory available. + printf("Fork failed... Out of memory.\n"); return ENOMEM; } else if (child_pid == 0) { - // Instructions for child process! - printf("Fork successful! Running child process now...\n"); - execv(args[0], &args[0]); + // Instructions for the child process! + + // Run the test binary and exit unsuccessfully if it's killed or dies for + // whatever reason. + execv(program_args[0], &program_args[0]); _exit(EXIT_FAILURE); } else { + // Instructions for the parent process! + + // Wait for the child process (running test) to finish, while keeping + // track of how long it's been running. do { - // Instructions for the parent process! w = waitpid(child_pid, &child_status, WNOHANG); + // Something went very wrong. if (w == -1) return EINVAL; - usleep(check_interval * 1000); + // Wait a bit before checking the test process' status again. + // Usleep() takes its argument in microseconds, hence we multiply + // by 1000 our interval in milliseconds. + usleep(check_interval_ms * 1000); if (w) { if (WIFEXITED(child_status)) { - printf("Child process exited by signal %d.\n", WEXITSTATUS(child_status)); + // Our test run completed successfully. return WEXITSTATUS(child_status); } } - } while (check_count++ < (timeout_ms / check_interval)); + } while (check_count++ < (config.timeout / check_interval_ms)); } - printf("Child process took too long. Timed out... Exiting...\n"); + printf("Test process took too long to complete, and timed out.\n"); kill(child_pid, SIGKILL); return ETIMEDOUT; } - -*/ From fcd9f1ab7aacc0dda6eb398f6fe05ce17b0749d9 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 15 Nov 2022 16:27:45 -0800 Subject: [PATCH 06/34] Seems to be working? --- src/native/cpp-corerun-watch-tower/watchy-tower.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp index 5fd7be88e7365..f584cb4d1831d 100644 --- a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp +++ b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp @@ -36,8 +36,8 @@ int main(const int argc, const char *argv[]) printf("Timeout Given: %ld\n", config.timeout); printf("Corerun Path Given: %s\n", config.corerun_path); printf("Corerun Arguments Given:\n"); - int r = run_timed_process(config); - printf("%d\n", r); + int exit_code = run_timed_process(config); + printf("Test Process exited with code: %d\n", exit_code); return EXIT_SUCCESS; } @@ -133,10 +133,6 @@ static int run_timed_process(configuration& config) program_args[i+1] = (char *) config.corerun_argv.at(i); } - for (int j = 0; j <= corerun_argc; j++) - printf("At [%d]: %s\n", j, program_args[j]); - return 100; - child_pid = fork(); if (child_pid < 0) @@ -151,6 +147,7 @@ static int run_timed_process(configuration& config) // Run the test binary and exit unsuccessfully if it's killed or dies for // whatever reason. + printf("Aboutta execute test\n"); execv(program_args[0], &program_args[0]); _exit(EXIT_FAILURE); } @@ -163,6 +160,7 @@ static int run_timed_process(configuration& config) do { w = waitpid(child_pid, &child_status, WNOHANG); + printf("Waiting...\n"); // Something went very wrong. if (w == -1) @@ -178,6 +176,7 @@ static int run_timed_process(configuration& config) if (WIFEXITED(child_status)) { // Our test run completed successfully. + printf("Exited successfully...\n"); return WEXITSTATUS(child_status); } } From 1c7f46c88baac69279e994e29b415071040ec456 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 16 Nov 2022 16:03:38 -0800 Subject: [PATCH 07/34] Watchdog is functional now! --- .../cpp-corerun-watch-tower/watchy-tower.cpp | 189 ------------------ .../CMakeLists.txt | 4 +- src/native/watchdog/watchdog.cpp | 88 ++++++++ 3 files changed, 90 insertions(+), 191 deletions(-) delete mode 100644 src/native/cpp-corerun-watch-tower/watchy-tower.cpp rename src/native/{cpp-corerun-watch-tower => watchdog}/CMakeLists.txt (50%) create mode 100644 src/native/watchdog/watchdog.cpp diff --git a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp b/src/native/cpp-corerun-watch-tower/watchy-tower.cpp deleted file mode 100644 index f584cb4d1831d..0000000000000 --- a/src/native/cpp-corerun-watch-tower/watchy-tower.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// File: watchy-tower.cpp - -// Will replace these includes with Microsoft .NET's ones if necessary afterwards :) -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct configuration -{ - configuration() = default; - - long int timeout; - const char *corerun_path; - std::vector corerun_argv; -}; - -static void display_usage(); -static bool parse_args(const int, const char *[], configuration&); -static int run_timed_process(configuration&); - -int main(const int argc, const char *argv[]) -{ - configuration config {}; - - if (!parse_args(argc, argv, config)) - return EXIT_FAILURE; - - // These printf's are just for general info during development. They will - // be removed before merging the PR. - printf("Timeout Given: %ld\n", config.timeout); - printf("Corerun Path Given: %s\n", config.corerun_path); - printf("Corerun Arguments Given:\n"); - int exit_code = run_timed_process(config); - printf("Test Process exited with code: %d\n", exit_code); - return EXIT_SUCCESS; -} - -static void display_usage() -{ - fprintf(stderr, "Help will go here.\n"); - return ; -} - -static bool parse_args(const int argc, const char *argv[], configuration& config) -{ - if (argc < 2) - { - display_usage(); - return false; - } - - for (int i = 1; i < argc; i++) - { - const char *arg = argv[i]; - // printf("%s\n", argv[i]); - - if (strcmp(arg, "-timeout") == 0 || strcmp(arg, "--timeout") == 0) - { - if (++i < argc) - { - config.timeout = strtol(argv[i], nullptr, 10); - } - else - { - fprintf(stderr, "Option '%s': Missing value in seconds.\n", arg); - return false; - } - } - else if (strcmp(arg, "-corerun") == 0 || strcmp(arg, "--corerun") == 0) - { - if (++i < argc) - { - config.corerun_path = argv[i]; - } - else - { - fprintf(stderr, "Option '%s': Missing path to corerun executable.\n", arg); - return false; - } - } - else if (strcmp(arg, "-args") == 0 || strcmp(arg, "--args") == 0) - { - // The args flag has to come last, since we can't know beforehand - // how many of the following arguments belong to this flag. So, making - // it last-only, we can assume it's until we're done processing - // the argument vector. - while (++i < argc) - { - config.corerun_argv.push_back(argv[i]); - } - } - else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--h") == 0 || strcmp(arg, "-?") == 0) - { - display_usage(); - return true; - } - else - { - fprintf(stderr, "Unknown option '%s'.\n", arg); - return false; - } - } - return true; -} - -static int run_timed_process(configuration& config) -{ - const int check_interval_ms = 1000; - int check_count = 0; - int corerun_argc = config.corerun_argv.size(); - - // Since our corerun_argv only contains the actual arguments to corerun, - // but the execv() call expects a list including the name of the executable, - // we make an additional slot in our list to add it. - char *program_args[corerun_argc + 1]; - program_args[0] = (char *) config.corerun_path; - - pid_t child_pid; - int child_status; - int w; - - // The calls to execute child processes require a char * array. - for (int i = 0; i < corerun_argc; i++) - { - // We're using index+1 to account for the corerun executable path stored - // at index 0. - program_args[i+1] = (char *) config.corerun_argv.at(i); - } - - child_pid = fork(); - - if (child_pid < 0) - { - // Fork failed. No memory available. - printf("Fork failed... Out of memory.\n"); - return ENOMEM; - } - else if (child_pid == 0) - { - // Instructions for the child process! - - // Run the test binary and exit unsuccessfully if it's killed or dies for - // whatever reason. - printf("Aboutta execute test\n"); - execv(program_args[0], &program_args[0]); - _exit(EXIT_FAILURE); - } - else - { - // Instructions for the parent process! - - // Wait for the child process (running test) to finish, while keeping - // track of how long it's been running. - do - { - w = waitpid(child_pid, &child_status, WNOHANG); - printf("Waiting...\n"); - - // Something went very wrong. - if (w == -1) - return EINVAL; - - // Wait a bit before checking the test process' status again. - // Usleep() takes its argument in microseconds, hence we multiply - // by 1000 our interval in milliseconds. - usleep(check_interval_ms * 1000); - - if (w) - { - if (WIFEXITED(child_status)) - { - // Our test run completed successfully. - printf("Exited successfully...\n"); - return WEXITSTATUS(child_status); - } - } - } while (check_count++ < (config.timeout / check_interval_ms)); - } - - printf("Test process took too long to complete, and timed out.\n"); - kill(child_pid, SIGKILL); - return ETIMEDOUT; -} diff --git a/src/native/cpp-corerun-watch-tower/CMakeLists.txt b/src/native/watchdog/CMakeLists.txt similarity index 50% rename from src/native/cpp-corerun-watch-tower/CMakeLists.txt rename to src/native/watchdog/CMakeLists.txt index 3418ff47c127b..24f6a1fb11d38 100644 --- a/src/native/cpp-corerun-watch-tower/CMakeLists.txt +++ b/src/native/watchdog/CMakeLists.txt @@ -1,4 +1,4 @@ cmake_minimum_required(VERSION 3.6.2) -project(WatchTower) +project(watchdog) set(CMAKE_CXX_STANDARD 11) -add_executable(WatchTower watchy-tower.cpp) +add_executable(watchdog watchdog.cpp) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp new file mode 100644 index 0000000000000..a5d06184305fe --- /dev/null +++ b/src/native/watchdog/watchdog.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include + +int run_timed_process(const long, const int, const char *[]); + +int main(const int argc, const char *argv[]) +{ + if (argc < 3) + { + printf("There are missing arguments. Got %d instead of 3+ :(\n", argc); + return EXIT_FAILURE; + } + + const long timeout_ms = strtol(argv[1], nullptr, 10); + int exit_code = run_timed_process(timeout_ms, argc-2, &argv[2]); + + printf("App Exit Code: %d\n", exit_code); + return EXIT_SUCCESS; +} + +int run_timed_process(const long timeout, const int exe_argc, const char *exe_path_and_argv[]) +{ + const int check_interval = 1000; + int check_count = 0; + char *args[exe_argc]; + + pid_t child_pid; + int child_status; + int wait_code; + + for (int i = 0; i < exe_argc; i++) + { + args[i] = (char *) exe_path_and_argv[i]; + } + + // This is just for development. Will remove it when it's ready to be submitted :) + for (int j = 0; j < exe_argc; j++) + { + printf("[%d]: %s\n", j, args[j]); + } + + child_pid = fork(); + + if (child_pid < 0) + { + printf("Fork failed... No memory available.\n"); + return ENOMEM; + } + else if (child_pid == 0) + { + printf("Running child process...\n"); + execv(args[0], &args[0]); + } + else + { + do + { + wait_code = waitpid(child_pid, &child_status, WNOHANG); + + // Something went terribly wrong. + if (wait_code == -1) + return EINVAL; + + // Passing ms * 1000 because usleep() receives its parameter in microseconds. + usleep(check_interval * 1000); + + if (wait_code) + { + if (WIFEXITED(child_status)) + { + printf("Child process exited successfully with status %d.\n", + WEXITSTATUS(child_status)); + return WEXITSTATUS(child_status); + } + } + } while (check_count++ < (timeout / check_interval)); + } + + printf("Child process took too long and timed out... Exiting it...\n"); + kill(child_pid, SIGKILL); + return ETIMEDOUT; +} + From ec90d1e38312ad4496fa3cce798943db75d2c3f4 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Mon, 21 Nov 2022 18:11:21 -0800 Subject: [PATCH 08/34] Fixed a nuisance with the Windows compiler messing with Linux code, but now gotta convert a whole char ** to a char *. --- src/native/watchdog/watchdog.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index a5d06184305fe..5474cf20fafa8 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -1,10 +1,15 @@ #include #include #include -#include #include #include + +#ifdef _WIN32 +#include +#else +#include #include +#endif int run_timed_process(const long, const int, const char *[]); @@ -25,9 +30,31 @@ int main(const int argc, const char *argv[]) int run_timed_process(const long timeout, const int exe_argc, const char *exe_path_and_argv[]) { + // We somehow need to convert the whole command-line to a single string for Windows :| +#ifdef _WIN32 + STARTUPINFO startupInfo; + PROCESS_INFORMATION procInfo; + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + ZeroMemory(&procInfo, sizeof(procInfo)); + + if (!CreateProcess(NULL, "cmdline", NULL, NULL, FALSE, 0, NULL, NULL, + &startupInfo, &procInfo)) + { + int error_code = GetLastError(); + printf("Process creation failed... Code %d.\n", error_code); + return error_code; + } + + WaitForSingleObject(procInfo.hProcess, timeout); + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); + +#else const int check_interval = 1000; int check_count = 0; - char *args[exe_argc]; + char **args = new char *[exe_argc]; pid_t child_pid; int child_status; @@ -83,6 +110,7 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa printf("Child process took too long and timed out... Exiting it...\n"); kill(child_pid, SIGKILL); +#endif return ETIMEDOUT; } From b157904ab3672d023656b7dc53345d025562d794 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 22 Nov 2022 16:33:26 -0800 Subject: [PATCH 09/34] Got the Windows draft working, at long last. --- src/native/watchdog/watchdog.cpp | 34 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 5474cf20fafa8..6677863224300 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -6,6 +6,7 @@ #ifdef _WIN32 #include +#include #else #include #include @@ -30,26 +31,37 @@ int main(const int argc, const char *argv[]) int run_timed_process(const long timeout, const int exe_argc, const char *exe_path_and_argv[]) { - // We somehow need to convert the whole command-line to a single string for Windows :| #ifdef _WIN32 - STARTUPINFO startupInfo; - PROCESS_INFORMATION procInfo; + std::string cmdline(exe_path_and_argv[0]); - ZeroMemory(&startupInfo, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); - ZeroMemory(&procInfo, sizeof(procInfo)); + for (int i = 1; i < exe_argc; i++) + { + cmdline.append(" "); + cmdline.append(exe_path_and_argv[i]); + } + + STARTUPINFO startup_info; + PROCESS_INFORMATION proc_info; + int exit_code; - if (!CreateProcess(NULL, "cmdline", NULL, NULL, FALSE, 0, NULL, NULL, - &startupInfo, &procInfo)) + ZeroMemory(&startup_info, sizeof(startup_info)); + startup_info.cb = sizeof(startup_info); + ZeroMemory(&proc_info, sizeof(proc_info)); + + if (!CreateProcess(NULL, &cmdline[0], NULL, NULL, FALSE, 0, NULL, NULL, + &startup_info, &proc_info)) { int error_code = GetLastError(); printf("Process creation failed... Code %d.\n", error_code); return error_code; } - WaitForSingleObject(procInfo.hProcess, timeout); - CloseHandle(procInfo.hProcess); - CloseHandle(procInfo.hThread); + WaitForSingleObject(proc_info.hProcess, timeout); + GetExitCodeProcess(proc_info.hProcess, &exit_code); + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + return exit_code; #else const int check_interval = 1000; From 36a75f08834b12cae6f29a3c014c29cb7eeea346 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Mon, 5 Dec 2022 17:17:00 -0800 Subject: [PATCH 10/34] Added initial linking of the watcher to the repo's build scripts. Not yet functional, but gotta save my progress :) --- eng/Subsets.props | 5 ++++ src/native/watchdog/CMakeLists.txt | 22 ++++++++++++++ src/native/watchdog/build-watchdog.sh | 4 +++ src/native/watchdog/build.proj | 41 +++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100755 src/native/watchdog/build-watchdog.sh create mode 100644 src/native/watchdog/build.proj diff --git a/eng/Subsets.props b/eng/Subsets.props index 9e666f71fe0a6..24cc5fbc995a8 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -149,6 +149,7 @@ + @@ -387,6 +388,10 @@ + + + + diff --git a/src/native/watchdog/CMakeLists.txt b/src/native/watchdog/CMakeLists.txt index 24f6a1fb11d38..c6d5e7329f4c5 100644 --- a/src/native/watchdog/CMakeLists.txt +++ b/src/native/watchdog/CMakeLists.txt @@ -1,4 +1,26 @@ cmake_minimum_required(VERSION 3.6.2) + +if (CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) + # CMake 3.14.5 contains bug fixes for iOS + cmake_minimum_required(VERSION 3.14.5) +elseif (CLR_CMAKE_TARGET_MACCATALYST) + # CMake 3.18.1 properly generates MacCatalyst C compiler + cmake_minimum_required(VERSION 3.18.1) +endif () + +if (WIN32) + cmake_policy(SET CMP0091 NEW) +else () + cmake_policy(SET CMP0042 NEW) +endif () + project(watchdog) + +include(../../../eng/native/configurepaths.cmake) +include(${CLR_ENG_NATIVE_DIR}/configurecompiler.cmake) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) + add_executable(watchdog watchdog.cpp) + diff --git a/src/native/watchdog/build-watchdog.sh b/src/native/watchdog/build-watchdog.sh new file mode 100755 index 0000000000000..77c0e94d58962 --- /dev/null +++ b/src/native/watchdog/build-watchdog.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo "Called build script successfully!" + diff --git a/src/native/watchdog/build.proj b/src/native/watchdog/build.proj new file mode 100644 index 0000000000000..3b5027911ac2d --- /dev/null +++ b/src/native/watchdog/build.proj @@ -0,0 +1,41 @@ + + + + .NET Tests Watchdog + <_BuildGeneralArgs>-arch $(TargetArchitecture) -c $(Configuration) -os $(TargetOS) + + + + + + + + + <_CMakeArgs Condition="'$(CMakeArgs)' != ''"> $(CMakeArgs) + <_BuildUnixArgs>$(_BuildGeneralArgs)$(_CMakeArgs) + + + + + + + + + + + + + + <_BuildWindowsArgs>$(_BuildGeneralArgs) + <_BuildWindowsArgs Condition="'$(Ninja)' == 'false'">$(_BuildWindowsArgs) msbuild + + + + + + + + + From c4f20098a420c8d5bac424fb91a8715874183bd8 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 6 Dec 2022 15:30:36 -0800 Subject: [PATCH 11/34] Moved the watcher to the CoreCLR project. Not yet functional though... --- eng/Subsets.props | 5 ---- src/coreclr/CMakeLists.txt | 6 ++++ src/native/watchdog/CMakeLists.txt | 26 +---------------- src/native/watchdog/build-watchdog.sh | 4 --- src/native/watchdog/build.proj | 41 --------------------------- src/native/watchdog/watchdog.cpp | 6 ++-- 6 files changed, 10 insertions(+), 78 deletions(-) delete mode 100755 src/native/watchdog/build-watchdog.sh delete mode 100644 src/native/watchdog/build.proj diff --git a/eng/Subsets.props b/eng/Subsets.props index 24cc5fbc995a8..9e666f71fe0a6 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -149,7 +149,6 @@ - @@ -388,10 +387,6 @@ - - - - diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index c28c30514832d..4504575e04cec 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -113,6 +113,11 @@ else() endif() endif() +#---------------------------------------------------- +# Build the test watchdog alongside the CLR +#---------------------------------------------------- +include("${CLR_SRC_NATIVE_DIR}/watchdog/CMakeLists.txt") + # Add this subdir. We install the headers for the jit. add_subdirectory(pal/prebuilt/inc) @@ -264,3 +269,4 @@ endif(CLR_CMAKE_HOST_WIN32) if(CLR_CROSS_COMPONENTS_BUILD) include(crosscomponents.cmake) endif(CLR_CROSS_COMPONENTS_BUILD) + diff --git a/src/native/watchdog/CMakeLists.txt b/src/native/watchdog/CMakeLists.txt index c6d5e7329f4c5..541e524225fd3 100644 --- a/src/native/watchdog/CMakeLists.txt +++ b/src/native/watchdog/CMakeLists.txt @@ -1,26 +1,2 @@ -cmake_minimum_required(VERSION 3.6.2) - -if (CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) - # CMake 3.14.5 contains bug fixes for iOS - cmake_minimum_required(VERSION 3.14.5) -elseif (CLR_CMAKE_TARGET_MACCATALYST) - # CMake 3.18.1 properly generates MacCatalyst C compiler - cmake_minimum_required(VERSION 3.18.1) -endif () - -if (WIN32) - cmake_policy(SET CMP0091 NEW) -else () - cmake_policy(SET CMP0042 NEW) -endif () - -project(watchdog) - -include(../../../eng/native/configurepaths.cmake) -include(${CLR_ENG_NATIVE_DIR}/configurecompiler.cmake) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_CXX_STANDARD 11) - -add_executable(watchdog watchdog.cpp) +add_executable(watchdog ${CMAKE_CURRENT_LIST_DIR}/watchdog.cpp) diff --git a/src/native/watchdog/build-watchdog.sh b/src/native/watchdog/build-watchdog.sh deleted file mode 100755 index 77c0e94d58962..0000000000000 --- a/src/native/watchdog/build-watchdog.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -echo "Called build script successfully!" - diff --git a/src/native/watchdog/build.proj b/src/native/watchdog/build.proj deleted file mode 100644 index 3b5027911ac2d..0000000000000 --- a/src/native/watchdog/build.proj +++ /dev/null @@ -1,41 +0,0 @@ - - - - .NET Tests Watchdog - <_BuildGeneralArgs>-arch $(TargetArchitecture) -c $(Configuration) -os $(TargetOS) - - - - - - - - - <_CMakeArgs Condition="'$(CMakeArgs)' != ''"> $(CMakeArgs) - <_BuildUnixArgs>$(_BuildGeneralArgs)$(_CMakeArgs) - - - - - - - - - - - - - - <_BuildWindowsArgs>$(_BuildGeneralArgs) - <_BuildWindowsArgs Condition="'$(Ninja)' == 'false'">$(_BuildWindowsArgs) msbuild - - - - - - - - - diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 6677863224300..a09a51a430ff4 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #include From e8b13a530f29758df073672cd8a529481ff24d1f Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 6 Dec 2022 16:54:59 -0800 Subject: [PATCH 12/34] Got it to build on Windows! --- src/native/watchdog/watchdog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index a09a51a430ff4..420ee4e134293 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -40,15 +40,15 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa cmdline.append(exe_path_and_argv[i]); } - STARTUPINFO startup_info; + STARTUPINFOA startup_info; PROCESS_INFORMATION proc_info; - int exit_code; + unsigned long exit_code; ZeroMemory(&startup_info, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); ZeroMemory(&proc_info, sizeof(proc_info)); - if (!CreateProcess(NULL, &cmdline[0], NULL, NULL, FALSE, 0, NULL, NULL, + if (!CreateProcessA(NULL, &cmdline[0], NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &proc_info)) { int error_code = GetLastError(); From b476ad225a39a1bddaabb19be49cd0e6d11077ba Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 7 Dec 2022 14:20:04 -0800 Subject: [PATCH 13/34] Builds and Works on Linux! --- src/coreclr/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 4504575e04cec..bf725ef11f1d4 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -116,7 +116,7 @@ endif() #---------------------------------------------------- # Build the test watchdog alongside the CLR #---------------------------------------------------- -include("${CLR_SRC_NATIVE_DIR}/watchdog/CMakeLists.txt") +add_subdirectory("${CLR_SRC_NATIVE_DIR}/watchdog" test-watchdog) # Add this subdir. We install the headers for the jit. add_subdirectory(pal/prebuilt/inc) From f74fb2ebac0894f9974439718c973b44a40c0b6c Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 8 Dec 2022 14:03:56 -0800 Subject: [PATCH 14/34] Fixed a slowdown with the watcher. --- src/native/watchdog/watchdog.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 420ee4e134293..852ae5178d492 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -26,7 +26,7 @@ int main(const int argc, const char *argv[]) int exit_code = run_timed_process(timeout_ms, argc-2, &argv[2]); printf("App Exit Code: %d\n", exit_code); - return EXIT_SUCCESS; + return exit_code; } int run_timed_process(const long timeout, const int exe_argc, const char *exe_path_and_argv[]) @@ -105,8 +105,9 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa if (wait_code == -1) return EINVAL; - // Passing ms * 1000 because usleep() receives its parameter in microseconds. - usleep(check_interval * 1000); + // TODO: Explain why we are multiplying by 25 here, and dividing + // by 40 in the while clause. + usleep(check_interval * 25); if (wait_code) { @@ -117,7 +118,7 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa return WEXITSTATUS(child_status); } } - } while (check_count++ < (timeout / check_interval)); + } while (check_count++ < ((timeout / check_interval) * 40)); } printf("Child process took too long and timed out... Exiting it...\n"); From 958dc2988c5c0e74f48ddfdfe5fb7039d2368fe8 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 8 Dec 2022 14:08:58 -0800 Subject: [PATCH 15/34] Forgot to not leak memory :) --- src/native/watchdog/watchdog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 852ae5178d492..f295b6ea68288 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -123,6 +123,7 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa printf("Child process took too long and timed out... Exiting it...\n"); kill(child_pid, SIGKILL); + free(args); #endif return ETIMEDOUT; } From 67e25fecdc7aa463517881a924fd4a64ab0fa738 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 8 Dec 2022 14:18:30 -0800 Subject: [PATCH 16/34] This is C++, not C. --- src/native/watchdog/watchdog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index f295b6ea68288..8a767a43fed95 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -123,7 +123,7 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa printf("Child process took too long and timed out... Exiting it...\n"); kill(child_pid, SIGKILL); - free(args); + delete[] args; // Don't leak memory :) #endif return ETIMEDOUT; } From 7ef09b2f24ee0168d793c29de89842dbd7fee4ae Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 13 Dec 2022 17:52:26 -0800 Subject: [PATCH 17/34] Bash scripts now call the watcher, but watcher still crashes when built with MSBuild... --- src/native/watchdog/watchdog.cpp | 58 ++++++++++--------- src/tests/Common/CLRTest.Execute.Bash.targets | 24 ++++++-- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 8a767a43fed95..5ebba3dd0a1a2 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -1,6 +1,5 @@ -#include -#include -#include +#include +#include #include #include @@ -8,8 +7,10 @@ #include #include #else -#include +#include #include +#include +#include #endif int run_timed_process(const long, const int, const char *[]); @@ -22,14 +23,14 @@ int main(const int argc, const char *argv[]) return EXIT_FAILURE; } - const long timeout_ms = strtol(argv[1], nullptr, 10); - int exit_code = run_timed_process(timeout_ms, argc-2, &argv[2]); + const long timeout_sec = strtol(argv[1], nullptr, 10); + int exit_code = run_timed_process(timeout_sec * 1000L, argc-2, &argv[2]); printf("App Exit Code: %d\n", exit_code); return exit_code; } -int run_timed_process(const long timeout, const int exe_argc, const char *exe_path_and_argv[]) +int run_timed_process(const long timeout_ms, const int proc_argc, const char *proc_argv[]) { #ifdef _WIN32 std::string cmdline(exe_path_and_argv[0]); @@ -64,21 +65,24 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa return exit_code; #else - const int check_interval = 1000; + // TODO: Describe what the 'ms_factor' is, and why it's being used here. + const int ms_factor = 40; + const int check_interval = 1000 / ms_factor; + int check_count = 0; - char **args = new char *[exe_argc]; + char *args[proc_argc]; pid_t child_pid; int child_status; - int wait_code; + int w; - for (int i = 0; i < exe_argc; i++) + for (int i = 0; i < proc_argc; i++) { - args[i] = (char *) exe_path_and_argv[i]; + args[i] = (char *) proc_argv[i]; } // This is just for development. Will remove it when it's ready to be submitted :) - for (int j = 0; j < exe_argc; j++) + for (int j = 0; j < proc_argc; j++) { printf("[%d]: %s\n", j, args[j]); } @@ -87,11 +91,13 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa if (child_pid < 0) { - printf("Fork failed... No memory available.\n"); + // Fork failed. No memory remaining available :( + printf("Fork failed... Returning ENOMEM.\n"); return ENOMEM; } else if (child_pid == 0) { + // Instructions for child process! printf("Running child process...\n"); execv(args[0], &args[0]); } @@ -99,31 +105,27 @@ int run_timed_process(const long timeout, const int exe_argc, const char *exe_pa { do { - wait_code = waitpid(child_pid, &child_status, WNOHANG); + // Instructions for the parent process! + w = waitpid(child_pid, &child_status, WNOHANG); - // Something went terribly wrong. - if (wait_code == -1) + if (w == -1) return EINVAL; - // TODO: Explain why we are multiplying by 25 here, and dividing - // by 40 in the while clause. - usleep(check_interval * 25); + std::this_thread::sleep_for(std::chrono::milliseconds(check_interval)); - if (wait_code) + if (w) { if (WIFEXITED(child_status)) - { - printf("Child process exited successfully with status %d.\n", - WEXITSTATUS(child_status)); return WEXITSTATUS(child_status); - } } - } while (check_count++ < ((timeout / check_interval) * 40)); + check_count += ms_factor; + + } while (check_count < ((timeout_ms / check_interval) * ms_factor)); } - printf("Child process took too long and timed out... Exiting it...\n"); + printf("Child process took too long. Timed out... Exiting...\n"); kill(child_pid, SIGKILL); - delete[] args; // Don't leak memory :) + #endif return ETIMEDOUT; } diff --git a/src/tests/Common/CLRTest.Execute.Bash.targets b/src/tests/Common/CLRTest.Execute.Bash.targets index 6104dbd9ecdad..19b0594a1e14e 100644 --- a/src/tests/Common/CLRTest.Execute.Bash.targets +++ b/src/tests/Common/CLRTest.Execute.Bash.targets @@ -172,6 +172,19 @@ fi Set CORE_ROOT to the specified value before running the test. + + true + =* + watcherFullPath + + Path to the test watcher that will look over the test. + + true =* @@ -179,7 +192,7 @@ fi @@ -242,10 +255,11 @@ then exit 1 fi - # Copy CORECLR native binaries to $LinkBin, + # Copy CORECLR native binaries and the test watcher (if provided) to $LinkBin, # so that we can run the test based on that directory cp $CORE_ROOT/*.so $LinkBin/ cp $CORE_ROOT/corerun $LinkBin/ + cp $_WatcherFullPath/watchdog $LinkBin/ # Copy some files that may be arguments for f in *.txt; @@ -255,6 +269,7 @@ then ExePath=$LinkBin/$(InputAssemblyName) export CORE_ROOT=$PWD/$LinkBin + export _WatcherFullPath=$PWD/$LinkBin/watchdog fi ]]> @@ -275,6 +290,7 @@ fi "$CORE_ROOT/corerun" $(CoreRunArgs) ${__DotEnvArg} + "$_WatcherFullPath" 300 ' -%(Identity)%(ParamText)|/%(Identity)%(ParamText)) From 226ea36d57931fedc3676c497bd46d8e7d9da8dd Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 13 Dec 2022 18:20:53 -0800 Subject: [PATCH 18/34] Renamed variable. --- src/native/watchdog/watchdog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 5ebba3dd0a1a2..295e83076c880 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -74,7 +74,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr pid_t child_pid; int child_status; - int w; + int wait_code; for (int i = 0; i < proc_argc; i++) { @@ -106,14 +106,14 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr do { // Instructions for the parent process! - w = waitpid(child_pid, &child_status, WNOHANG); + wait_code = waitpid(child_pid, &child_status, WNOHANG); if (w == -1) return EINVAL; std::this_thread::sleep_for(std::chrono::milliseconds(check_interval)); - if (w) + if (wait_code) { if (WIFEXITED(child_status)) return WEXITSTATUS(child_status); From 5fbd7873a544aca04d999dfd9da9dab9c248ae35 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 14 Dec 2022 11:59:09 -0800 Subject: [PATCH 19/34] FIXED THE LINUX PART! --- src/native/watchdog/watchdog.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 295e83076c880..8c93a52382507 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #endif int run_timed_process(const long, const int, const char *[]); @@ -70,7 +71,9 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr const int check_interval = 1000 / ms_factor; int check_count = 0; - char *args[proc_argc]; + // char *args[proc_argc]; + // std::unique_ptr args = std::make_unique(proc_argc); + std::vector args; pid_t child_pid; int child_status; @@ -78,8 +81,9 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr for (int i = 0; i < proc_argc; i++) { - args[i] = (char *) proc_argv[i]; + args.push_back(proc_argv[i]); } + args.push_back(NULL); // This is just for development. Will remove it when it's ready to be submitted :) for (int j = 0; j < proc_argc; j++) @@ -99,7 +103,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr { // Instructions for child process! printf("Running child process...\n"); - execv(args[0], &args[0]); + execv(args[0], const_cast(args.data())); } else { @@ -108,7 +112,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr // Instructions for the parent process! wait_code = waitpid(child_pid, &child_status, WNOHANG); - if (w == -1) + if (wait_code == -1) return EINVAL; std::this_thread::sleep_for(std::chrono::milliseconds(check_interval)); From 0ff6b8d6bb97b943f4c3999c3062c73ab4e99f24 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 15 Dec 2022 17:29:41 -0800 Subject: [PATCH 20/34] Started implementing the constant flow of logs. Had to save my progress. --- src/native/watchdog/watchdog.cpp | 8 +- .../Common/XUnitWrapperGenerator/ITestInfo.cs | 6 +- .../XUnitWrapperGenerator.cs | 11 ++- .../Common/XUnitWrapperLibrary/TestSummary.cs | 85 ++++++++++++++++++- 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 8c93a52382507..102cfabdc851d 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -34,12 +34,12 @@ int main(const int argc, const char *argv[]) int run_timed_process(const long timeout_ms, const int proc_argc, const char *proc_argv[]) { #ifdef _WIN32 - std::string cmdline(exe_path_and_argv[0]); + std::string cmdline(proc_argv[0]); - for (int i = 1; i < exe_argc; i++) + for (int i = 1; i < proc_argc; i++) { cmdline.append(" "); - cmdline.append(exe_path_and_argv[i]); + cmdline.append(proc_argv[i]); } STARTUPINFOA startup_info; @@ -71,8 +71,6 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr const int check_interval = 1000 / ms_factor; int check_count = 0; - // char *args[proc_argc]; - // std::unique_ptr args = std::make_unique(proc_argc); std::vector args; pid_t child_pid; diff --git a/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs b/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs index 213fc3d36d1bb..6654d597ff4b9 100644 --- a/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs +++ b/src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs @@ -341,11 +341,11 @@ public string WrapTestExecutionWithReporting(string testExecutionExpression, ITe builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Running test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});"); builder.AppendLine($"{_outputRecorderIdentifier}.ResetTestOutput();"); builder.AppendLine(testExecutionExpression); - builder.AppendLine($"{_summaryLocalIdentifier}.ReportPassedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\", stopwatch.Elapsed - testStart, {_outputRecorderIdentifier}.GetTestOutput());"); + builder.AppendLine($"{_summaryLocalIdentifier}.ReportPassedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\", stopwatch.Elapsed - testStart, {_outputRecorderIdentifier}.GetTestOutput(), tempLogSw);"); builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Passed test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});"); builder.AppendLine("}"); builder.AppendLine("catch (System.Exception ex) {"); - builder.AppendLine($"{_summaryLocalIdentifier}.ReportFailedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\", stopwatch.Elapsed - testStart, ex, {_outputRecorderIdentifier}.GetTestOutput());"); + builder.AppendLine($"{_summaryLocalIdentifier}.ReportFailedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\", stopwatch.Elapsed - testStart, ex, {_outputRecorderIdentifier}.GetTestOutput(), tempLogSw);"); builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Failed test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});"); builder.AppendLine("}"); @@ -359,6 +359,6 @@ public string WrapTestExecutionWithReporting(string testExecutionExpression, ITe public string GenerateSkippedTestReporting(ITestInfo skippedTest) { - return $"{_summaryLocalIdentifier}.ReportSkippedTest({skippedTest.TestNameExpression}, \"{skippedTest.ContainingType}\", @\"{skippedTest.Method}\", System.TimeSpan.Zero, string.Empty);"; + return $"{_summaryLocalIdentifier}.ReportSkippedTest({skippedTest.TestNameExpression}, \"{skippedTest.ContainingType}\", @\"{skippedTest.Method}\", System.TimeSpan.Zero, string.Empty, tempLogSw);"; } } diff --git a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs index adcfa65fabe09..7fb506fd67d39 100644 --- a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs +++ b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs @@ -155,7 +155,9 @@ private static string GenerateFullTestRunner(ImmutableArray testInfos builder.AppendLine("System.Collections.Generic.HashSet testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();"); builder.AppendLine("XUnitWrapperLibrary.TestFilter filter = new (args, testExclusionList);"); - builder.AppendLine("XUnitWrapperLibrary.TestSummary summary = new();"); + builder.AppendLine($@"XUnitWrapperLibrary.TestSummary summary = new();"); + // builder.AppendLine($@"XUnitWrapperLibrary.TestSummary summary = new(""{assemblyName}"");"); + // builder.AppendLine("summary.OpenTempLog();"); builder.AppendLine("System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();"); builder.AppendLine("XUnitWrapperLibrary.TestOutputRecorder outputRecorder = new(System.Console.Out);"); builder.AppendLine("System.Console.SetOut(outputRecorder);"); @@ -178,18 +180,24 @@ private static string GenerateFullTestRunner(ImmutableArray testInfos { if (currentTestExecutor != 0) testExecutorBuilder.AppendLine("}"); + currentTestExecutor++; testExecutorBuilder.AppendLine($"void TestExecutor{currentTestExecutor}(){{"); + testExecutorBuilder.AppendLine($@"using (System.IO.StreamWriter tempLogSw = System.IO.File.AppendText(""{assemblyName}_templog.xml"")) {{"); builder.AppendLine($"TestExecutor{currentTestExecutor}();"); testsLeftInCurrentTestExecutor = 50; // Break test executors into groups of 50, which empircally seems to work well } + testExecutorBuilder.AppendLine(test.GenerateTestExecution(reporter)); totalTestsEmitted++; testsLeftInCurrentTestExecutor--; } + + testExecutorBuilder.AppendLine("}"); testExecutorBuilder.AppendLine("}"); } + // builder.AppendLine($@"summary.CloseTempLog();"); builder.AppendLine($@"string testResults = summary.GetTestResultOutput(""{assemblyName}"");"); builder.AppendLine($@"string workitemUploadRoot = System.Environment.GetEnvironmentVariable(""HELIX_WORKITEM_UPLOAD_ROOT"");"); builder.AppendLine($@"if (workitemUploadRoot != null) System.IO.File.WriteAllText(System.IO.Path.Combine(workitemUploadRoot, ""{assemblyName}.testResults.xml.txt""), testResults);"); @@ -197,7 +205,6 @@ private static string GenerateFullTestRunner(ImmutableArray testInfos builder.AppendLine("return 100;"); builder.Append(testExecutorBuilder); - builder.AppendLine("public static class TestCount { public const int Count = " + totalTestsEmitted.ToString() + "; }"); return builder.ToString(); } diff --git a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs index b230fa485a055..e751b9a43c0eb 100644 --- a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs +++ b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs @@ -3,13 +3,67 @@ // using System; +using System.IO; using System.Collections.Generic; using System.Text; namespace XUnitWrapperLibrary; public class TestSummary { - readonly record struct TestResult(string Name, string ContainingTypeName, string MethodName, TimeSpan Duration, Exception? Exception, string? SkipReason, string? Output); + // readonly record struct TestResult(string Name, string ContainingTypeName, string MethodName, TimeSpan Duration, Exception? Exception, string? SkipReason, string? Output); + readonly record struct TestResult + { + readonly string Name; + readonly string ContainingTypeName; + readonly string MethodName; + readonly TimeSpan Duration; + readonly Exception? Exception; + readonly string? SkipReason; + readonly string? Output; + + public TestResult(string name, string containingTypeName, string methodName, TimeSpan duration, Exception? exception, string? skipReason, string? output) + { + Name = name; + ContainingTypeName = containingTypeName; + MethodName = methodName; + Duration = duration; + Exception = exception; + SkipReason = skipReason; + Output = output; + } + + public string ToXmlString() + { + var testResultSb = new StringBuilder(); + testResultSb.Append($@"" + : string.Empty + + if (Exception is not null) + { + // Append the exception here :) + } + else if (SkipReason is not null) + { + testResultSb.Append($@" result=""Skip"">"); + } + else + { + testResultSb.AppendLine($@" result=""Pass"">{outputElement}"); + } + + return testResultSb.ToString(); + } + } public int PassedTests { get; private set; } = 0; public int FailedTests { get; private set; } = 0; @@ -18,25 +72,48 @@ public class TestSummary private readonly List _testResults = new(); private DateTime _testRunStart = DateTime.Now; + private string _assemblyName = "NoSpecifiedAssembly"; + + // public TestSummary(string assemblyName) + // { + // _assemblyName = assemblyName; + // } - public void ReportPassedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string output) + public void ReportPassedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string output, StreamWriter tempLogSw) { PassedTests++; _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, null, null, output)); } - public void ReportFailedTest(string name, string containingTypeName, string methodName, TimeSpan duration, Exception ex, string output) + public void ReportFailedTest(string name, string containingTypeName, string methodName, TimeSpan duration, Exception ex, string output, StreamWriter tempLogSw) { FailedTests++; _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, ex, null, output)); } - public void ReportSkippedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string reason) + public void ReportSkippedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string reason, StreamWriter tempLogSw) { SkippedTests++; _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, null, reason, null)); } + // public void OpenTempLog() + // { + // using (StreamWriter sw = File.CreateText($"{_assemblyName}_templog.xml")) + // { + // sw.WriteLine(""); + // } + // } + + // public void CloseTempLog() + // { + // using (StreamWriter sw = File.AppendText($"{_assemblyName}_templog.xml")) + // { + // sw.WriteLine(""); + // } + // } + + // NOTE: This will likely change with the existence of the temp log. public string GetTestResultOutput(string assemblyName) { double totalRunSeconds = (DateTime.Now - _testRunStart).TotalSeconds; From 8f21b9c32fbb43c892bf681378bae882ba068339 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 16 Dec 2022 16:36:09 -0800 Subject: [PATCH 21/34] TEMP LOG BUILDS! --- .../XUnitWrapperGenerator.cs | 3 + .../Common/XUnitWrapperLibrary/TestSummary.cs | 64 +++++++++---------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs index 7fb506fd67d39..834f330e2b0eb 100644 --- a/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs +++ b/src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs @@ -179,7 +179,10 @@ private static string GenerateFullTestRunner(ImmutableArray testInfos if (testsLeftInCurrentTestExecutor == 0) { if (currentTestExecutor != 0) + { + testExecutorBuilder.AppendLine("}"); testExecutorBuilder.AppendLine("}"); + } currentTestExecutor++; testExecutorBuilder.AppendLine($"void TestExecutor{currentTestExecutor}(){{"); diff --git a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs index e751b9a43c0eb..2331000c41e3c 100644 --- a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs +++ b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs @@ -40,11 +40,38 @@ public string ToXmlString() string outputElement = !string.IsNullOrWhiteSpace(Output) ? $"" - : string.Empty + : string.Empty; if (Exception is not null) { - // Append the exception here :) + string? message = Exception.Message; + + if (Exception is System.Reflection.TargetInvocationException tie) + { + if (tie.InnerException is not null) + { + message = $"{message}\n INNER EXCEPTION--\n" + + $"{tie.InnerException.GetType()}--\n" + + $"{tie.InnerException.Message}--\n" + + $"{tie.InnerException.StackTrace}"; + } + } + + if (string.IsNullOrWhiteSpace(message)) + { + message = "NoExceptionMessage"; + } + + testResultSb.Append($@" result=""Fail"">" + + $@"" + + $"" + + "{outputElement}"); } else if (SkipReason is not null) { @@ -146,38 +173,7 @@ public string GetTestResultOutput(string assemblyName) foreach (var test in _testResults) { - resultsFile.Append($@"" : string.Empty; - if (test.Exception is not null) - { - string exceptionMessage = test.Exception.Message; - if (test.Exception is System.Reflection.TargetInvocationException tie) - { - if (tie.InnerException != null) - { - exceptionMessage = $"{exceptionMessage} \n INNER EXCEPTION--\n {tie.InnerException.GetType()}--\n{tie.InnerException.Message}--\n{tie.InnerException.StackTrace}"; - } - } - if (string.IsNullOrWhiteSpace(exceptionMessage)) - { - exceptionMessage = "NoExceptionMessage"; - } - - string? stackTrace = test.Exception.StackTrace; - if (string.IsNullOrWhiteSpace(stackTrace)) - { - stackTrace = "NoStackTrace"; - } - resultsFile.AppendLine($@"result=""Fail"">{outputElement}"); - } - else if (test.SkipReason is not null) - { - resultsFile.AppendLine($@"result=""Skip"">"); - } - else - { - resultsFile.AppendLine($@" result=""Pass"">{outputElement}"); - } + resultsFile.AppendLine(test.ToXmlString()); } resultsFile.AppendLine(""); From c7fc54126c3e1c37520c60d1ec4958569fb95d6f Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 16 Dec 2022 17:10:54 -0800 Subject: [PATCH 22/34] TEMP LOGS WORK! --- .../Common/XUnitWrapperLibrary/TestSummary.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs index 2331000c41e3c..f5b4f013dd6af 100644 --- a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs +++ b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs @@ -109,19 +109,25 @@ public string ToXmlString() public void ReportPassedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string output, StreamWriter tempLogSw) { PassedTests++; - _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, null, null, output)); + var result = new TestResult(name, containingTypeName, methodName, duration, null, null, output); + _testResults.Add(result); + tempLogSw.WriteLine(result.ToXmlString()); } public void ReportFailedTest(string name, string containingTypeName, string methodName, TimeSpan duration, Exception ex, string output, StreamWriter tempLogSw) { FailedTests++; - _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, ex, null, output)); + var result = new TestResult(name, containingTypeName, methodName, duration, ex, null, output); + _testResults.Add(result); + tempLogSw.WriteLine(result.ToXmlString()); } public void ReportSkippedTest(string name, string containingTypeName, string methodName, TimeSpan duration, string reason, StreamWriter tempLogSw) { SkippedTests++; - _testResults.Add(new TestResult(name, containingTypeName, methodName, duration, null, reason, null)); + var result = new TestResult(name, containingTypeName, methodName, duration, null, reason, null); + _testResults.Add(result); + tempLogSw.WriteLine(result.ToXmlString()); } // public void OpenTempLog() @@ -140,7 +146,7 @@ public void ReportSkippedTest(string name, string containingTypeName, string met // } // } - // NOTE: This will likely change with the existence of the temp log. + // NOTE: This will likely change or be removed altogether with the existence of the temp log. public string GetTestResultOutput(string assemblyName) { double totalRunSeconds = (DateTime.Now - _testRunStart).TotalSeconds; From a88e48cd9efd41c8b4e64df96b33550765ee7ee6 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Tue, 21 Feb 2023 18:02:08 -0800 Subject: [PATCH 23/34] Test Watcher seems to be working on Linux and MacOS. --- src/native/watchdog/watchdog.cpp | 11 +++++++++-- src/tests/Common/CLRTest.Execute.Bash.targets | 12 +++++++++--- src/tests/Common/XUnitWrapperLibrary/TestSummary.cs | 1 - src/tests/Common/helixpublishwitharcade.proj | 6 ++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 102cfabdc851d..b6052aafcd2d1 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -1,18 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + #include #include #include #include #ifdef _WIN32 + #include #include -#else + +#else // !_WIN32 + #include #include #include #include #include -#endif + +#endif // _WIN32 int run_timed_process(const long, const int, const char *[]); diff --git a/src/tests/Common/CLRTest.Execute.Bash.targets b/src/tests/Common/CLRTest.Execute.Bash.targets index f082fdf99ce35..e07942658605a 100644 --- a/src/tests/Common/CLRTest.Execute.Bash.targets +++ b/src/tests/Common/CLRTest.Execute.Bash.targets @@ -267,7 +267,7 @@ then # so that we can run the test based on that directory cp $CORE_ROOT/*.so $LinkBin/ cp $CORE_ROOT/corerun $LinkBin/ - cp $_WatcherFullPath/watchdog $LinkBin/ + cp $_WatcherFullPath $LinkBin/ # Copy some files that may be arguments for f in *.txt; @@ -334,8 +334,11 @@ fi if [ ! -z "$CLRCustomTestLauncher" ]; then LAUNCHER="$CLRCustomTestLauncher $PWD/" +elif [ ! -z "$_DebuggerFullPath" ] +then + LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" else - LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(WatcherRunFile) $(CLRTestRunFile)" + LAUNCHER="$(WatcherRunFile) $(CLRTestRunFile)" fi $(BashIlrtTestLaunchCmds) @@ -362,8 +365,11 @@ $(BashLinkerTestLaunchCmds) if [ ! -z "$CLRCustomTestLauncher" ]; then LAUNCHER="$CLRCustomTestLauncher $PWD/" +elif [ ! -z "$_DebuggerFullPath" ] +then + LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" else - LAUNCHER="$_DebuggerFullPath $(CLRTestRunFile)" + LAUNCHER="$(WatcherRunFile) $(CLRTestRunFile)" fi $(BashIlrtTestLaunchCmds) diff --git a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs index b38a605a481a8..c81a82d99423d 100644 --- a/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs +++ b/src/tests/Common/XUnitWrapperLibrary/TestSummary.cs @@ -104,7 +104,6 @@ public string ToXmlString() private readonly List _testResults = new(); private DateTime _testRunStart = DateTime.Now; - private string _assemblyName = "NoSpecifiedAssembly"; public void ReportPassedTest(string name, string containingTypeName, diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index a92da0f62efca..7d78cab82b56f 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -718,9 +718,15 @@ $CORE_ROOT/xunit/xunit.console.dll + + $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/watchdog + $([MSBuild]::NormalizePath($(TestWatcherDirectory))) + + + From 8fceb44f093ab2373e64f34c19520be879a4fa79 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 22 Feb 2023 13:28:12 -0800 Subject: [PATCH 24/34] Updated the Helix Commands with the watcher now included, and removed some dev-only logging from the watcher. Unix should be good to go now, or very close to be. --- src/native/watchdog/watchdog.cpp | 7 ------- src/tests/Common/helixpublishwitharcade.proj | 9 ++++++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index b6052aafcd2d1..7885297f45cfe 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -90,12 +90,6 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr } args.push_back(NULL); - // This is just for development. Will remove it when it's ready to be submitted :) - for (int j = 0; j < proc_argc; j++) - { - printf("[%d]: %s\n", j, args[j]); - } - child_pid = fork(); if (child_pid < 0) @@ -107,7 +101,6 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr else if (child_pid == 0) { // Instructions for child process! - printf("Running child process...\n"); execv(args[0], const_cast(args.data())); } else diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index 7d78cab82b56f..d051fdd812584 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -376,6 +376,9 @@ <_MergedWrapperRunScriptPrefix Condition="'$(TestWrapperTargetsWindows)' == 'true'">call + + <_MergedWrapperRunScriptWatcherArgs Condition="'$(TestWrapperTargetsWindows)' != 'true'">-watcher=./watchdog + <_MergedWrapperRunScriptWatcherArgs Condition="'$(TestWrapperTargetsWindows)' == 'true'">/watcher=.\watchdog.exe @@ -411,8 +414,8 @@ - - + + @@ -720,7 +723,7 @@ $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/watchdog - $([MSBuild]::NormalizePath($(TestWatcherDirectory))) + $([MSBuild]::NormalizePath($(TestWatcherPath))) From 064b9b0b45af1e9f176626195a8faf67d750099c Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 22 Feb 2023 15:45:55 -0800 Subject: [PATCH 25/34] Fixed build issue in the watcher's Windows version. --- src/native/watchdog/watchdog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index 7885297f45cfe..ebe0070336be6 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -65,7 +65,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr return error_code; } - WaitForSingleObject(proc_info.hProcess, timeout); + WaitForSingleObject(proc_info.hProcess, timeout_ms); GetExitCodeProcess(proc_info.hProcess, &exit_code); CloseHandle(proc_info.hProcess); From 2cb927096232b0e6828ac01c52d7c1a952186812 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 22 Feb 2023 17:54:10 -0800 Subject: [PATCH 26/34] Apparently works on Windows now too? --- .../Common/CLRTest.Execute.Batch.targets | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tests/Common/CLRTest.Execute.Batch.targets b/src/tests/Common/CLRTest.Execute.Batch.targets index db74a66be45b5..9dec88846b797 100644 --- a/src/tests/Common/CLRTest.Execute.Batch.targets +++ b/src/tests/Common/CLRTest.Execute.Batch.targets @@ -216,6 +216,20 @@ Exit /b 0 ]]> Set CORE_ROOT to the specified value before running the test. + + + true + watcherFullPath + + Path to the test watcher that will look over the test. + @@ -260,17 +274,19 @@ IF defined DoLink ( Exit /b 1 ) - REM Copy CORECLR native binaries to %LinkBin%, so that we can run the test based on that directory + REM Copy CORECLR native binaries and the test watcher (if provided) to %LinkBin%, so that we can run the test based on that directory copy %CORE_ROOT%\clrjit.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\coreclr.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\mscorrc.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\CoreRun.exe %LinkBin% > nul 2> nul + copy %_WatcherFullPath% %LinkBin% > nul 2> nul REM Copy some files that may be arguments copy *.txt %LinkBin% > nul 2> nul set ExePath=%LinkBin%\$(InputAssemblyName) - set CORE_ROOT=%scriptPath%LinkBin% + set CORE_ROOT=%scriptPath%\%LinkBin% + set _WatcherFullPath=%scriptPath%\%LinkBin%\watchdog.exe ) ]]> @@ -289,6 +305,8 @@ if defined DoLink ( "%CORE_ROOT%\corerun.exe" $(CoreRunArgs) %__DotEnvArg% + "%_WatcherFullPath%" 300 + Date: Thu, 23 Feb 2023 12:11:13 -0800 Subject: [PATCH 27/34] Fixed build issue with Windows x86. --- src/native/watchdog/watchdog.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index ebe0070336be6..b4a92971e1a7d 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -6,12 +6,12 @@ #include #include -#ifdef _WIN32 +#ifdef TARGET_WINDOWS #include #include -#else // !_WIN32 +#else // !TARGET_WINDOWS #include #include @@ -19,11 +19,15 @@ #include #include -#endif // _WIN32 +#endif // TARGET_WINDOWS int run_timed_process(const long, const int, const char *[]); +#ifdef TARGET_X86 +int __cdecl main(const int argc, const char *argv[]) +#else int main(const int argc, const char *argv[]) +#endif { if (argc < 3) { @@ -40,7 +44,7 @@ int main(const int argc, const char *argv[]) int run_timed_process(const long timeout_ms, const int proc_argc, const char *proc_argv[]) { -#ifdef _WIN32 +#ifdef TARGET_WINDOWS std::string cmdline(proc_argv[0]); for (int i = 1; i < proc_argc; i++) @@ -72,7 +76,8 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr CloseHandle(proc_info.hThread); return exit_code; -#else +#else // !TARGET_WINDOWS + // TODO: Describe what the 'ms_factor' is, and why it's being used here. const int ms_factor = 40; const int check_interval = 1000 / ms_factor; @@ -128,7 +133,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr printf("Child process took too long. Timed out... Exiting...\n"); kill(child_pid, SIGKILL); -#endif +#endif // TARGET_WINDOWS return ETIMEDOUT; } From eba2bcd15500d7b00910a68beba5525351a76c7f Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 24 Feb 2023 15:43:05 -0800 Subject: [PATCH 28/34] Fixed issue where we were not building the watcher in certain subsets that need it. --- src/native/watchdog/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/native/watchdog/CMakeLists.txt b/src/native/watchdog/CMakeLists.txt index 541e524225fd3..723e105d7373f 100644 --- a/src/native/watchdog/CMakeLists.txt +++ b/src/native/watchdog/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(watchdog ${CMAKE_CURRENT_LIST_DIR}/watchdog.cpp) +add_executable_clr(watchdog ${CMAKE_CURRENT_LIST_DIR}/watchdog.cpp) +install_clr(TARGETS watchdog DESTINATIONS . COMPONENT hosts) +install_clr(TARGETS watchdog DESTINATIONS . COMPONENT nativeaot) From d68d16c74ab2abd480a5acbd532a328f9b4c6a11 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Mon, 27 Feb 2023 10:59:05 -0800 Subject: [PATCH 29/34] Fixed yet another Windows issue. --- src/tests/Common/helixpublishwitharcade.proj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index d051fdd812584..22dd56da62dfc 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -722,7 +722,10 @@ - $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/watchdog + watchdog + watchdog.exe + + $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/$(TestWatcherExe) $([MSBuild]::NormalizePath($(TestWatcherPath))) From 998965cf3b6a56205d3680c13dbfbe2287eb661a Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Mon, 27 Feb 2023 14:55:05 -0800 Subject: [PATCH 30/34] Used ExeSuffix instead of recomputing it and excluded Browser-Wasm --- src/tests/Common/helixpublishwitharcade.proj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index 22dd56da62dfc..c43ecd6979776 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -722,17 +722,17 @@ - watchdog - watchdog.exe - + watchdog$(ExeSuffix) $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/$(TestWatcherExe) $([MSBuild]::NormalizePath($(TestWatcherPath))) - - + + + + From 7cb4e89b961b105c462064851f8cd94c0a5eeb7f Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Wed, 1 Mar 2023 12:07:50 -0800 Subject: [PATCH 31/34] Changed the Helix Correlation Payloads to bundle the whole watchdog directory, rather than just the executable, and reallowed tests to be run without the watcher. --- src/tests/Common/CLRTest.Execute.Bash.targets | 12 ++++++------ src/tests/Common/CLRTest.Execute.Batch.targets | 6 +++--- src/tests/Common/helixpublishwitharcade.proj | 7 +++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/tests/Common/CLRTest.Execute.Bash.targets b/src/tests/Common/CLRTest.Execute.Bash.targets index e07942658605a..46115287cf011 100644 --- a/src/tests/Common/CLRTest.Execute.Bash.targets +++ b/src/tests/Common/CLRTest.Execute.Bash.targets @@ -334,11 +334,11 @@ fi if [ ! -z "$CLRCustomTestLauncher" ]; then LAUNCHER="$CLRCustomTestLauncher $PWD/" -elif [ ! -z "$_DebuggerFullPath" ] +elif [ ! -z "$_WatcherFullPath" ] then - LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" -else LAUNCHER="$(WatcherRunFile) $(CLRTestRunFile)" +else + LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" fi $(BashIlrtTestLaunchCmds) @@ -365,11 +365,11 @@ $(BashLinkerTestLaunchCmds) if [ ! -z "$CLRCustomTestLauncher" ]; then LAUNCHER="$CLRCustomTestLauncher $PWD/" -elif [ ! -z "$_DebuggerFullPath" ] +elif [ ! -z "$_WatcherFullPath" ] then - LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" -else LAUNCHER="$(WatcherRunFile) $(CLRTestRunFile)" +else + LAUNCHER="$_DebuggerFullPath $_DebuggerArgsSeparator $(CLRTestRunFile)" fi $(BashIlrtTestLaunchCmds) diff --git a/src/tests/Common/CLRTest.Execute.Batch.targets b/src/tests/Common/CLRTest.Execute.Batch.targets index 9dec88846b797..1c0cd605944c4 100644 --- a/src/tests/Common/CLRTest.Execute.Batch.targets +++ b/src/tests/Common/CLRTest.Execute.Batch.targets @@ -319,10 +319,10 @@ $(BatchCopyCoreShimLocalCmds) IF NOT "%CLRCustomTestLauncher%"=="" ( set LAUNCHER=call %CLRCustomTestLauncher% %scriptPath% -) ELSE IF NOT "%_DebuggerFullPath%"=="" ( - set LAUNCHER=%_DebuggerFullPath% $(CLRTestRunFile) -) ELSE ( +) ELSE IF NOT "%_WatcherFullPath%"=="" ( set LAUNCHER=$(WatcherRunFile) $(CLRTestRunFile) +) ELSE ( + set LAUNCHER=%_DebuggerFullPath% $(CLRTestRunFile) ) $(BatchIlrtTestLaunchCmds) diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index c43ecd6979776..807ee491025bb 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -722,9 +722,8 @@ - watchdog$(ExeSuffix) - $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/$(TestWatcherExe) - $([MSBuild]::NormalizePath($(TestWatcherPath))) + $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/ + $([MSBuild]::NormalizePath($(TestWatcherDirectory))) @@ -732,7 +731,7 @@ - + From 2ba916a2218dae300c4c3b5a52642b78352d66c8 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 2 Mar 2023 20:00:21 -0800 Subject: [PATCH 32/34] Changed the scripts to use the test watcher in the Core_Root, instead of the object artifacts. --- src/tests/Common/CLRTest.Execute.Bash.targets | 31 +++++++------------ .../Common/CLRTest.Execute.Batch.targets | 23 +++++--------- src/tests/Common/helixpublishwitharcade.proj | 13 ++------ 3 files changed, 22 insertions(+), 45 deletions(-) diff --git a/src/tests/Common/CLRTest.Execute.Bash.targets b/src/tests/Common/CLRTest.Execute.Bash.targets index 46115287cf011..5cc68ec20eff0 100644 --- a/src/tests/Common/CLRTest.Execute.Bash.targets +++ b/src/tests/Common/CLRTest.Execute.Bash.targets @@ -180,19 +180,6 @@ fi Set CORE_ROOT to the specified value before running the test. - - true - =* - watcherFullPath - - Path to the test watcher that will look over the test. - - true =* @@ -206,6 +193,12 @@ fi export __DotEnvArg=-e ${__DotEnv}]]> A dotenv file to pass to corerun to set environment variables for the test run. + + + false + + Run the tests using the test watcher. + @@ -263,11 +256,11 @@ then exit 1 fi - # Copy CORECLR native binaries and the test watcher (if provided) to $LinkBin, + # Copy CORECLR native binaries and the test watcher to $LinkBin, # so that we can run the test based on that directory cp $CORE_ROOT/*.so $LinkBin/ cp $CORE_ROOT/corerun $LinkBin/ - cp $_WatcherFullPath $LinkBin/ + cp $CORE_ROOT/watchdog $LinkBin/ # Copy some files that may be arguments for f in *.txt; @@ -277,7 +270,6 @@ then ExePath=$LinkBin/$(InputAssemblyName) export CORE_ROOT=$PWD/$LinkBin - export _WatcherFullPath=$PWD/$LinkBin/watchdog fi ]]> @@ -298,7 +290,7 @@ fi "$CORE_ROOT/corerun" $(CoreRunArgs) ${__DotEnvArg} - "$_WatcherFullPath" 300 + "$CORE_ROOT/watchdog" 300 Set CORE_ROOT to the specified value before running the test. - - true - watcherFullPath + + false - Path to the test watcher that will look over the test. + Run the tests using the test watcher. @@ -274,19 +268,18 @@ IF defined DoLink ( Exit /b 1 ) - REM Copy CORECLR native binaries and the test watcher (if provided) to %LinkBin%, so that we can run the test based on that directory + REM Copy CORECLR native binaries and the test watcher to %LinkBin%, so that we can run the test based on that directory copy %CORE_ROOT%\clrjit.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\coreclr.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\mscorrc.dll %LinkBin% > nul 2> nul copy %CORE_ROOT%\CoreRun.exe %LinkBin% > nul 2> nul - copy %_WatcherFullPath% %LinkBin% > nul 2> nul + copy %CORE_ROOT%\watchdog.exe %LinkBin% > nul 2> nul REM Copy some files that may be arguments copy *.txt %LinkBin% > nul 2> nul set ExePath=%LinkBin%\$(InputAssemblyName) set CORE_ROOT=%scriptPath%\%LinkBin% - set _WatcherFullPath=%scriptPath%\%LinkBin%\watchdog.exe ) ]]> @@ -305,7 +298,7 @@ if defined DoLink ( "%CORE_ROOT%\corerun.exe" $(CoreRunArgs) %__DotEnvArg% - "%_WatcherFullPath%" 300 + "%CORE_ROOT%\watchdog.exe" 300 <_MergedWrapperRunScriptPrefix Condition="'$(TestWrapperTargetsWindows)' == 'true'">call - - <_MergedWrapperRunScriptWatcherArgs Condition="'$(TestWrapperTargetsWindows)' != 'true'">-watcher=./watchdog - <_MergedWrapperRunScriptWatcherArgs Condition="'$(TestWrapperTargetsWindows)' == 'true'">/watcher=.\watchdog.exe @@ -414,8 +411,8 @@ - - + + @@ -721,17 +718,11 @@ $CORE_ROOT/xunit/xunit.console.dll - - $(ArtifactsDir)obj/coreclr/$(OSPlatformConfig)/test-watchdog/ - $([MSBuild]::NormalizePath($(TestWatcherDirectory))) - - - From a712352e02cbbcfd4132f346ba52f3bde4abb7b3 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Fri, 3 Mar 2023 13:59:15 -0800 Subject: [PATCH 33/34] Fixed undeclared variable in Windows test scripts. --- src/tests/Common/CLRTest.Execute.Batch.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/Common/CLRTest.Execute.Batch.targets b/src/tests/Common/CLRTest.Execute.Batch.targets index 434cb297dc97e..2e0d05e8c635b 100644 --- a/src/tests/Common/CLRTest.Execute.Batch.targets +++ b/src/tests/Common/CLRTest.Execute.Batch.targets @@ -438,6 +438,7 @@ setlocal ENABLEDELAYEDEXPANSION set "lockFolder=%~dp0\lock" pushd %~dp0 set "scriptPath=%~dp0" +set /A _RunWithWatcher=0 $(BatchCLRTestArgPrep) $(BatchCLRTestExitCodePrep) From 0cc8875da566da6fd1a74f4a0773c04420f43a67 Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Thu, 9 Mar 2023 16:16:58 -0800 Subject: [PATCH 34/34] Addressed PR feedback comments. --- src/native/watchdog/watchdog.cpp | 11 ++++------- src/tests/Common/helixpublishwitharcade.proj | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/native/watchdog/watchdog.cpp b/src/native/watchdog/watchdog.cpp index b4a92971e1a7d..1dc6f74fb06b6 100644 --- a/src/native/watchdog/watchdog.cpp +++ b/src/native/watchdog/watchdog.cpp @@ -78,10 +78,7 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr #else // !TARGET_WINDOWS - // TODO: Describe what the 'ms_factor' is, and why it's being used here. - const int ms_factor = 40; - const int check_interval = 1000 / ms_factor; - + const int check_interval_ms = 25; int check_count = 0; std::vector args; @@ -118,16 +115,16 @@ int run_timed_process(const long timeout_ms, const int proc_argc, const char *pr if (wait_code == -1) return EINVAL; - std::this_thread::sleep_for(std::chrono::milliseconds(check_interval)); + std::this_thread::sleep_for(std::chrono::milliseconds(check_interval_ms)); if (wait_code) { if (WIFEXITED(child_status)) return WEXITSTATUS(child_status); } - check_count += ms_factor; + check_count++; - } while (check_count < ((timeout_ms / check_interval) * ms_factor)); + } while (check_count < (timeout_ms / check_interval_ms)); } printf("Child process took too long. Timed out... Exiting...\n"); diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index 0bf7fc2206427..8f862c4ed29ab 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -721,7 +721,7 @@ - +