X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FWindows%2FProgram.inc;h=dc09738e2e71dc204199b3ec314e0a16e839b814;hb=8753ba91d28cd0fe7e6767466dec320b1fe2af86;hp=ee0f90742860fbc18fdedc27649df058e5639e08;hpb=f3fa6837bf880ada8c2d43e798c2d62148aacd1f;p=oota-llvm.git diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index ee0f9074286..dc09738e2e7 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "Windows.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/FileSystem.h" #include #include #include @@ -22,83 +24,78 @@ //=== and must not be UNIX code //===----------------------------------------------------------------------===// -namespace { - struct Win32ProcessInfo { - HANDLE hProcess; - DWORD dwProcessId; - }; -} - namespace llvm { using namespace sys; +ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} + // This function just uses the PATH environment variable to find the program. std::string sys::FindProgramByName(const std::string &progName) { // Check some degenerate cases if (progName.length() == 0) // no program return ""; - Path temp; - if (!temp.set(progName)) // invalid name - return ""; + std::string temp = progName; // Return paths with slashes verbatim. if (progName.find('\\') != std::string::npos || progName.find('/') != std::string::npos) - return temp.str(); + return temp; // At this point, the file name is valid and does not contain slashes. // Let Windows search for it. - char buffer[MAX_PATH]; - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - buffer, &dummy); - - // See if it wasn't found. - if (len == 0) + SmallVector progNameUnicode; + if (windows::UTF8ToUTF16(progName, progNameUnicode)) return ""; - // See if we got the entire path. - if (len < MAX_PATH) - return std::string(buffer); - - // Buffer was too small; grow and retry. - while (true) { - char *b = reinterpret_cast(_alloca(len+1)); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); + SmallVector buffer; + DWORD len = MAX_PATH; + do { + buffer.reserve(len); + len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe", + buffer.capacity(), buffer.data(), NULL); - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) + // See if it wasn't found. + if (len == 0) return ""; - else if (len2 <= len) - return std::string(b); - len = len2; - } + // Buffer was too small; grow and retry. + } while (len > buffer.capacity()); + + buffer.set_size(len); + SmallVector result; + if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result)) + return ""; + + return std::string(result.data(), result.size()); } -static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { +static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { HANDLE h; if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + return INVALID_HANDLE_VALUE; return h; } - const char *fname; - if (path->isEmpty()) + std::string fname; + if (path->empty()) fname = "NUL"; else - fname = path->c_str(); + fname = *path; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; - h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, - &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); + SmallVector fnameUnicode; + if (windows::UTF8ToUTF16(fname, fnameUnicode)) + return INVALID_HANDLE_VALUE; + + h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + (fd ? "input: " : "output: ")); @@ -170,14 +167,10 @@ static unsigned int ArgLenWithQuotes(const char *Str) { } -static bool Execute(void **Data, - const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - if (!path.canExecute()) { +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, + const char **envp, const StringRef **redirects, + unsigned memoryLimit, std::string *ErrMsg) { + if (!sys::fs::can_execute(Program)) { if (ErrMsg) *ErrMsg = "program not executable"; return false; @@ -194,8 +187,8 @@ static bool Execute(void **Data, } // Now build the command line. - char *command = reinterpret_cast(_alloca(len+1)); - char *p = command; + OwningArrayPtr command(new char[len+1]); + char *p = command.get(); for (unsigned i = 0; args[i]; i++) { const char *arg = args[i]; @@ -226,34 +219,28 @@ static bool Execute(void **Data, *p = 0; // The pointer to the environment block for the new process. - char *envblock = 0; + std::vector EnvBlock; if (envp) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. + for (unsigned i = 0; envp[i]; ++i) { + SmallVector EnvString; + if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); + return false; + } - // First, determine the length of the environment block. - len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock = reinterpret_cast(_alloca(len+1)); - p = envblock; - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; + EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); + EnvBlock.push_back(0); } - - *p = 0; + EnvBlock.push_back(0); } // Create a child process. - STARTUPINFO si; + STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; @@ -277,9 +264,14 @@ static bool Execute(void **Data, if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); + if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); + return false; + } } else { // Just redirect stderr si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); @@ -297,8 +289,27 @@ static bool Execute(void **Data, fflush(stdout); fflush(stderr); - BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, - envblock, NULL, &si, &pi); + + SmallVector ProgramUtf16; + if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert application name to UTF-16")); + return false; + } + + SmallVector CommandUtf16; + if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) { + SetLastError(ec.value()); + MakeErrMsg(ErrMsg, + std::string("Unable to convert command-line to UTF-16")); + return false; + } + + BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, + TRUE, CREATE_UNICODE_ENVIRONMENT, + EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, + &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with @@ -311,15 +322,12 @@ static bool Execute(void **Data, if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.str() + "'"); + Program.str() + "'"); return false; } - if (Data) { - Win32ProcessInfo* wpi = new Win32ProcessInfo; - wpi->hProcess = pi.hProcess; - wpi->dwProcessId = pi.dwProcessId; - *Data = wpi; - } + + PI.Pid = pi.dwProcessId; + PI.ProcessHandle = pi.hProcess; // Make sure these get closed no matter what. ScopedCommonHandle hThread(pi.hThread); @@ -327,7 +335,7 @@ static bool Execute(void **Data, // Assign the process to a job if a memory limit is defined. ScopedJobHandle hJob; if (memoryLimit != 0) { - hJob = CreateJobObject(0, 0); + hJob = CreateJobObjectW(0, 0); bool success = false; if (hJob) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; @@ -349,68 +357,72 @@ static bool Execute(void **Data, } } - // Don't leak the handle if the caller doesn't want it. - if (!Data) - CloseHandle(pi.hProcess); - return true; } -static int WaitAux(Win32ProcessInfo *wpi, unsigned secondsToWait, - std::string *ErrMsg) { - // Wait for the process to terminate. - HANDLE hProcess = wpi->hProcess; - DWORD millisecondsToWait = INFINITE; - if (secondsToWait > 0) - millisecondsToWait = secondsToWait * 1000; - - if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(hProcess, 1)) { - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); - // -2 indicates a crash or timeout as opposed to failure to execute. - return -2; +namespace llvm { +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilChildTerminates, std::string *ErrMsg) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + assert(PI.ProcessHandle && + "invalid process handle to wait on, process not started?"); + DWORD milliSecondsToWait = 0; + if (WaitUntilChildTerminates) + milliSecondsToWait = INFINITE; + else if (SecondsToWait > 0) + milliSecondsToWait = SecondsToWait * 1000; + + ProcessInfo WaitResult = PI; + DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait); + if (WaitStatus == WAIT_TIMEOUT) { + if (SecondsToWait) { + if (!TerminateProcess(PI.ProcessHandle, 1)) { + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); + + // -2 indicates a crash or timeout as opposed to failure to execute. + WaitResult.ReturnCode = -2; + CloseHandle(PI.ProcessHandle); + return WaitResult; + } + WaitForSingleObject(PI.ProcessHandle, INFINITE); + CloseHandle(PI.ProcessHandle); + } else { + // Non-blocking wait. + return ProcessInfo(); } - WaitForSingleObject(hProcess, INFINITE); } // Get its exit status. DWORD status; - BOOL rc = GetExitCodeProcess(hProcess, &status); + BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status); DWORD err = GetLastError(); + CloseHandle(PI.ProcessHandle); if (!rc) { SetLastError(err); - MakeErrMsg(ErrMsg, "Failed getting status for program."); + if (ErrMsg) + MakeErrMsg(ErrMsg, "Failed getting status for program."); + // -2 indicates a crash or timeout as opposed to failure to execute. - return -2; + WaitResult.ReturnCode = -2; + return WaitResult; } if (!status) - return 0; + return WaitResult; // Pass 10(Warning) and 11(Error) to the callee as negative value. if ((status & 0xBFFF0000U) == 0x80000000U) - return (int)status; - - if (status & 0xFF) - return status & 0x7FFFFFFF; - - return 1; -} - -static int Wait(void *&Data, const Path &path, unsigned secondsToWait, - std::string *ErrMsg) { - Win32ProcessInfo *wpi = reinterpret_cast(Data); - int Ret = WaitAux(wpi, secondsToWait, ErrMsg); - - CloseHandle(wpi->hProcess); - delete wpi; - Data = 0; + WaitResult.ReturnCode = static_cast(status); + else if (status & 0xFF) + WaitResult.ReturnCode = status & 0x7FFFFFFF; + else + WaitResult.ReturnCode = 1; - return Ret; + return WaitResult; } -namespace llvm { error_code sys::ChangeStdinToBinary(){ int result = _setmode( _fileno(stdin), _O_BINARY ); if (result == -1) @@ -447,5 +459,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef Args) { } return true; } - }