swr/rast: Better ExecCmd (i.e. system()) implmentation
authorGeorge Kyriazis <george.kyriazis@intel.com>
Sat, 20 Jan 2018 00:03:16 +0000 (18:03 -0600)
committerGeorge Kyriazis <george.kyriazis@intel.com>
Thu, 25 Jan 2018 19:26:49 +0000 (13:26 -0600)
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 <bruce.cherniak@intel.com>
src/gallium/drivers/swr/rasterizer/common/os.cpp
src/gallium/drivers/swr/rasterizer/common/os.h
src/gallium/drivers/swr/rasterizer/jitter/JitManager.cpp

index 27ad5e90b66b66ff18cfc1bc781d33345133f98f..2d97270b997532e96c668ce87c03c45889a353e2 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "common/os.h"
 #include <vector>
+#include <array>
 #include <sstream>
 
 #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<WinPipe, 3> 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<size_t>(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<DWORD>(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;
+}
index c7e87e28904aacef41a14c8c1f82544c377dfa4e..5cfd12ff72a788cd50cc56ca6f4810fdd7c7aba5 100644 (file)
@@ -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__
index 5a71ab6a4f85f3e2fa0fd5985d84df6c57e452fa..675438be72f947579fac732c8f236faf52905ff4 100644 (file)
@@ -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;