swr: fix build with mingw
[mesa.git] / src / gallium / drivers / swr / rasterizer / common / os.cpp
index 27ad5e90b66b66ff18cfc1bc781d33345133f98f..a40745f30fcabceb04e0ebdfb64d60b6bc8e4bb9 100644 (file)
@@ -1,28 +1,29 @@
 /****************************************************************************
-* Copyright (C) 2017 Intel Corporation.   All Rights Reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a
-* copy of this software and associated documentation files (the "Software"),
-* to deal in the Software without restriction, including without limitation
-* the rights to use, copy, modify, merge, publish, distribute, sublicense,
-* and/or sell copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice (including the next
-* paragraph) shall be included in all copies or substantial portions of the
-* Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-* IN THE SOFTWARE.
-****************************************************************************/
+ * Copyright (C) 2017 Intel Corporation.   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ****************************************************************************/
 
 #include "common/os.h"
 #include <vector>
+#include <array>
 #include <sstream>
 
 #if defined(_WIN32)
 #include <pthread.h>
 #endif // Linux
 
-
-
-#if defined(_WIN32)
+#if defined(_MSC_VER)
 static const DWORD MS_VC_EXCEPTION = 0x406D1388;
 
-#pragma pack(push,8)  
+#pragma pack(push, 8)
 typedef struct tagTHREADNAME_INFO
 {
-    DWORD dwType; // Must be 0x1000.  
-    LPCSTR szName; // Pointer to name (in user addr space).  
-    DWORD dwThreadID; // Thread ID (-1=caller thread).  
-    DWORD dwFlags; // Reserved for future use, must be zero.  
+    DWORD  dwType;     // Must be 0x1000.
+    LPCSTR szName;     // Pointer to name (in user addr space).
+    DWORD  dwThreadID; // Thread ID (-1=caller thread).
+    DWORD  dwFlags;    // Reserved for future use, must be zero.
 } THREADNAME_INFO;
 #pragma pack(pop)
 
 void LegacySetThreadName(const char* pThreadName)
 {
     THREADNAME_INFO info;
-    info.dwType = 0x1000;
-    info.szName = pThreadName;
+    info.dwType     = 0x1000;
+    info.szName     = pThreadName;
     info.dwThreadID = GetCurrentThreadId();
-    info.dwFlags = 0;
+    info.dwFlags    = 0;
 
     if (!IsDebuggerPresent())
     {
@@ -62,38 +61,38 @@ void LegacySetThreadName(const char* pThreadName)
         return;
     }
 
-#pragma warning(push)  
-#pragma warning(disable: 6320 6322)  
-    __try {
+#pragma warning(push)
+#pragma warning(disable : 6320 6322)
+    __try
+    {
         RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
     }
-    __except (EXCEPTION_EXECUTE_HANDLER) {
+    __except (EXCEPTION_EXECUTE_HANDLER)
+    {
     }
-#pragma warning(pop)  
+#pragma warning(pop)
 }
 #endif // _WIN32
 
 void SWR_API SetCurrentThreadName(const char* pThreadName)
 {
-#if defined(_WIN32)
+#if defined(_MSC_VER)
     // The SetThreadDescription API was brought in version 1607 of Windows 10.
-    typedef HRESULT(WINAPI* PFNSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
+    typedef HRESULT(WINAPI * PFNSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
     // The SetThreadDescription API works even if no debugger is attached.
-    auto pfnSetThreadDescription =
-        reinterpret_cast<PFNSetThreadDescription>(
-            GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"));
+    auto pfnSetThreadDescription = reinterpret_cast<PFNSetThreadDescription>(
+        GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"));
 
     if (!pfnSetThreadDescription)
     {
         // try KernelBase.dll
-        pfnSetThreadDescription =
-            reinterpret_cast<PFNSetThreadDescription>(
-                GetProcAddress(GetModuleHandleA("KernelBase.dll"), "SetThreadDescription"));
+        pfnSetThreadDescription = reinterpret_cast<PFNSetThreadDescription>(
+            GetProcAddress(GetModuleHandleA("KernelBase.dll"), "SetThreadDescription"));
     }
 
     if (pfnSetThreadDescription)
     {
-        std::string utf8Name = pThreadName;
+        std::string  utf8Name = pThreadName;
         std::wstring wideName;
         wideName.resize(utf8Name.size() + 1);
         swprintf_s(&(wideName.front()), wideName.size(), L"%S", utf8Name.c_str());
@@ -112,12 +111,13 @@ void SWR_API SetCurrentThreadName(const char* pThreadName)
 #endif // Linux
 }
 
-static void SplitString(std::vector<std::string>& out_segments, const std::string& input, char splitToken)
+static void
+SplitString(std::vector<std::string>& out_segments, const std::string& input, char splitToken)
 {
     out_segments.clear();
 
     std::istringstream f(input);
-    std::string s;
+    std::string        s;
     while (std::getline(f, s, splitToken))
     {
         if (s.size())
@@ -151,3 +151,162 @@ 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;
+}