diff options
author | Mikhail Glushenkov <foldr@codedgers.com> | 2009-07-18 21:43:12 +0000 |
---|---|---|
committer | Mikhail Glushenkov <foldr@codedgers.com> | 2009-07-18 21:43:12 +0000 |
commit | 3140619c63d205d79b8eac1d88afa918981fa258 (patch) | |
tree | 24b3dc75a8edeed8867f7aa5c4c6aadb52063881 /lib/System | |
parent | 617dd7baa6dfd3a7b5ee72ace37f6b6aeaa6006b (diff) |
Remove duplication in Program::Execute{And,No}Wait.
Implemented by moving the code out of static functions into methods of Program
class.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76340 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/System')
-rw-r--r-- | lib/System/Program.cpp | 27 | ||||
-rw-r--r-- | lib/System/Unix/Program.inc | 116 | ||||
-rw-r--r-- | lib/System/Win32/Program.inc | 224 |
3 files changed, 91 insertions, 276 deletions
diff --git a/lib/System/Program.cpp b/lib/System/Program.cpp index eb289d81b2..a3049d46fd 100644 --- a/lib/System/Program.cpp +++ b/lib/System/Program.cpp @@ -22,6 +22,33 @@ using namespace sys; //=== independent code. //===----------------------------------------------------------------------===// +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + return prg.Wait(secondsToWait, ErrMsg); + else + return -1; +} + +void +Program::ExecuteNoWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +} + + } // Include the platform-specific parts of this class. diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc index 342b45cdd3..d4e88fd6d1 100644 --- a/lib/System/Unix/Program.inc +++ b/lib/System/Unix/Program.inc @@ -142,49 +142,47 @@ static void SetMemoryLimits (unsigned size) #endif } -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg) +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { if (!path.canExecute()) { if (ErrMsg) *ErrMsg = path.toString() + " is not executable"; - return -1; + return false; } -#ifdef HAVE_SYS_WAIT_H // Create a child process. int child = fork(); switch (child) { // An error occured: Return to the caller. case -1: MakeErrMsg(ErrMsg, "Couldn't fork"); - return -1; + return false; // Child process: Execute the program. case 0: { // Redirect file descriptors... if (redirects) { // Redirect stdin - if (RedirectIO(redirects[0], 0, ErrMsg)) { return -1; } + if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } // Redirect stdout - if (RedirectIO(redirects[1], 1, ErrMsg)) { return -1; } + if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr // to the FD already open for stdout. if (-1 == dup2(1,2)) { MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); - return -1; + return false; } } else { // Just redirect stderr - if (RedirectIO(redirects[2], 2, ErrMsg)) { return -1; } + if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } } } @@ -214,8 +212,23 @@ Program::ExecuteAndWait(const Path& path, fsync(1); fsync(2); + Pid_ = child; + + return true; +} + +int +Program::Wait(unsigned secondsToWait, + std::string* ErrMsg) +{ +#ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; + if (Pid_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + // Install a timeout handler. if (secondsToWait) { Timeout = false; @@ -229,6 +242,7 @@ Program::ExecuteAndWait(const Path& path, // Parent process: Wait for the child process to terminate. int status; + int child = this->Pid_; while (wait(&status) != child) if (secondsToWait && errno == EINTR) { // Kill the child. @@ -274,78 +288,6 @@ Program::ExecuteAndWait(const Path& path, } -void -Program::ExecuteNoWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) -{ - if (!path.canExecute()) { - if (ErrMsg) - *ErrMsg = path.toString() + " is not executable"; - return; - } - - // Create a child process. - int child = fork(); - switch (child) { - // An error occured: Return to the caller. - case -1: - MakeErrMsg(ErrMsg, "Couldn't fork"); - return; - - // Child process: Execute the program. - case 0: { - // Redirect file descriptors... - if (redirects) { - // Redirect stdin - if (RedirectIO(redirects[0], 0, ErrMsg)) { return; } - // Redirect stdout - if (RedirectIO(redirects[1], 1, ErrMsg)) { return; } - if (redirects[1] && redirects[2] && - *(redirects[1]) == *(redirects[2])) { - // If stdout and stderr should go to the same place, redirect stderr - // to the FD already open for stdout. - if (-1 == dup2(1,2)) { - MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); - return; - } - } else { - // Just redirect stderr - if (RedirectIO(redirects[2], 2, ErrMsg)) { return; } - } - } - - // Set memory limits - if (memoryLimit!=0) { - SetMemoryLimits(memoryLimit); - } - - // Execute! - if (envp != 0) - execve (path.c_str(), (char**)args, (char**)envp); - else - execv (path.c_str(), (char**)args); - // If the execve() failed, we should exit and let the parent pick up - // our non-zero exit status. - exit (errno); - } - - // Parent process: Break out of the switch to do our processing. - default: - break; - } - - // Make sure stderr and stdout have been flushed - std::cerr << std::flush; - std::cout << std::flush; - fsync(1); - fsync(2); - -} - bool Program::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return false; diff --git a/lib/System/Win32/Program.inc b/lib/System/Win32/Program.inc index 71f686ca02..7dbfb3e632 100644 --- a/lib/System/Win32/Program.inc +++ b/lib/System/Win32/Program.inc @@ -109,18 +109,17 @@ static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { DWORD cbJobObjectInfoLength); #endif -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg) { +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { if (!path.canExecute()) { if (ErrMsg) *ErrMsg = "program not executable"; - return -1; + return false; } // Windows wants a command line, not an array of args, to pass to the new @@ -195,13 +194,13 @@ Program::ExecuteAndWait(const Path& path, si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); if (si.hStdInput == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, "can't redirect stdin"); - return -1; + return false; } si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); if (si.hStdOutput == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); MakeErrMsg(ErrMsg, "can't redirect stdout"); - return -1; + return false; } if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { // If stdout and stderr should go to the same place, redirect stderr @@ -216,7 +215,7 @@ Program::ExecuteAndWait(const Path& path, CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); MakeErrMsg(ErrMsg, "can't redirect stderr"); - return -1; + return false; } } } @@ -242,8 +241,9 @@ Program::ExecuteAndWait(const Path& path, SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + path.toString() + "'"); - return -1; + return false; } + Pid_ = pi.dwProcessId; // Make sure these get closed no matter what. AutoHandle hProcess(pi.hProcess); @@ -270,204 +270,50 @@ Program::ExecuteAndWait(const Path& path, MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); TerminateProcess(pi.hProcess, 1); WaitForSingleObject(pi.hProcess, INFINITE); - return -1; + return false; } } - // Wait for it to terminate. + return true; +} + +int +Program::Wait(unsigned secondsToWait, + std::string* ErrMsg) { + if (Pid_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + AutoHandle hProcess = OpenProcess(SYNCHRONIZE, FALSE, Pid_); + + // Wait for the process to terminate. DWORD millisecondsToWait = INFINITE; if (secondsToWait > 0) millisecondsToWait = secondsToWait * 1000; - if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(pi.hProcess, 1)) { - MakeErrMsg(ErrMsg, std::string("Failed to terminate timed-out program '") - + path.toString() + "'"); + if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { + if (!TerminateProcess(hProcess, 1)) { + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); return -1; } - WaitForSingleObject(pi.hProcess, INFINITE); + WaitForSingleObject(hProcess, INFINITE); } // Get its exit status. DWORD status; - rc = GetExitCodeProcess(pi.hProcess, &status); - err = GetLastError(); + BOOL rc = GetExitCodeProcess(hProcess, &status); + DWORD err = GetLastError(); if (!rc) { SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Failed getting status for program '") + - path.toString() + "'"); + MakeErrMsg(ErrMsg, "Failed getting status for program."); return -1; } return status; } -void -Program::ExecuteNoWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - if (!path.canExecute()) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return; - } - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces. - - // First, determine the length of the command line. - unsigned len = 0; - for (unsigned i = 0; args[i]; i++) { - len += strlen(args[i]) + 1; - if (strchr(args[i], ' ')) - len += 2; - } - - // Now build the command line. - char *command = reinterpret_cast<char *>(_alloca(len+1)); - char *p = command; - - for (unsigned i = 0; args[i]; i++) { - const char *arg = args[i]; - size_t len = strlen(arg); - bool needsQuoting = strchr(arg, ' ') != 0; - if (needsQuoting) - *p++ = '"'; - memcpy(p, arg, len); - p += len; - if (needsQuoting) - *p++ = '"'; - *p++ = ' '; - } - - *p = 0; - - // The pointer to the environment block for the new process. - char *envblock = 0; - - 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. - - // 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<char *>(_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; - } - - *p = 0; - } - - // Create a child process. - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - if (redirects) { - si.dwFlags = STARTF_USESTDHANDLES; - - si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); - if (si.hStdInput == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, "can't redirect stdin"); - return; - } - si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); - if (si.hStdOutput == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - MakeErrMsg(ErrMsg, "can't redirect stdout"); - return; - } - 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); - } else { - // Just redirect stderr - si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); - if (si.hStdError == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't redirect stderr"); - return; - } - } - } - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - - fflush(stdout); - fflush(stderr); - BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, - envblock, NULL, &si, &pi); - DWORD err = GetLastError(); - - // Regardless of whether the process got created or not, we are done with - // the handles we created for it to inherit. - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - // Now return an error if the process didn't get created. - if (!rc) - { - SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.toString() + "'"); - return; - } - - // Make sure these get closed no matter what. - AutoHandle hProcess(pi.hProcess); - AutoHandle hThread(pi.hThread); - - // Assign the process to a job if a memory limit is defined. - AutoHandle hJob(0); - if (memoryLimit != 0) { - hJob = CreateJobObject(0, 0); - bool success = false; - if (hJob != 0) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; - if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, - &jeli, sizeof(jeli))) { - if (AssignProcessToJobObject(hJob, pi.hProcess)) - success = true; - } - } - if (!success) { - SetLastError(GetLastError()); - MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); - TerminateProcess(pi.hProcess, 1); - WaitForSingleObject(pi.hProcess, INFINITE); - return; - } - } -} - bool Program::ChangeStdinToBinary(){ int result = _setmode( _fileno(stdin), _O_BINARY ); return result == -1; |