From 0b46c7b3b00d93132bab028017cdfdec1693ed7d Mon Sep 17 00:00:00 2001 From: George Kyriazis Date: Fri, 19 Jan 2018 18:03:16 -0600 Subject: [PATCH] swr/rast: Better ExecCmd (i.e. system()) implmentation Hides console window creation during JIT linker execution in apps that don't have a console. Remove hooking of CreateProcessInternalA - the MSFT implementation just turns around and calls CreateProcessInternalW which, we do hook. Reviewed-by: Bruce Cherniak --- .../drivers/swr/rasterizer/common/os.cpp | 158 ++++++++++++++++++ .../drivers/swr/rasterizer/common/os.h | 9 + .../swr/rasterizer/jitter/JitManager.cpp | 36 +--- 3 files changed, 169 insertions(+), 34 deletions(-) diff --git a/src/gallium/drivers/swr/rasterizer/common/os.cpp b/src/gallium/drivers/swr/rasterizer/common/os.cpp index 27ad5e90b66..2d97270b997 100644 --- a/src/gallium/drivers/swr/rasterizer/common/os.cpp +++ b/src/gallium/drivers/swr/rasterizer/common/os.cpp @@ -23,6 +23,7 @@ #include "common/os.h" #include +#include #include #if defined(_WIN32) @@ -151,3 +152,160 @@ void SWR_API CreateDirectoryPath(const std::string& path) } #endif // Unix } + +/// Execute Command (block until finished) +/// @returns process exit value +int SWR_API ExecCmd( + const std::string& cmd, ///< (In) Command line string + const char* pOptEnvStrings, ///< (Optional In) Environment block for new process + std::string* pOptStdOut, ///< (Optional Out) Standard Output text + std::string* pOptStdErr, ///< (Optional Out) Standard Error text + const std::string* pOptStdIn) ///< (Optional In) Standard Input text +{ + int rvalue = -1; + +#if defined(_WIN32) + struct WinPipe + { + HANDLE hRead; + HANDLE hWrite; + }; + std::array hPipes = {}; + + SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) }; + saAttr.bInheritHandle = TRUE; //Pipe handles are inherited by child process. + saAttr.lpSecurityDescriptor = NULL; + + { + bool bFail = false; + for (WinPipe& p : hPipes) + { + if (!CreatePipe(&p.hRead, &p.hWrite, &saAttr, 0)) + { + bFail = true; + } + } + + if (bFail) + { + for (WinPipe& p : hPipes) + { + CloseHandle(p.hRead); + CloseHandle(p.hWrite); + } + return rvalue; + } + } + + STARTUPINFOA StartupInfo{}; + StartupInfo.cb = sizeof(STARTUPINFOA); + StartupInfo.dwFlags = STARTF_USESTDHANDLES; + StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; + StartupInfo.wShowWindow = SW_HIDE; + if (pOptStdIn) + { + StartupInfo.hStdInput = hPipes[0].hRead; + } + StartupInfo.hStdOutput = hPipes[1].hWrite; + StartupInfo.hStdError = hPipes[2].hWrite; + PROCESS_INFORMATION procInfo{}; + + // CreateProcess can modify the string + std::string local_cmd = cmd; + + BOOL ProcessValue = CreateProcessA( + NULL, + (LPSTR)local_cmd.c_str(), + NULL, + NULL, + TRUE, + 0, + (LPVOID)pOptEnvStrings, + NULL, + &StartupInfo, + &procInfo); + + if (ProcessValue && procInfo.hProcess) + { + auto ReadFromPipe = [](HANDLE hPipe, std::string* pOutStr) + { + char buf[1024]; + DWORD dwRead = 0; + DWORD dwAvail = 0; + while (true) + { + if (!::PeekNamedPipe(hPipe, NULL, 0, NULL, &dwAvail, NULL)) + { + break; + } + + if (!dwAvail) // no data available, return + { + break; + } + + if (!::ReadFile(hPipe, buf, std::min(sizeof(buf) - 1, size_t(dwAvail)), &dwRead, NULL) || !dwRead) + { + // error, the child process might ended + break; + } + + buf[dwRead] = 0; + if (pOutStr) + { + (*pOutStr) += buf; + } + } + }; + bool bProcessEnded = false; + size_t bytesWritten = 0; + do + { + if (pOptStdIn && (pOptStdIn->size() > bytesWritten)) + { + DWORD bytesToWrite = static_cast(pOptStdIn->size()) - bytesWritten; + if (!::WriteFile( + hPipes[0].hWrite, + pOptStdIn->data() + bytesWritten, + bytesToWrite, &bytesToWrite, nullptr)) + { + // Failed to write to pipe + break; + } + bytesWritten += bytesToWrite; + } + + // Give some timeslice (50ms), so we won't waste 100% cpu. + bProcessEnded = (WaitForSingleObject(procInfo.hProcess, 50) == WAIT_OBJECT_0); + + ReadFromPipe(hPipes[1].hRead, pOptStdOut); + ReadFromPipe(hPipes[2].hRead, pOptStdErr); + } + while (!bProcessEnded); + + DWORD exitVal = 0; + if (!GetExitCodeProcess(procInfo.hProcess, &exitVal)) + { + exitVal = 1; + } + + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); + + rvalue = exitVal; + } + + for (WinPipe& p : hPipes) + { + CloseHandle(p.hRead); + CloseHandle(p.hWrite); + } + +#else + + // Non-Windows implementation + +#endif + + return rvalue; +} diff --git a/src/gallium/drivers/swr/rasterizer/common/os.h b/src/gallium/drivers/swr/rasterizer/common/os.h index c7e87e28904..5cfd12ff72a 100644 --- a/src/gallium/drivers/swr/rasterizer/common/os.h +++ b/src/gallium/drivers/swr/rasterizer/common/os.h @@ -280,4 +280,13 @@ typedef MEGABYTE GIGABYTE[1024]; void SWR_API SetCurrentThreadName(const char* pThreadName); void SWR_API CreateDirectoryPath(const std::string& path); +/// Execute Command (block until finished) +/// @returns process exit value +int SWR_API ExecCmd( + const std::string& cmd, ///< (In) Command line string + const char* pOptEnvStrings = nullptr, ///< (Optional In) Environment block for new process + std::string* pOptStdOut = nullptr, ///< (Optional Out) Standard Output text + std::string* pOptStdErr = nullptr, ///< (Optional Out) Standard Error text + const std::string* pOptStdIn = nullptr); ///< (Optional In) Standard Input text + #endif//__SWR_OS_H__ diff --git a/src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp b/src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp index 5a71ab6a4f8..675438be72f 100644 --- a/src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp +++ b/src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp @@ -599,44 +599,12 @@ JitCache::JitCache() } } -#if defined(_WIN32) -int ExecUnhookedProcess(const char* pCmdLine) +int ExecUnhookedProcess(const std::string& CmdLine, std::string* pStdOut, std::string* pStdErr) { static const char *g_pEnv = "RASTY_DISABLE_HOOK=1\0"; - STARTUPINFOA StartupInfo{}; - StartupInfo.cb = sizeof(STARTUPINFOA); - PROCESS_INFORMATION procInfo{}; - - BOOL ProcessValue = CreateProcessA( - NULL, - (LPSTR)pCmdLine, - NULL, - NULL, - TRUE, - 0, - (LPVOID)g_pEnv, - NULL, - &StartupInfo, - &procInfo); - - if (ProcessValue && procInfo.hProcess) - { - WaitForSingleObject(procInfo.hProcess, INFINITE); - DWORD exitVal = 0; - if (!GetExitCodeProcess(procInfo.hProcess, &exitVal)) - { - exitVal = 1; - } - - CloseHandle(procInfo.hProcess); - - return exitVal; - } - - return -1; + return ExecCmd(CmdLine, g_pEnv, pStdOut, pStdErr); } -#endif #if defined(_WIN64) && defined(ENABLE_JIT_DEBUG) && defined(JIT_BASE_DIR) EXTERN_C IMAGE_DOS_HEADER __ImageBase; -- 2.30.2