diff options
-rw-r--r-- | tools/testrunner/main.cpp | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp index 3823215a..0b3a5c03 100644 --- a/tools/testrunner/main.cpp +++ b/tools/testrunner/main.cpp @@ -94,7 +94,7 @@ struct Timestamp } }; -bool run_executable(const ::helpers::path& file, const ::std::vector<const char*>& args, const ::helpers::path& outfile); +bool run_executable(const ::helpers::path& file, const ::std::vector<const char*>& args, const ::helpers::path& outfile, unsigned timeout_seconds); bool run_compiler(const ::helpers::path& source_file, const ::helpers::path& output, const ::std::vector<::std::string>& extra_flags, ::helpers::path libdir={}, bool is_dep=false) { @@ -134,7 +134,16 @@ bool run_compiler(const ::helpers::path& source_file, const ::helpers::path& out for(const auto& s : extra_flags) args.push_back(s.c_str()); - return run_executable(MRUSTC_PATH, args, logfile); + return run_executable(MRUSTC_PATH, args, logfile, 0); +} + +static bool gTimeout = false; +static bool gInterrupted = false; +void sigalrm_handler(int) { + gTimeout = true; +} +void sigint_handler(int) { + gInterrupted = true; } int main(int argc, const char* argv[]) @@ -145,6 +154,13 @@ int main(int argc, const char* argv[]) return v; } + { + struct sigaction sa = {0}; + sa.sa_handler = sigalrm_handler; + sigaction(SIGALRM, &sa, NULL); + signal(SIGINT, sigint_handler); + } + ::std::vector<::std::string> skip_list; // > Filter out tests listed in an exceptions file (newline separated, supports comments) if( opts.exceptions_file ) @@ -297,6 +313,10 @@ int main(int argc, const char* argv[]) unsigned n_ok = 0; for(const auto& test : tests) { + if( gInterrupted ) { + DEBUG(">> Interrupted"); + return 1; + } if( !opts.test_list.empty() && ::std::find(opts.test_list.begin(), opts.test_list.end(), test.m_name) == opts.test_list.end() ) { if( opts.debug_level > 0 ) @@ -358,7 +378,7 @@ int main(int argc, const char* argv[]) auto compile_logfile = outdir / test.m_name + "-build.log"; if( !run_compiler(test.m_path, outfile, test.m_extra_flags, depdir) ) { - DEBUG("COMPILE FAIL " << test.m_name); + DEBUG("COMPILE FAIL " << test.m_name << ", log in " << compile_logfile); n_cfail ++; if( opts.fail_fast ) return 1; @@ -371,14 +391,15 @@ int main(int argc, const char* argv[]) auto run_out_file = outdir / test.m_name + ".out"; if( Timestamp::for_file(run_out_file) < test_output_ts ) { - if( !run_executable(outfile, { outfile.str().c_str() }, run_out_file) ) + auto run_out_file_tmp = run_out_file + ".tmp"; + if( !run_executable(outfile, { outfile.str().c_str() }, run_out_file_tmp, 10) ) { DEBUG("RUN FAIL " << test.m_name); // Move the failing output file auto fail_file = run_out_file + "_failed"; remove(fail_file.str().c_str()); - rename(run_out_file.str().c_str(), fail_file.str().c_str()); + rename(run_out_file_tmp.str().c_str(), fail_file.str().c_str()); DEBUG("- Output in " << fail_file); n_fail ++; @@ -387,6 +408,11 @@ int main(int argc, const char* argv[]) else continue; } + else + { + remove(run_out_file.str().c_str()); + rename(run_out_file_tmp.str().c_str(), run_out_file.str().c_str()); + } } else { @@ -501,7 +527,7 @@ void Options::usage_full() const } /// -bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const char*>& args, const ::helpers::path& outfile) +bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const char*>& args, const ::helpers::path& outfile, unsigned timeout_seconds) { #ifdef _WIN32 ::std::stringstream cmdline; @@ -530,6 +556,7 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const c CreateProcessA(exe_name.str().c_str(), (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); SetErrorMode(em); CloseHandle(si.hStdOutput); + // TODO: Use timeout_seconds WaitForSingleObject(pi.hProcess, INFINITE); DWORD status = 1; GetExitCodeProcess(pi.hProcess, &status); @@ -567,15 +594,24 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const c posix_spawn_file_actions_destroy(&file_actions); int status = -1; - waitpid(pid, &status, 0); + // NOTE: `alarm(0)` clears any pending alarm, so no need to check before + // calling + alarm(timeout_seconds); + if( waitpid(pid, &status, 0) <= 0 ) + { + DEBUG(exe_name << " timed out, killing it"); + kill(pid, SIGKILL); + return false; + } + alarm(0); if( status != 0 ) { if( WIFEXITED(status) ) - DEBUG(exe_name << " exited with non-zero exit status " << WEXITSTATUS(status) << ", see log " << outfile_str); + DEBUG(exe_name << " exited with non-zero exit status " << WEXITSTATUS(status)); else if( WIFSIGNALED(status) ) - DEBUG(exe_name << " was terminated with signal " << WTERMSIG(status) << ", see log " << outfile_str); + DEBUG(exe_name << " was terminated with signal " << WTERMSIG(status)); else - DEBUG(exe_name << " terminated for unknown reason, status=" << status << ", see log " << outfile_str); + DEBUG(exe_name << " terminated for unknown reason, status=" << status); return false; } #endif |