X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FSupport%2FUnix%2FProgram.inc;h=7bf6eceda73389b35f75037abc72aa787e9e3527;hp=a93a9120eaa97638d48788c7fefea1135b7bc975;hb=f6066a7fd359459256ad8d589a74e02af462c982;hpb=8b68480453b472fbc49aebc49c37e3ef4cad66cb diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index a93a9120eaa..7bf6eceda73 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -19,6 +19,7 @@ #include "Unix.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" #include #if HAVE_SYS_STAT_H #include @@ -36,6 +37,9 @@ #include #endif #ifdef HAVE_POSIX_SPAWN +#ifdef __sun__ +#define _RESTRICT_KYWD +#endif #include #if !defined(__APPLE__) extern char **environ; @@ -45,8 +49,11 @@ #endif namespace llvm { + using namespace sys; +ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} + // This function just uses the PATH environment variable to find the program. std::string sys::FindProgramByName(const std::string& progName) { @@ -65,7 +72,7 @@ sys::FindProgramByName(const std::string& progName) { // Get the path. If its empty, we can't do anything to find it. const char *PathStr = getenv("PATH"); - if (PathStr == 0) + if (!PathStr) return ""; // Now we have a colon separated list of directories to search; try them. @@ -94,7 +101,7 @@ sys::FindProgramByName(const std::string& progName) { } static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) { - if (Path == 0) // Noop + if (!Path) // Noop return false; std::string File; if (Path->empty()) @@ -124,7 +131,7 @@ static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) { #ifdef HAVE_POSIX_SPAWN static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg, posix_spawn_file_actions_t *FileActions) { - if (Path == 0) // Noop + if (!Path) // Noop return false; const char *File; if (Path->empty()) @@ -175,15 +182,22 @@ static void SetMemoryLimits (unsigned size) } -static bool Execute(void **Data, StringRef Program, const char **args, +static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, const char **envp, const StringRef **redirects, unsigned memoryLimit, std::string *ErrMsg) { + if (!llvm::sys::fs::exists(Program)) { + if (ErrMsg) + *ErrMsg = std::string("Executable \"") + Program.str() + + std::string("\" doesn't exist!"); + return false; + } + // If this OS has posix_spawn and there is no memory limit being implied, use // posix_spawn. It is more efficient than fork/exec. #ifdef HAVE_POSIX_SPAWN if (memoryLimit == 0) { posix_spawn_file_actions_t FileActionsStore; - posix_spawn_file_actions_t *FileActions = 0; + posix_spawn_file_actions_t *FileActions = nullptr; // If we call posix_spawn_file_actions_addopen we have to make sure the // c strings we pass to it stay alive until the call to posix_spawn, @@ -191,7 +205,7 @@ static bool Execute(void **Data, StringRef Program, const char **args, std::string RedirectsStorage[3]; if (redirects) { - std::string *RedirectsStr[3] = {0, 0, 0}; + std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr}; for (int I = 0; I < 3; ++I) { if (redirects[I]) { RedirectsStorage[I] = *redirects[I]; @@ -206,7 +220,7 @@ static bool Execute(void **Data, StringRef Program, const char **args, if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) || RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions)) return false; - if (redirects[1] == 0 || redirects[2] == 0 || + if (redirects[1] == nullptr || redirects[2] == nullptr || *redirects[1] != *redirects[2]) { // Just redirect stderr if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions)) @@ -230,8 +244,9 @@ static bool Execute(void **Data, StringRef Program, const char **args, // Explicitly initialized to prevent what appears to be a valgrind false // positive. pid_t PID = 0; - int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, /*attrp*/0, - const_cast(args), const_cast(envp)); + int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, + /*attrp*/nullptr, const_cast(args), + const_cast(envp)); if (FileActions) posix_spawn_file_actions_destroy(FileActions); @@ -239,8 +254,8 @@ static bool Execute(void **Data, StringRef Program, const char **args, if (Err) return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); - if (Data) - *Data = reinterpret_cast(PID); + PI.Pid = PID; + return true; } #endif @@ -282,7 +297,7 @@ static bool Execute(void **Data, StringRef Program, const char **args, // Execute! std::string PathStr = Program; - if (envp != 0) + if (envp != nullptr) execve(PathStr.c_str(), const_cast(args), const_cast(envp)); @@ -303,58 +318,76 @@ static bool Execute(void **Data, StringRef Program, const char **args, break; } - if (Data) - *Data = reinterpret_cast(child); + PI.Pid = child; return true; } -static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, - std::string *ErrMsg) { +namespace llvm { + +ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilTerminates, std::string *ErrMsg) { #ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; - assert(Data && "invalid pid to wait on, process not started?"); - - // Install a timeout handler. The handler itself does nothing, but the simple - // fact of having a handler at all causes the wait below to return with EINTR, - // unlike if we used SIG_IGN. - if (secondsToWait) { + assert(PI.Pid && "invalid pid to wait on, process not started?"); + + int WaitPidOptions = 0; + pid_t ChildPid = PI.Pid; + if (WaitUntilTerminates) { + SecondsToWait = 0; + } else if (SecondsToWait) { + // Install a timeout handler. The handler itself does nothing, but the + // simple fact of having a handler at all causes the wait below to return + // with EINTR, unlike if we used SIG_IGN. memset(&Act, 0, sizeof(Act)); Act.sa_handler = TimeOutHandler; sigemptyset(&Act.sa_mask); sigaction(SIGALRM, &Act, &Old); - alarm(secondsToWait); - } + alarm(SecondsToWait); + } else if (SecondsToWait == 0) + WaitPidOptions = WNOHANG; // Parent process: Wait for the child process to terminate. int status; - uint64_t pid = reinterpret_cast(Data); - pid_t child = static_cast(pid); - while (waitpid(pid, &status, 0) != child) - if (secondsToWait && errno == EINTR) { - // Kill the child. - kill(child, SIGKILL); - - // Turn off the alarm and restore the signal handler - alarm(0); - sigaction(SIGALRM, &Old, 0); - - // Wait for child to die - if (wait(&status) != child) - MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); - else - MakeErrMsg(ErrMsg, "Child timed out", 0); - - return -2; // Timeout detected - } else if (errno != EINTR) { - MakeErrMsg(ErrMsg, "Error waiting for child process"); - return -1; + ProcessInfo WaitResult; + + do { + WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions); + } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR); + + if (WaitResult.Pid != PI.Pid) { + if (WaitResult.Pid == 0) { + // Non-blocking wait. + return WaitResult; + } else { + if (SecondsToWait && errno == EINTR) { + // Kill the child. + kill(PI.Pid, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, nullptr); + + // Wait for child to die + if (wait(&status) != ChildPid) + MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); + else + MakeErrMsg(ErrMsg, "Child timed out", 0); + + WaitResult.ReturnCode = -2; // Timeout detected + return WaitResult; + } else if (errno != EINTR) { + MakeErrMsg(ErrMsg, "Error waiting for child process"); + WaitResult.ReturnCode = -1; + return WaitResult; + } } + } // We exited normally without timeout, so turn off the timer. - if (secondsToWait) { + if (SecondsToWait && !WaitUntilTerminates) { alarm(0); - sigaction(SIGALRM, &Old, 0); + sigaction(SIGALRM, &Old, nullptr); } // Return the proper exit status. Detect error conditions @@ -362,24 +395,19 @@ static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, int result = 0; if (WIFEXITED(status)) { result = WEXITSTATUS(status); -#ifdef HAVE_POSIX_SPAWN - // The posix_spawn child process returns 127 on any kind of error. - // Following the POSIX convention for command-line tools (which posix_spawn - // itself apparently does not), check to see if the failure was due to some - // reason other than the file not existing, and return 126 in this case. - bool Exists; - if (result == 127 && !llvm::sys::fs::exists(Program, Exists) && Exists) - result = 126; -#endif + WaitResult.ReturnCode = result; + if (result == 127) { if (ErrMsg) *ErrMsg = llvm::sys::StrError(ENOENT); - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } if (result == 126) { if (ErrMsg) *ErrMsg = "Program could not be executed"; - return -1; + WaitResult.ReturnCode = -1; + return WaitResult; } } else if (WIFSIGNALED(status)) { if (ErrMsg) { @@ -391,31 +419,42 @@ static int Wait(void *&Data, StringRef Program, unsigned secondsToWait, } // Return a special value to indicate that the process received an unhandled // signal during execution as opposed to failing to execute. - return -2; + WaitResult.ReturnCode = -2; } - return result; #else if (ErrMsg) *ErrMsg = "Program::Wait is not implemented on this platform yet!"; - return -1; + ProcessInfo WaitResult; + WaitResult.ReturnCode = -2; #endif + return WaitResult; } -namespace llvm { - -error_code sys::ChangeStdinToBinary(){ + std::error_code sys::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. - return make_error_code(errc::success); + return std::error_code(); } -error_code sys::ChangeStdoutToBinary(){ + std::error_code sys::ChangeStdoutToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. - return make_error_code(errc::success); + return std::error_code(); } -error_code sys::ChangeStderrToBinary(){ - // Do nothing, as Unix doesn't differentiate between text and binary. - return make_error_code(errc::success); +std::error_code +llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, + WindowsEncodingMethod Encoding /*unused*/) { + std::error_code EC; + llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OpenFlags::F_Text); + + if (EC) + return EC; + + OS << Contents; + + if (OS.has_error()) + return std::make_error_code(std::errc::io_error); + + return EC; } bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef Args) { @@ -426,17 +465,16 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef Args) { return true; // Conservatively account for space required by environment variables. - ArgMax /= 2; + long HalfArgMax = ArgMax / 2; size_t ArgLength = 0; for (ArrayRef::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { ArgLength += strlen(*I) + 1; - if (ArgLength > size_t(ArgMax)) { + if (ArgLength > size_t(HalfArgMax)) { return false; } } return true; } - }