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 <bruce.cherniak@intel.com>
This commit is contained in:
George Kyriazis 2018-01-19 18:03:16 -06:00
parent 2d16b61bff
commit 0b46c7b3b0
3 changed files with 169 additions and 34 deletions

View 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;
}

View 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__

View 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;