Revert "Add more test_utils functions."
This reverts commit 5fcfcea4a9379633a83a67fc1d94938cb31f2a9c.
Reason for revert:
1 Test Suite(s) failed. angle_unittests failed because of:
TestUtils.RunApp on Linux CFI
https://ci.chromium.org/p/chromium/builders/ci/Linux%20CFI
Original change's description:
> Add more test_utils functions.
>
> Includes methods for creating temporary files, deleting files, and
> reading files into a string. Also renames GetPathSeparator to mention
> it's only used for environment variables. Includes a new virtual type
> angle::Process that will be used to implement cross-platform async
> Process launching for tests. Also includes a way to specify a custom
> crash handler callback.
>
> Also adds a few unit tests for the new functionality. They are disabled
> on Android because the functions are not needed by the new test runner.
>
> Bug: angleproject:3162
> Change-Id: I3e2c2e9837608884c98379fa0f78c9ffbe158d73
> Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1821940
> Commit-Queue: Jamie Madill <jmadill@chromium.org>
> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
TBR=ynovikov@chromium.org,jonahr@google.com,jmadill@chromium.org
Change-Id: I1441bfbae31712f72b4aebeeea9cd711c3975a5d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: angleproject:3162
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1869254
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/system_utils.cpp b/src/common/system_utils.cpp
index 54693b3..257fc42 100644
--- a/src/common/system_utils.cpp
+++ b/src/common/system_utils.cpp
@@ -22,7 +22,7 @@
else
{
buf = path;
- buf += GetPathSeparatorForEnvironmentVar();
+ buf += GetPathSeparator();
buf += oldValue;
newValue = buf.c_str();
}
diff --git a/src/common/system_utils.h b/src/common/system_utils.h
index ccb4e9d..1191fac 100644
--- a/src/common/system_utils.h
+++ b/src/common/system_utils.h
@@ -22,7 +22,7 @@
bool SetEnvironmentVar(const char *variableName, const char *value);
bool UnsetEnvironmentVar(const char *variableName);
std::string GetEnvironmentVar(const char *variableName);
-const char *GetPathSeparatorForEnvironmentVar();
+const char *GetPathSeparator();
bool PrependPathToEnvironmentVar(const char *variableName, const char *path);
bool IsDirectory(const char *filename);
diff --git a/src/common/system_utils_posix.cpp b/src/common/system_utils_posix.cpp
index d71a073..c8cb68a 100644
--- a/src/common/system_utils_posix.cpp
+++ b/src/common/system_utils_posix.cpp
@@ -18,6 +18,56 @@
namespace angle
{
+
+namespace
+{
+struct ScopedPipe
+{
+ ~ScopedPipe()
+ {
+ closeEndPoint(0);
+ closeEndPoint(1);
+ }
+ void closeEndPoint(int index)
+ {
+ if (fds[index] >= 0)
+ {
+ close(fds[index]);
+ fds[index] = -1;
+ }
+ }
+ int fds[2] = {
+ -1,
+ -1,
+ };
+};
+
+void ReadEntireFile(int fd, std::string *out)
+{
+ out->clear();
+
+ while (true)
+ {
+ char buffer[256];
+ ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
+
+ // If interrupted, retry.
+ if (bytesRead < 0 && errno == EINTR)
+ {
+ continue;
+ }
+
+ // If failed, or nothing to read, we are done.
+ if (bytesRead <= 0)
+ {
+ break;
+ }
+
+ out->append(buffer, bytesRead);
+ }
+}
+} // anonymous namespace
+
Optional<std::string> GetCWD()
{
std::array<char, 4096> pathBuf;
@@ -50,11 +100,117 @@
return (value == nullptr ? std::string() : std::string(value));
}
-const char *GetPathSeparatorForEnvironmentVar()
+const char *GetPathSeparator()
{
return ":";
}
+bool RunApp(const std::vector<const char *> &args,
+ std::string *stdoutOut,
+ std::string *stderrOut,
+ int *exitCodeOut)
+{
+ if (args.size() == 0 || args.back() != nullptr)
+ {
+ return false;
+ }
+
+ ScopedPipe stdoutPipe;
+ ScopedPipe stderrPipe;
+
+ // Create pipes for stdout and stderr.
+ if (stdoutOut && pipe(stdoutPipe.fds) != 0)
+ {
+ return false;
+ }
+ if (stderrOut && pipe(stderrPipe.fds) != 0)
+ {
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0)
+ {
+ return false;
+ }
+
+ if (pid == 0)
+ {
+ // Child. Execute the application.
+
+ // Redirect stdout and stderr to the pipe fds.
+ if (stdoutOut)
+ {
+ if (dup2(stdoutPipe.fds[1], STDOUT_FILENO) < 0)
+ {
+ _exit(errno);
+ }
+ }
+ if (stderrOut)
+ {
+ if (dup2(stderrPipe.fds[1], STDERR_FILENO) < 0)
+ {
+ _exit(errno);
+ }
+ }
+
+ // Execute the application, which doesn't return unless failed. Note: execv takes argv as
+ // `char * const *` for historical reasons. It is safe to const_cast it:
+ //
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
+ //
+ // > The statement about argv[] and envp[] being constants is included to make explicit to
+ // future writers of language bindings that these objects are completely constant. Due to a
+ // limitation of the ISO C standard, it is not possible to state that idea in standard C.
+ // Specifying two levels of const- qualification for the argv[] and envp[] parameters for
+ // the exec functions may seem to be the natural choice, given that these functions do not
+ // modify either the array of pointers or the characters to which the function points, but
+ // this would disallow existing correct code. Instead, only the array of pointers is noted
+ // as constant.
+ execv(args[0], const_cast<char *const *>(args.data()));
+ _exit(errno);
+ }
+
+ // Parent. Read child output from the pipes and clean it up.
+
+ // Close the write end of the pipes, so EOF can be generated when child exits.
+ stdoutPipe.closeEndPoint(1);
+ stderrPipe.closeEndPoint(1);
+
+ // Read back the output of the child.
+ if (stdoutOut)
+ {
+ ReadEntireFile(stdoutPipe.fds[0], stdoutOut);
+ }
+ if (stderrOut)
+ {
+ ReadEntireFile(stderrPipe.fds[0], stderrOut);
+ }
+
+ // Cleanup the child.
+ int status = 0;
+ do
+ {
+ pid_t changedPid = waitpid(pid, &status, 0);
+ if (changedPid < 0 && errno == EINTR)
+ {
+ continue;
+ }
+ if (changedPid < 0)
+ {
+ return false;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ // Retrieve the error code.
+ if (exitCodeOut)
+ {
+ *exitCodeOut = WEXITSTATUS(status);
+ }
+
+ return true;
+}
+
class PosixLibrary : public Library
{
public:
diff --git a/src/common/system_utils_unittest.cpp b/src/common/system_utils_unittest.cpp
index 7b189b9..7a5948a 100644
--- a/src/common/system_utils_unittest.cpp
+++ b/src/common/system_utils_unittest.cpp
@@ -9,11 +9,46 @@
#include "gtest/gtest.h"
#include "common/system_utils.h"
+#include "common/system_utils_unittest_helper.h"
using namespace angle;
namespace
{
+#if defined(ANGLE_PLATFORM_WINDOWS)
+constexpr char kRunAppHelperExecutable[] = "angle_unittests_helper.exe";
+#else
+constexpr char kRunAppHelperExecutable[] = "angle_unittests_helper";
+#endif
+
+// Transforms various line endings into C/Unix line endings:
+//
+// - A\nB -> A\nB
+// - A\rB -> A\nB
+// - A\r\nB -> A\nB
+std::string NormalizeNewLines(const std::string &str)
+{
+ std::string result;
+
+ for (size_t i = 0; i < str.size(); ++i)
+ {
+ if (str[i] == '\r')
+ {
+ if (i + 1 < str.size() && str[i + 1] == '\n')
+ {
+ ++i;
+ }
+ result += '\n';
+ }
+ else
+ {
+ result += str[i];
+ }
+ }
+
+ return result;
+}
+
// Test getting the executable path
TEST(SystemUtils, ExecutablePath)
{
@@ -60,4 +95,48 @@
readback = GetEnvironmentVar(kEnvVarName);
EXPECT_EQ("", readback);
}
+
+// Test running an external application and receiving its output
+TEST(SystemUtils, RunApp)
+{
+#if defined(ANGLE_PLATFORM_ANDROID)
+ // TODO: android support. http://anglebug.com/3125
+ return;
+#endif
+
+#if defined(ANGLE_PLATFORM_FUCHSIA)
+ // TODO: fuchsia support. http://anglebug.com/3161
+ return;
+#endif
+
+ std::string executablePath = GetExecutableDirectory();
+ EXPECT_NE(executablePath, "");
+ executablePath += "/";
+ executablePath += kRunAppHelperExecutable;
+
+ std::vector<const char *> args = {executablePath.c_str(), kRunAppTestArg1, kRunAppTestArg2,
+ nullptr};
+
+ std::string stdoutOutput;
+ std::string stderrOutput;
+ int exitCode = EXIT_FAILURE;
+
+ // Test that the application can be executed.
+ bool ranApp = RunApp(args, &stdoutOutput, &stderrOutput, &exitCode);
+ EXPECT_TRUE(ranApp);
+ EXPECT_EQ(kRunAppTestStdout, NormalizeNewLines(stdoutOutput));
+ EXPECT_EQ(kRunAppTestStderr, NormalizeNewLines(stderrOutput));
+ EXPECT_EQ(EXIT_SUCCESS, exitCode);
+
+ // Test that environment variables reach the cild.
+ bool setEnvDone = SetEnvironmentVar(kRunAppTestEnvVarName, kRunAppTestEnvVarValue);
+ EXPECT_TRUE(setEnvDone);
+
+ ranApp = RunApp(args, &stdoutOutput, &stderrOutput, &exitCode);
+ EXPECT_TRUE(ranApp);
+ EXPECT_EQ("", stdoutOutput);
+ EXPECT_EQ(kRunAppTestEnvVarValue, NormalizeNewLines(stderrOutput));
+ EXPECT_EQ(EXIT_SUCCESS, exitCode);
+}
+
} // anonymous namespace
diff --git a/util/test_utils_unittest_helper.cpp b/src/common/system_utils_unittest_helper.cpp
similarity index 94%
rename from util/test_utils_unittest_helper.cpp
rename to src/common/system_utils_unittest_helper.cpp
index 2604f11..f1bfa69 100644
--- a/util/test_utils_unittest_helper.cpp
+++ b/src/common/system_utils_unittest_helper.cpp
@@ -5,11 +5,9 @@
// system_utils_unittest_helper.cpp: Helper to the SystemUtils.RunApp unittest
-#include "test_utils_unittest_helper.h"
-
-#include "common/system_utils.h"
-
+#include "common/system_utils_unittest_helper.h"
#include <string.h>
+#include "common/system_utils.h"
int main(int argc, char **argv)
{
diff --git a/util/test_utils_unittest_helper.h b/src/common/system_utils_unittest_helper.h
similarity index 100%
rename from util/test_utils_unittest_helper.h
rename to src/common/system_utils_unittest_helper.h
diff --git a/src/common/system_utils_win.cpp b/src/common/system_utils_win.cpp
index 48e26c9..6aa196c 100644
--- a/src/common/system_utils_win.cpp
+++ b/src/common/system_utils_win.cpp
@@ -15,6 +15,56 @@
namespace angle
{
+namespace
+{
+struct ScopedPipe
+{
+ ~ScopedPipe()
+ {
+ closeReadHandle();
+ closeWriteHandle();
+ }
+ void closeReadHandle()
+ {
+ if (readHandle)
+ {
+ CloseHandle(readHandle);
+ readHandle = nullptr;
+ }
+ }
+ void closeWriteHandle()
+ {
+ if (writeHandle)
+ {
+ CloseHandle(writeHandle);
+ writeHandle = nullptr;
+ }
+ }
+ HANDLE readHandle = nullptr;
+ HANDLE writeHandle = nullptr;
+};
+
+void ReadEntireFile(HANDLE handle, std::string *out)
+{
+ out->clear();
+
+ while (true)
+ {
+ char buffer[256];
+ DWORD bytesRead;
+
+ BOOL success = ReadFile(handle, buffer, sizeof(buffer), &bytesRead, nullptr);
+
+ if (!success || bytesRead == 0)
+ {
+ break;
+ }
+
+ out->append(buffer, bytesRead);
+ }
+}
+} // anonymous namespace
+
std::string GetExecutablePath()
{
std::array<char, MAX_PATH> executableFileBuf;
@@ -76,7 +126,7 @@
}
}
-const char *GetPathSeparatorForEnvironmentVar()
+const char *GetPathSeparator()
{
return ";";
}
@@ -92,6 +142,117 @@
return static_cast<double>(curTime.QuadPart) / frequency.QuadPart;
}
+bool RunApp(const std::vector<const char *> &args,
+ std::string *stdoutOut,
+ std::string *stderrOut,
+ int *exitCodeOut)
+{
+ ScopedPipe stdoutPipe;
+ ScopedPipe stderrPipe;
+
+ SECURITY_ATTRIBUTES sa_attr;
+ // Set the bInheritHandle flag so pipe handles are inherited.
+ sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa_attr.bInheritHandle = TRUE;
+ sa_attr.lpSecurityDescriptor = nullptr;
+
+ // Create pipes for stdout and stderr. Ensure the read handles to the pipes are not inherited.
+ if (stdoutOut && !CreatePipe(&stdoutPipe.readHandle, &stdoutPipe.writeHandle, &sa_attr, 0) &&
+ !SetHandleInformation(stdoutPipe.readHandle, HANDLE_FLAG_INHERIT, 0))
+ {
+ return false;
+ }
+ if (stderrOut && !CreatePipe(&stderrPipe.readHandle, &stderrPipe.writeHandle, &sa_attr, 0) &&
+ !SetHandleInformation(stderrPipe.readHandle, HANDLE_FLAG_INHERIT, 0))
+ {
+ return false;
+ }
+
+ // Concat the nicely separated arguments into one string so the application has to reparse it.
+ // We don't support quotation and spaces in arguments currently.
+ std::vector<char> commandLineString;
+ for (const char *arg : args)
+ {
+ if (arg)
+ {
+ if (!commandLineString.empty())
+ {
+ commandLineString.push_back(' ');
+ }
+ commandLineString.insert(commandLineString.end(), arg, arg + strlen(arg));
+ }
+ }
+ commandLineString.push_back('\0');
+
+ STARTUPINFOA startInfo = {};
+
+ startInfo.cb = sizeof(STARTUPINFOA);
+ startInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ if (stdoutOut)
+ {
+ startInfo.hStdOutput = stdoutPipe.writeHandle;
+ }
+ else
+ {
+ startInfo.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ if (stderrOut)
+ {
+ startInfo.hStdError = stderrPipe.writeHandle;
+ }
+ else
+ {
+ startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ }
+
+ if (stderrOut || stdoutOut)
+ {
+ startInfo.dwFlags |= STARTF_USESTDHANDLES;
+ }
+
+ // Create the child process.
+ PROCESS_INFORMATION processInfo = {};
+ if (!CreateProcessA(nullptr, commandLineString.data(), nullptr, nullptr,
+ TRUE, // Handles are inherited.
+ 0, nullptr, nullptr, &startInfo, &processInfo))
+ {
+ return false;
+ }
+
+ // Close the write end of the pipes, so EOF can be generated when child exits.
+ stdoutPipe.closeWriteHandle();
+ stderrPipe.closeWriteHandle();
+
+ // Read back the output of the child.
+ if (stdoutOut)
+ {
+ ReadEntireFile(stdoutPipe.readHandle, stdoutOut);
+ }
+ if (stderrOut)
+ {
+ ReadEntireFile(stderrPipe.readHandle, stderrOut);
+ }
+
+ // Cleanup the child.
+ bool success = WaitForSingleObject(processInfo.hProcess, INFINITE) == WAIT_OBJECT_0;
+
+ if (success)
+ {
+ DWORD exitCode = 0;
+ success = GetExitCodeProcess(processInfo.hProcess, &exitCode);
+
+ if (success)
+ {
+ *exitCodeOut = static_cast<int>(exitCode);
+ }
+ }
+
+ CloseHandle(processInfo.hProcess);
+ CloseHandle(processInfo.hThread);
+
+ return success;
+}
+
class Win32Library : public Library
{
public:
@@ -165,5 +326,4 @@
{
__debugbreak();
}
-
} // namespace angle
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index d0d5dec..1ac3b58 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -45,8 +45,8 @@
}
}
-angle_executable("test_utils_unittest_helper") {
- sources = test_utils_unittest_helper_sources
+angle_executable("angle_unittests_helper") {
+ sources = angle_unittests_helper_sources
deps = [
"${angle_root}:angle_common",
@@ -104,7 +104,7 @@
# SystemUtils.RunApp, the only unittest using a helper binary, is not supported on these
# platforms yet.
data_deps = [
- ":test_utils_unittest_helper",
+ ":angle_unittests_helper",
]
}
}
diff --git a/src/tests/angle_unittests.gni b/src/tests/angle_unittests.gni
index d6a86a3..b1686cc 100644
--- a/src/tests/angle_unittests.gni
+++ b/src/tests/angle_unittests.gni
@@ -15,6 +15,7 @@
"../common/matrix_utils_unittest.cpp",
"../common/string_utils_unittest.cpp",
"../common/system_utils_unittest.cpp",
+ "../common/system_utils_unittest_helper.h",
"../common/utilities_unittest.cpp",
"../common/vector_utils_unittest.cpp",
"../feature_support_util/feature_support_util_unittest.cpp",
@@ -129,8 +130,6 @@
"../tests/test_utils/ShaderCompileTreeTest.h",
"../tests/test_utils/ShaderCompileTreeTest.cpp",
"../tests/test_utils/ShaderExtensionTest.h",
- "../../util/test_utils_unittest.cpp",
- "../../util/test_utils_unittest_helper.h",
]
# TODO(jmadill): should probably call this windows sources
@@ -139,9 +138,9 @@
"../tests/compiler_tests/UnrollFlatten_test.cpp",
]
-test_utils_unittest_helper_sources = [
- "../../util/test_utils_unittest_helper.cpp",
- "../../util/test_utils_unittest_helper.h",
+angle_unittests_helper_sources = [
+ "../common/system_utils_unittest_helper.cpp",
+ "../common/system_utils_unittest_helper.h",
]
if (is_android) {
diff --git a/src/tests/perf_tests/glmark2Benchmark.cpp b/src/tests/perf_tests/glmark2Benchmark.cpp
index 174fcc6..2d5e463 100644
--- a/src/tests/perf_tests/glmark2Benchmark.cpp
+++ b/src/tests/perf_tests/glmark2Benchmark.cpp
@@ -151,9 +151,10 @@
}
args.push_back(nullptr);
- ProcessHandle process(args, true, false);
- ASSERT_TRUE(process && process->started());
- ASSERT_TRUE(process->finish());
+ std::string output;
+ int exitCode;
+
+ bool success = RunApp(args, &output, nullptr, &exitCode);
// Restore the current working directory for the next tests.
if (cwd.valid())
@@ -161,11 +162,11 @@
SetCWD(cwd.value().c_str());
}
- ASSERT_EQ(EXIT_SUCCESS, process->getExitCode());
+ ASSERT_TRUE(success);
+ ASSERT_EQ(EXIT_SUCCESS, exitCode);
if (!OneFrame())
{
- std::string output = process->getStdout();
parseOutput(output, benchmarkName, completeRun);
}
}
diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp
index c0a268e..993185b 100644
--- a/src/tests/test_utils/ANGLETest.cpp
+++ b/src/tests/test_utils/ANGLETest.cpp
@@ -320,15 +320,15 @@
std::vector<const char *> childArgs = commonArgs;
childArgs.push_back(configStr.c_str());
- ProcessHandle process(childArgs, false, false);
- if (!process->started() || !process->finish())
+ int exitCode = 0;
+ if (!RunApp(childArgs, nullptr, nullptr, &exitCode))
{
std::cerr << "Launching child config " << config << " failed.\n";
}
- else if (process->getExitCode() != 0)
+ else if (exitCode != 0)
{
- std::cerr << "Child config " << config << " failed with exit code "
- << process->getExitCode() << ".\n";
+ std::cerr << "Child config " << config << " failed with exit code " << exitCode
+ << ".\n";
success = false;
}
}
@@ -481,7 +481,7 @@
{
mSetUpCalled = true;
- InitCrashHandler(nullptr);
+ InitCrashHandler();
gDefaultPlatformMethods.overrideWorkaroundsD3D = TestPlatform_overrideWorkaroundsD3D;
gDefaultPlatformMethods.overrideFeaturesVk = TestPlatform_overrideFeaturesVk;
diff --git a/util/posix/crash_handler_posix.cpp b/util/posix/crash_handler_posix.cpp
index 64c31a7..e40c4b5 100644
--- a/util/posix/crash_handler_posix.cpp
+++ b/util/posix/crash_handler_posix.cpp
@@ -43,7 +43,7 @@
// No implementations yet.
}
-void InitCrashHandler(CrashCallback *callback)
+void InitCrashHandler()
{
// No implementations yet.
}
@@ -140,7 +140,7 @@
SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP,
};
-void InitCrashHandler(CrashCallback *callback)
+void InitCrashHandler()
{
for (int sig : kSignals)
{
diff --git a/util/posix/test_utils_posix.cpp b/util/posix/test_utils_posix.cpp
index 82c5a70..9d6c82f 100644
--- a/util/posix/test_utils_posix.cpp
+++ b/util/posix/test_utils_posix.cpp
@@ -10,13 +10,10 @@
#include <errno.h>
#include <sched.h>
-#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <cstdarg>
-#include <cstring>
-#include "common/debug.h"
#include "common/platform.h"
#if !defined(ANGLE_PLATFORM_FUCHSIA)
@@ -29,222 +26,6 @@
namespace angle
{
-namespace
-{
-struct ScopedPipe
-{
- ~ScopedPipe()
- {
- closeEndPoint(0);
- closeEndPoint(1);
- }
-
- void closeEndPoint(int index)
- {
- if (fds[index] >= 0)
- {
- close(fds[index]);
- fds[index] = -1;
- }
- }
-
- bool valid() const { return fds[0] != -1 || fds[1] != -1; }
-
- int fds[2] = {
- -1,
- -1,
- };
-};
-
-void ReadEntireFile(int fd, std::string *out)
-{
- out->clear();
-
- while (true)
- {
- char buffer[256];
- ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
-
- // If interrupted, retry.
- if (bytesRead < 0 && errno == EINTR)
- {
- continue;
- }
-
- // If failed, or nothing to read, we are done.
- if (bytesRead <= 0)
- {
- break;
- }
-
- out->append(buffer, bytesRead);
- }
-}
-
-class PosixProcess : public Process
-{
- public:
- PosixProcess(const std::vector<const char *> &commandLineArgs,
- bool captureStdOut,
- bool captureStdErr)
- {
-#if defined(ANGLE_PLATFORM_FUCHSIA)
- ANGLE_UNUSED_VARIABLE(ReadEntireFile);
- ANGLE_UNUSED_VARIABLE(mExitCode);
- ANGLE_UNUSED_VARIABLE(mPID);
-#else
- if (commandLineArgs.empty() || commandLineArgs.back() != nullptr)
- {
- return;
- }
-
- // Create pipes for stdout and stderr.
- if (captureStdOut && pipe(mStdoutPipe.fds) != 0)
- {
- return;
- }
- if (captureStdErr && pipe(mStderrPipe.fds) != 0)
- {
- return;
- }
-
- mPID = fork();
- if (mPID < 0)
- {
- return;
- }
-
- mStarted = true;
-
- if (mPID == 0)
- {
- // Child. Execute the application.
-
- // Redirect stdout and stderr to the pipe fds.
- if (captureStdOut)
- {
- if (dup2(mStdoutPipe.fds[1], STDOUT_FILENO) < 0)
- {
- _exit(errno);
- }
- }
- if (captureStdErr)
- {
- if (dup2(mStderrPipe.fds[1], STDERR_FILENO) < 0)
- {
- _exit(errno);
- }
- }
-
- // Execute the application, which doesn't return unless failed. Note: execv takes argv
- // as `char * const *` for historical reasons. It is safe to const_cast it:
- //
- // http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
- //
- // > The statement about argv[] and envp[] being constants is included to make explicit
- // to future writers of language bindings that these objects are completely constant.
- // Due to a limitation of the ISO C standard, it is not possible to state that idea in
- // standard C. Specifying two levels of const- qualification for the argv[] and envp[]
- // parameters for the exec functions may seem to be the natural choice, given that these
- // functions do not modify either the array of pointers or the characters to which the
- // function points, but this would disallow existing correct code. Instead, only the
- // array of pointers is noted as constant.
- execv(commandLineArgs[0], const_cast<char *const *>(commandLineArgs.data()));
- _exit(errno);
- }
- // Parent continues execution.
-#endif // defined(ANGLE_PLATFORM_FUCHSIA)
- }
-
- ~PosixProcess() override {}
-
- bool started() override { return mStarted; }
-
- bool finish() override
- {
- if (!mStarted)
- {
- return false;
- }
-
-#if defined(ANGLE_PLATFORM_FUCHSIA)
- return false;
-#else
- // Close the write end of the pipes, so EOF can be generated when child exits.
- // Then read back the output of the child.
- if (mStdoutPipe.valid())
- {
- mStdoutPipe.closeEndPoint(1);
- ReadEntireFile(mStdoutPipe.fds[0], &mStdout);
- }
- if (mStderrPipe.valid())
- {
- mStderrPipe.closeEndPoint(1);
- ReadEntireFile(mStderrPipe.fds[0], &mStderr);
- }
-
- // Cleanup the child.
- int status = 0;
- do
- {
- pid_t changedPid = waitpid(mPID, &status, 0);
- if (changedPid < 0 && errno == EINTR)
- {
- continue;
- }
- if (changedPid < 0)
- {
- return false;
- }
- } while (!WIFEXITED(status) && !WIFSIGNALED(status));
-
- // Retrieve the error code.
- mExitCode = WEXITSTATUS(status);
- return true;
-#endif // defined(ANGLE_PLATFORM_FUCHSIA)
- }
-
- bool finished() override
- {
- if (!mStarted)
- {
- return false;
- }
-
- return (::kill(mPID, 0) != 0);
- }
-
- int getExitCode() override { return 0; }
-
- bool kill() override
- {
- if (!mStarted)
- {
- return false;
- }
-
- if (finished())
- {
- return true;
- }
-
- return (::kill(mPID, SIGTERM) == 0);
- }
-
- private:
- bool mStarted = false;
- ScopedPipe mStdoutPipe;
- ScopedPipe mStderrPipe;
- int mExitCode = 0;
- pid_t mPID = -1;
-};
-
-std::string TempFileName()
-{
- return std::string(".angle.XXXXXX");
-}
-} // anonymous namespace
-
void Sleep(unsigned int milliseconds)
{
// On Windows Sleep(0) yields while it isn't guaranteed by Posix's sleep
@@ -313,68 +94,4 @@
return false;
#endif
}
-
-bool GetTempDir(char *tempDirOut, uint32_t maxDirNameLen)
-{
- const char *tmp = getenv("TMPDIR");
- if (tmp)
- {
- strncpy(tempDirOut, tmp, maxDirNameLen);
- return true;
- }
-
-#if defined(ANGLE_PLATFORM_ANDROID)
- // TODO(jmadill): Android support. http://anglebug.com/3162
- // return PathService::Get(DIR_CACHE, path);
- return false;
-#else
- strncpy(tempDirOut, "/tmp", maxDirNameLen);
- return true;
-#endif
-}
-
-bool CreateTemporaryFileInDir(const char *dir, char *tempFileNameOut, uint32_t maxFileNameLen)
-{
- std::string tempFile = TempFileName();
- sprintf(tempFileNameOut, "%s/%s", dir, tempFile.c_str());
- int fd = mkstemp(tempFileNameOut);
- close(fd);
- return fd != -1;
-}
-
-bool DeleteFile(const char *path)
-{
- return unlink(path) == 0;
-}
-
-Process *LaunchProcess(const std::vector<const char *> &args,
- bool captureStdout,
- bool captureStderr)
-{
- return new PosixProcess(args, captureStdout, captureStderr);
-}
-
-int NumberOfProcessors()
-{
- // sysconf returns the number of "logical" (not "physical") processors on both
- // Mac and Linux. So we get the number of max available "logical" processors.
- //
- // Note that the number of "currently online" processors may be fewer than the
- // returned value of NumberOfProcessors(). On some platforms, the kernel may
- // make some processors offline intermittently, to save power when system
- // loading is low.
- //
- // One common use case that needs to know the processor count is to create
- // optimal number of threads for optimization. It should make plan according
- // to the number of "max available" processors instead of "currently online"
- // ones. The kernel should be smart enough to make all processors online when
- // it has sufficient number of threads waiting to run.
- long res = sysconf(_SC_NPROCESSORS_CONF);
- if (res == -1)
- {
- return 1;
- }
-
- return static_cast<int>(res);
-}
} // namespace angle
diff --git a/util/shader_utils.cpp b/util/shader_utils.cpp
index 17b8c85..518608e 100644
--- a/util/shader_utils.cpp
+++ b/util/shader_utils.cpp
@@ -4,26 +4,33 @@
// found in the LICENSE file.
//
-#include "util/shader_utils.h"
+#include "shader_utils.h"
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>
-#include "util/test_utils.h"
-
namespace
{
-bool ReadEntireFile(const std::string &filePath, std::string *contentsOut)
+std::string ReadFileToString(const std::string &source)
{
- constexpr uint32_t kMaxBufferSize = 2000;
- char buffer[kMaxBufferSize] = {};
- if (!angle::ReadEntireFileToString(filePath.c_str(), buffer, kMaxBufferSize) ||
- strlen(buffer) == 0)
- return false;
- *contentsOut = buffer;
- return true;
+ std::ifstream stream(source.c_str());
+ if (!stream)
+ {
+ std::cerr << "Failed to load shader file: " << source;
+ return "";
+ }
+
+ std::string result;
+
+ stream.seekg(0, std::ios::end);
+ result.reserve(static_cast<unsigned int>(stream.tellg()));
+ stream.seekg(0, std::ios::beg);
+
+ result.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
+
+ return result;
}
GLuint CompileProgramInternal(const char *vsSource,
@@ -117,10 +124,9 @@
GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
{
- std::string source;
- if (!ReadEntireFile(sourcePath, &source))
+ std::string source = ReadFileToString(sourcePath);
+ if (source.empty())
{
- std::cerr << "Error reading shader file: " << sourcePath << "\n";
return 0;
}
@@ -208,17 +214,10 @@
GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
{
- std::string vsSource;
- if (!ReadEntireFile(vsPath, &vsSource))
+ std::string vsSource = ReadFileToString(vsPath);
+ std::string fsSource = ReadFileToString(fsPath);
+ if (vsSource.empty() || fsSource.empty())
{
- std::cerr << "Error reading shader: " << vsPath << "\n";
- return 0;
- }
-
- std::string fsSource;
- if (!ReadEntireFile(fsPath, &fsSource))
- {
- std::cerr << "Error reading shader: " << fsPath << "\n";
return 0;
}
diff --git a/util/test_utils.cpp b/util/test_utils.cpp
deleted file mode 100644
index ac4dc8f..0000000
--- a/util/test_utils.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright 2019 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// system_utils: Defines common utility functions
-
-#include "util/test_utils.h"
-
-#include <cstring>
-#include <fstream>
-
-namespace angle
-{
-bool CreateTemporaryFile(char *tempFileNameOut, uint32_t maxFileNameLen)
-{
- constexpr uint32_t kMaxPath = 1000u;
- char tempPath[kMaxPath];
-
- if (!GetTempDir(tempPath, kMaxPath))
- return false;
-
- return CreateTemporaryFileInDir(tempPath, tempFileNameOut, maxFileNameLen);
-}
-
-bool GetFileSize(const char *filePath, uint32_t *sizeOut)
-{
- std::ifstream stream(filePath);
- if (!stream)
- {
- return false;
- }
-
- stream.seekg(0, std::ios::end);
- *sizeOut = static_cast<uint32_t>(stream.tellg());
- return true;
-}
-
-bool ReadEntireFileToString(const char *filePath, char *contentsOut, uint32_t maxLen)
-{
- std::ifstream stream(filePath);
- if (!stream)
- {
- return false;
- }
-
- std::string contents;
-
- stream.seekg(0, std::ios::end);
- contents.reserve(static_cast<unsigned int>(stream.tellg()));
- stream.seekg(0, std::ios::beg);
-
- contents.assign((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
-
- strncpy(contentsOut, contents.c_str(), maxLen);
- return true;
-}
-
-// static
-Process::~Process() = default;
-
-ProcessHandle::ProcessHandle() : mProcess(nullptr) {}
-
-ProcessHandle::ProcessHandle(Process *process) : mProcess(process) {}
-
-ProcessHandle::ProcessHandle(const std::vector<const char *> &args,
- bool captureStdout,
- bool captureStderr)
- : mProcess(LaunchProcess(args, captureStdout, captureStderr))
-{}
-
-ProcessHandle::~ProcessHandle()
-{
- reset();
-}
-
-ProcessHandle::ProcessHandle(ProcessHandle &&other) : mProcess(other.mProcess)
-{
- other.mProcess = nullptr;
-}
-
-ProcessHandle &ProcessHandle::operator=(ProcessHandle &&rhs)
-{
- std::swap(mProcess, rhs.mProcess);
- return *this;
-}
-
-void ProcessHandle::reset()
-{
- if (mProcess)
- {
- delete mProcess;
- mProcess = nullptr;
- }
-}
-} // namespace angle
diff --git a/util/test_utils.h b/util/test_utils.h
index fe8a969..6a4951d 100644
--- a/util/test_utils.h
+++ b/util/test_utils.h
@@ -9,12 +9,9 @@
#ifndef UTIL_TEST_UTILS_H_
#define UTIL_TEST_UTILS_H_
-#include <functional>
#include <string>
#include <vector>
-#include "common/angleutils.h"
-#include "util/Timer.h"
#include "util/util_export.h"
namespace angle
@@ -31,96 +28,12 @@
ANGLE_UTIL_EXPORT bool StabilizeCPUForBenchmarking();
// Set a crash handler to print stack traces.
-using CrashCallback = std::function<void()>;
-ANGLE_UTIL_EXPORT void InitCrashHandler(CrashCallback *callback);
+ANGLE_UTIL_EXPORT void InitCrashHandler();
ANGLE_UTIL_EXPORT void TerminateCrashHandler();
// Print a stack back trace.
ANGLE_UTIL_EXPORT void PrintStackBacktrace();
-// Get temporary directory.
-ANGLE_UTIL_EXPORT bool GetTempDir(char *tempDirOut, uint32_t maxDirNameLen);
-
-// Creates a temporary file. The full path is placed in |path|, and the
-// function returns true if was successful in creating the file. The file will
-// be empty and all handles closed after this function returns.
-ANGLE_UTIL_EXPORT bool CreateTemporaryFile(char *tempFileNameOut, uint32_t maxFileNameLen);
-
-// Same as CreateTemporaryFile but the file is created in |dir|.
-ANGLE_UTIL_EXPORT bool CreateTemporaryFileInDir(const char *dir,
- char *tempFileNameOut,
- uint32_t maxFileNameLen);
-
-// Deletes a file or directory.
-ANGLE_UTIL_EXPORT bool DeleteFile(const char *path);
-
-// Reads a file contents into a string.
-ANGLE_UTIL_EXPORT bool ReadEntireFileToString(const char *filePath,
- char *contentsOut,
- uint32_t maxLen);
-
-// Compute a file's size.
-ANGLE_UTIL_EXPORT bool GetFileSize(const char *filePath, uint32_t *sizeOut);
-
-class ProcessHandle;
-
-class ANGLE_UTIL_EXPORT Process : angle::NonCopyable
-{
- public:
- virtual bool started() = 0;
- virtual bool finished() = 0;
- virtual bool finish() = 0;
- virtual bool kill() = 0;
- virtual int getExitCode() = 0;
-
- double getElapsedTimeSeconds() const { return mTimer.getElapsedTime(); }
- const std::string &getStdout() const { return mStdout; }
- const std::string &getStderr() const { return mStderr; }
-
- protected:
- friend class ProcessHandle;
- virtual ~Process();
-
- Timer mTimer;
- std::string mStdout;
- std::string mStderr;
-};
-
-class ANGLE_UTIL_EXPORT ProcessHandle final : angle::NonCopyable
-{
- public:
- ProcessHandle();
- ProcessHandle(Process *process);
- ProcessHandle(const std::vector<const char *> &args, bool captureStdout, bool captureStderr);
- ~ProcessHandle();
- ProcessHandle(ProcessHandle &&other);
- ProcessHandle &operator=(ProcessHandle &&rhs);
-
- Process *operator->() { return mProcess; }
- const Process *operator->() const { return mProcess; }
-
- operator bool() const { return mProcess != nullptr; }
-
- void reset();
-
- private:
- Process *mProcess;
-};
-
-// Launch a process and optionally get the output. Uses a vector of c strings as command line
-// arguments to the child process. Returns a Process handle which can be used to retrieve
-// the stdout and stderr outputs as well as the exit code.
-//
-// Pass false for stdoutOut/stderrOut if you don't need to capture them.
-//
-// On success, returns a Process pointer with started() == true.
-// On failure, returns a Process pointer with started() == false.
-ANGLE_UTIL_EXPORT Process *LaunchProcess(const std::vector<const char *> &args,
- bool captureStdout,
- bool captureStderr);
-
-ANGLE_UTIL_EXPORT int NumberOfProcessors();
-
} // namespace angle
#endif // UTIL_TEST_UTILS_H_
diff --git a/util/test_utils_unittest.cpp b/util/test_utils_unittest.cpp
deleted file mode 100644
index 380d43f..0000000
--- a/util/test_utils_unittest.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-// Copyright 2019 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// test_utils_unittest.cpp: Unit tests for ANGLE's test utility functions
-
-#include "gtest/gtest.h"
-
-#include "common/system_utils.h"
-#include "util/Timer.h"
-#include "util/test_utils.h"
-#include "util/test_utils_unittest_helper.h"
-
-using namespace angle;
-
-namespace
-{
-#if defined(ANGLE_PLATFORM_WINDOWS)
-constexpr char kRunAppHelperExecutable[] = "test_utils_unittest_helper.exe";
-#else
-constexpr char kRunAppHelperExecutable[] = "test_utils_unittest_helper";
-#endif
-
-// Transforms various line endings into C/Unix line endings:
-//
-// - A\nB -> A\nB
-// - A\rB -> A\nB
-// - A\r\nB -> A\nB
-std::string NormalizeNewLines(const std::string &str)
-{
- std::string result;
-
- for (size_t i = 0; i < str.size(); ++i)
- {
- if (str[i] == '\r')
- {
- if (i + 1 < str.size() && str[i + 1] == '\n')
- {
- ++i;
- }
- result += '\n';
- }
- else
- {
- result += str[i];
- }
- }
-
- return result;
-}
-
-// Tests that Sleep() actually waits some time.
-TEST(TestUtils, Sleep)
-{
- Timer timer;
- timer.start();
- angle::Sleep(500);
- timer.stop();
-
- // Use a slightly fuzzy range
- EXPECT_GT(timer.getElapsedTime(), 0.48);
-}
-
-constexpr uint32_t kMaxPath = 1000;
-
-// Temporary file creation is not supported on Android right now.
-#if defined(ANGLE_PLATFORM_ANDROID)
-# define MAYBE_CreateAndDeleteTemporaryFile DISABLED_CreateAndDeleteTemporaryFile
-# define MAYBE_CreateAndDeleteFileInTempDir DISABLED_CreateAndDeleteFileInTempDir
-#else
-# define MAYBE_CreateAndDeleteTemporaryFile CreateAndDeleteTemporaryFile
-# define MAYBE_CreateAndDeleteFileInTempDir CreateAndDeleteFileInTempDir
-#endif // defined(ANGLE_PLATFORM_ANDROID)
-
-// Test creating and deleting temporary file.
-TEST(TestUtils, MAYBE_CreateAndDeleteTemporaryFile)
-{
- char path[kMaxPath] = {};
- ASSERT_TRUE(CreateTemporaryFile(path, kMaxPath));
- ASSERT_TRUE(strlen(path) > 0);
-
- const char kOutputString[] = "test output";
-
- FILE *fp = fopen(path, "wt");
- ASSERT_NE(fp, nullptr);
- int retval = fputs(kOutputString, fp);
- fclose(fp);
-
- EXPECT_GE(retval, 0);
-
- // Test ReadEntireFileToString
- char actualString[kMaxPath];
- EXPECT_TRUE(ReadEntireFileToString(path, actualString, kMaxPath));
- EXPECT_EQ(strcmp(actualString, kOutputString), 0);
-
- // Delete the temporary file.
- EXPECT_TRUE(angle::DeleteFile(path));
-}
-
-// Tests creating and deleting a file in the system temp dir.
-TEST(TestUtils, MAYBE_CreateAndDeleteFileInTempDir)
-{
- char tempDir[kMaxPath];
- ASSERT_TRUE(GetTempDir(tempDir, kMaxPath));
-
- char path[kMaxPath] = {};
- ASSERT_TRUE(CreateTemporaryFileInDir(tempDir, path, kMaxPath));
- ASSERT_TRUE(strlen(path) > 0);
-
- const char kOutputString[] = "test output";
-
- FILE *fp = fopen(path, "wt");
- ASSERT_NE(fp, nullptr);
- int retval = fputs(kOutputString, fp);
- fclose(fp);
-
- EXPECT_GE(retval, 0);
-
- // Test ReadEntireFileToString
- char actualString[kMaxPath];
- EXPECT_TRUE(ReadEntireFileToString(path, actualString, kMaxPath));
- EXPECT_EQ(strcmp(actualString, kOutputString), 0);
-
- // Delete the temporary file.
- EXPECT_TRUE(angle::DeleteFile(path));
-}
-
-// Test running an external application and receiving its output
-TEST(TestUtils, RunApp)
-{
-#if defined(ANGLE_PLATFORM_ANDROID)
- // TODO: android support. http://anglebug.com/3125
- return;
-#endif
-
-#if defined(ANGLE_PLATFORM_FUCHSIA)
- // TODO: fuchsia support. http://anglebug.com/3161
- return;
-#endif
-
- std::string executablePath = GetExecutableDirectory();
- EXPECT_NE(executablePath, "");
- executablePath += "/";
- executablePath += kRunAppHelperExecutable;
-
- std::vector<const char *> args = {executablePath.c_str(), kRunAppTestArg1, kRunAppTestArg2,
- nullptr};
-
- // Test that the application can be executed.
- {
- ProcessHandle process(args, true, true);
- EXPECT_TRUE(process->started());
- EXPECT_TRUE(process->finish());
- EXPECT_TRUE(process->finished());
-
- EXPECT_EQ(kRunAppTestStdout, NormalizeNewLines(process->getStdout()));
- EXPECT_EQ(kRunAppTestStderr, NormalizeNewLines(process->getStderr()));
- EXPECT_EQ(EXIT_SUCCESS, process->getExitCode());
- }
-
- // Test that environment variables reach the cild.
- {
- bool setEnvDone = SetEnvironmentVar(kRunAppTestEnvVarName, kRunAppTestEnvVarValue);
- EXPECT_TRUE(setEnvDone);
-
- ProcessHandle process(LaunchProcess(args, true, true));
- EXPECT_TRUE(process->started());
- EXPECT_TRUE(process->finish());
-
- EXPECT_EQ("", process->getStdout());
- EXPECT_EQ(kRunAppTestEnvVarValue, NormalizeNewLines(process->getStderr()));
- EXPECT_EQ(EXIT_SUCCESS, process->getExitCode());
- }
-}
-
-// Verify that NumberOfProcessors returns something sane.
-TEST(TestUtils, NumberOfProcessors)
-{
- int numProcs = angle::NumberOfProcessors();
- EXPECT_GT(numProcs, 0);
- EXPECT_LT(numProcs, 1000);
-}
-} // namespace
diff --git a/util/util.gni b/util/util.gni
index fa1b336..4304cae 100644
--- a/util/util.gni
+++ b/util/util.gni
@@ -12,7 +12,6 @@
"util/random_utils.h",
"util/shader_utils.cpp",
"util/shader_utils.h",
- "util/test_utils.cpp",
"util/test_utils.h",
"util/util_export.h",
"util/util_gl.h",
diff --git a/util/windows/test_utils_win.cpp b/util/windows/test_utils_win.cpp
index 3349d1a..05a44c8 100644
--- a/util/windows/test_utils_win.cpp
+++ b/util/windows/test_utils_win.cpp
@@ -11,14 +11,8 @@
#include <stdarg.h>
#include <windows.h>
#include <array>
-#include <iostream>
-#include <vector>
-
-#include <aclapi.h>
#include "common/angleutils.h"
-
-#include "anglebase/no_destructor.h"
#include "util/windows/third_party/StackWalker/src/StackWalker.h"
namespace angle
@@ -111,312 +105,6 @@
// The compiler wants us to return something. This is what we'd do if we didn't _exit().
return EXCEPTION_EXECUTE_HANDLER;
}
-
-CrashCallback *gCrashHandlerCallback;
-
-LONG WINAPI CrashHandler(EXCEPTION_POINTERS *e)
-{
- if (gCrashHandlerCallback)
- {
- (*gCrashHandlerCallback)();
- }
- return StackTraceCrashHandler(e);
-}
-
-struct ScopedPipe
-{
- ~ScopedPipe()
- {
- closeReadHandle();
- closeWriteHandle();
- }
- bool closeReadHandle()
- {
- if (readHandle)
- {
- if (::CloseHandle(readHandle) == FALSE)
- {
- std::cerr << "Error closing write handle: " << GetLastError();
- return false;
- }
- readHandle = nullptr;
- }
-
- return true;
- }
- bool closeWriteHandle()
- {
- if (writeHandle)
- {
- if (::CloseHandle(writeHandle) == FALSE)
- {
- std::cerr << "Error closing write handle: " << GetLastError();
- return false;
- }
- writeHandle = nullptr;
- }
-
- return true;
- }
-
- bool valid() const { return readHandle != nullptr || writeHandle != nullptr; }
-
- bool initPipe(SECURITY_ATTRIBUTES *securityAttribs)
- {
- if (::CreatePipe(&readHandle, &writeHandle, securityAttribs, 0) == FALSE)
- {
- std::cerr << "Error creating pipe: " << GetLastError() << "\n";
- return false;
- }
-
- // Ensure the read handles to the pipes are not inherited.
- if (::SetHandleInformation(readHandle, HANDLE_FLAG_INHERIT, 0) == FALSE)
- {
- std::cerr << "Error setting handle info on pipe: " << GetLastError() << "\n";
- return false;
- }
-
- return true;
- }
-
- HANDLE readHandle = nullptr;
- HANDLE writeHandle = nullptr;
-};
-
-// Returns false on EOF or error.
-void ReadFromFile(bool blocking, HANDLE handle, std::string *out)
-{
- char buffer[8192];
- DWORD bytesRead = 0;
-
- while (true)
- {
- if (!blocking)
- {
- BOOL success = ::PeekNamedPipe(handle, nullptr, 0, nullptr, &bytesRead, nullptr);
- if (success == FALSE || bytesRead == 0)
- return;
- }
-
- BOOL success = ::ReadFile(handle, buffer, sizeof(buffer), &bytesRead, nullptr);
- if (success == FALSE || bytesRead == 0)
- return;
-
- out->append(buffer, bytesRead);
- }
-
- // unreachable.
-}
-
-// Returns the Win32 last error code or ERROR_SUCCESS if the last error code is
-// ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND. This is useful in cases where
-// the absence of a file or path is a success condition (e.g., when attempting
-// to delete an item in the filesystem).
-bool ReturnSuccessOnNotFound()
-{
- const DWORD error_code = ::GetLastError();
- return (error_code == ERROR_FILE_NOT_FOUND || error_code == ERROR_PATH_NOT_FOUND);
-}
-
-class WindowsProcess : public Process
-{
- public:
- WindowsProcess(const std::vector<const char *> &commandLineArgs,
- bool captureStdOut,
- bool captureStdErr)
- {
- mProcessInfo.hProcess = INVALID_HANDLE_VALUE;
- mProcessInfo.hThread = INVALID_HANDLE_VALUE;
-
- std::vector<char> commandLineString;
- for (const char *arg : commandLineArgs)
- {
- if (arg)
- {
- if (!commandLineString.empty())
- {
- commandLineString.push_back(' ');
- }
- commandLineString.insert(commandLineString.end(), arg, arg + strlen(arg));
- }
- }
- commandLineString.push_back('\0');
-
- // Set the bInheritHandle flag so pipe handles are inherited.
- SECURITY_ATTRIBUTES securityAttribs;
- securityAttribs.nLength = sizeof(SECURITY_ATTRIBUTES);
- securityAttribs.bInheritHandle = TRUE;
- securityAttribs.lpSecurityDescriptor = nullptr;
-
- STARTUPINFOA startInfo = {};
-
- // Create pipes for stdout and stderr.
- startInfo.cb = sizeof(STARTUPINFOA);
- startInfo.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
- if (captureStdOut)
- {
- if (!mStdoutPipe.initPipe(&securityAttribs))
- {
- return;
- }
- startInfo.hStdOutput = mStdoutPipe.writeHandle;
- }
- else
- {
- startInfo.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
- }
-
- if (captureStdErr)
- {
- if (!mStderrPipe.initPipe(&securityAttribs))
- {
- return;
- }
- startInfo.hStdError = mStderrPipe.writeHandle;
- }
- else
- {
- startInfo.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
- }
-
- if (captureStdOut || captureStdErr)
- {
- startInfo.dwFlags |= STARTF_USESTDHANDLES;
- }
-
- // Create the child process.
- if (::CreateProcessA(nullptr, commandLineString.data(), nullptr, nullptr,
- TRUE, // Handles are inherited.
- 0, nullptr, nullptr, &startInfo, &mProcessInfo) == FALSE)
- {
- std::cerr << "CreateProcessA Error code: " << GetLastError() << "\n";
- return;
- }
-
- // Close the write end of the pipes, so EOF can be generated when child exits.
- if (!mStdoutPipe.closeWriteHandle() || !mStderrPipe.closeWriteHandle())
- return;
-
- mStarted = true;
- mTimer.start();
- }
-
- ~WindowsProcess() override
- {
- if (mProcessInfo.hProcess != INVALID_HANDLE_VALUE)
- {
- ::CloseHandle(mProcessInfo.hProcess);
- }
- if (mProcessInfo.hThread != INVALID_HANDLE_VALUE)
- {
- ::CloseHandle(mProcessInfo.hThread);
- }
- }
-
- bool started() override { return mStarted; }
-
- bool finish() override
- {
- if (mStdoutPipe.valid())
- {
- ReadFromFile(true, mStdoutPipe.readHandle, &mStdout);
- }
-
- if (mStderrPipe.valid())
- {
- ReadFromFile(true, mStderrPipe.readHandle, &mStderr);
- }
-
- DWORD result = ::WaitForSingleObject(mProcessInfo.hProcess, INFINITE);
- mTimer.stop();
- return result == WAIT_OBJECT_0;
- }
-
- bool finished() override
- {
- if (!mStarted)
- return false;
-
- // Pipe stdin and stdout.
- if (mStdoutPipe.valid())
- {
- ReadFromFile(false, mStdoutPipe.readHandle, &mStdout);
- }
-
- if (mStderrPipe.valid())
- {
- ReadFromFile(false, mStderrPipe.readHandle, &mStderr);
- }
-
- DWORD result = ::WaitForSingleObject(mProcessInfo.hProcess, 0);
- if (result == WAIT_OBJECT_0)
- {
- mTimer.stop();
- return true;
- }
- if (result == WAIT_TIMEOUT)
- return false;
-
- mTimer.stop();
- std::cerr << "Unexpected result from WaitForSingleObject: " << result
- << ". Last error: " << ::GetLastError() << "\n";
- return false;
- }
-
- int getExitCode() override
- {
- if (!mStarted)
- return -1;
-
- if (mProcessInfo.hProcess == INVALID_HANDLE_VALUE)
- return -1;
-
- DWORD exitCode = 0;
- if (::GetExitCodeProcess(mProcessInfo.hProcess, &exitCode) == FALSE)
- return -1;
-
- return static_cast<int>(exitCode);
- }
-
- bool kill() override
- {
- if (!mStarted)
- return true;
-
- HANDLE newHandle;
- if (::DuplicateHandle(::GetCurrentProcess(), mProcessInfo.hProcess, ::GetCurrentProcess(),
- &newHandle, PROCESS_ALL_ACCESS, false,
- DUPLICATE_CLOSE_SOURCE) == FALSE)
- {
- std::cerr << "Error getting permission to terminate process: " << ::GetLastError()
- << "\n";
- return false;
- }
- mProcessInfo.hProcess = newHandle;
-
- if (::TerminateThread(mProcessInfo.hThread, 1) == FALSE)
- {
- std::cerr << "TerminateThread failed: " << GetLastError() << "\n";
- return false;
- }
-
- if (::TerminateProcess(mProcessInfo.hProcess, 1) == FALSE)
- {
- std::cerr << "TerminateProcess failed: " << GetLastError() << "\n";
- return false;
- }
-
- mStarted = false;
- mTimer.stop();
- return true;
- }
-
- private:
- bool mStarted = false;
- ScopedPipe mStdoutPipe;
- ScopedPipe mStderrPipe;
- PROCESS_INFORMATION mProcessInfo = {};
-};
} // anonymous namespace
void Sleep(unsigned int milliseconds)
@@ -439,18 +127,13 @@
OutputDebugStringA(buffer.data());
}
-void InitCrashHandler(CrashCallback *callback)
+void InitCrashHandler()
{
- if (callback)
- {
- gCrashHandlerCallback = callback;
- }
- SetUnhandledExceptionFilter(CrashHandler);
+ SetUnhandledExceptionFilter(StackTraceCrashHandler);
}
void TerminateCrashHandler()
{
- gCrashHandlerCallback = nullptr;
SetUnhandledExceptionFilter(nullptr);
}
@@ -461,61 +144,4 @@
RtlCaptureContext(&context);
PrintBacktrace(&context);
}
-
-Process *LaunchProcess(const std::vector<const char *> &args,
- bool captureStdout,
- bool captureStderr)
-{
- return new WindowsProcess(args, captureStdout, captureStderr);
-}
-
-bool GetTempDir(char *tempDirOut, uint32_t maxDirNameLen)
-{
- DWORD pathLen = ::GetTempPathA(maxDirNameLen, tempDirOut);
- return (pathLen < MAX_PATH && pathLen > 0);
-}
-
-bool CreateTemporaryFileInDir(const char *dir, char *tempFileNameOut, uint32_t maxFileNameLen)
-{
- char fileName[MAX_PATH + 1];
- if (::GetTempFileNameA(dir, "ANGLE", 0, fileName) == 0)
- return false;
-
- strncpy(tempFileNameOut, fileName, maxFileNameLen);
- return true;
-}
-
-bool DeleteFile(const char *path)
-{
- if (strlen(path) >= MAX_PATH)
- return false;
-
- const DWORD attr = ::GetFileAttributesA(path);
- // Report success if the file or path does not exist.
- if (attr == INVALID_FILE_ATTRIBUTES)
- {
- return ReturnSuccessOnNotFound();
- }
-
- // Clear the read-only bit if it is set.
- if ((attr & FILE_ATTRIBUTE_READONLY) &&
- !::SetFileAttributesA(path, attr & ~FILE_ATTRIBUTE_READONLY))
- {
- // It's possible for |path| to be gone now under a race with other deleters.
- return ReturnSuccessOnNotFound();
- }
-
- // We don't handle directories right now.
- if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
- {
- return false;
- }
-
- return !!::DeleteFileA(path) ? true : ReturnSuccessOnNotFound();
-}
-
-int NumberOfProcessors()
-{
- return ::GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
-}
} // namespace angle
diff --git a/util/windows/win32/test_utils_win32.cpp b/util/windows/win32/test_utils_win32.cpp
index 9e08b23..4f4aa8d 100644
--- a/util/windows/win32/test_utils_win32.cpp
+++ b/util/windows/win32/test_utils_win32.cpp
@@ -11,10 +11,9 @@
#include <windows.h>
#include <array>
-#include "util/random_utils.h"
-
namespace angle
{
+
void SetLowPriorityProcess()
{
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
@@ -22,15 +21,15 @@
bool StabilizeCPUForBenchmarking()
{
- if (::SetThreadAffinityMask(::GetCurrentThread(), 1) == 0)
+ if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0)
{
return false;
}
- if (::SetPriorityClass(::GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == FALSE)
+ if (SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS) == FALSE)
{
return false;
}
- if (::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == FALSE)
+ if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) == FALSE)
{
return false;
}