From 9f1d9fd1964d82f3e801efb71518144492cdf290 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 12 Jun 2013 20:58:35 +0000 Subject: Remove the program class. It was only used to implement ExecuteAndWait and ExecuteNoWait. Expose just those two functions and make Execute and Wait implementations details. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183864 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/Program.h | 159 ++++++++++--------------------------- lib/Support/DataStream.cpp | 2 +- lib/Support/GraphWriter.cpp | 4 +- lib/Support/MemoryBuffer.cpp | 2 +- lib/Support/Program.cpp | 38 +++++---- lib/Support/Unix/Program.inc | 38 ++++----- lib/Support/raw_ostream.cpp | 2 +- tools/bugpoint/OptimizerDriver.cpp | 10 +-- tools/bugpoint/ToolRunner.cpp | 15 ++-- tools/llvm-nm/llvm-nm.cpp | 2 +- unittests/Support/ProgramTest.cpp | 6 +- utils/not/not.cpp | 5 +- 12 files changed, 99 insertions(+), 184 deletions(-) diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h index db12a153f6..dac377aaa7 100644 --- a/include/llvm/Support/Program.h +++ b/include/llvm/Support/Program.h @@ -22,49 +22,42 @@ namespace llvm { class error_code; namespace sys { - - // TODO: Add operations to communicate with the process, redirect its I/O, - // etc. - - /// This class provides an abstraction for programs that are executable by the - /// operating system. It provides a platform generic way to find executable - /// programs from the path and to execute them in various ways. The sys::Path - /// class is used to specify the location of the Program. - /// @since 1.4 - /// @brief An abstraction for finding and executing programs. - class Program { - /// Opaque handle for target specific data. - void *Data_; - - // Noncopyable. - Program(const Program& other) LLVM_DELETED_FUNCTION; - Program& operator=(const Program& other) LLVM_DELETED_FUNCTION; - - /// @name Methods - /// @{ - - Program(); - ~Program(); - - /// This function executes the program using the \p arguments provided. The - /// invoked program will inherit the stdin, stdout, and stderr file - /// descriptors, the environment and other configuration settings of the - /// invoking program. If Path::executable() does not return true when this - /// function is called then a std::string is thrown. - /// @returns false in case of error, true otherwise. - /// @see FindProgramByName - /// @brief Executes the program with the given set of \p args. - bool Execute - ( const Path& path, ///< sys::Path object providing the path of the + /// This static constructor (factory) will attempt to locate a program in + /// the operating system's file system using some pre-determined set of + /// locations to search (e.g. the PATH on Unix). Paths with slashes are + /// returned unmodified. + /// @returns A Path object initialized to the path of the program or a + /// Path object that is empty (invalid) if the program could not be found. + /// @brief Construct a Program by finding it by name. + Path FindProgramByName(const std::string& name); + + // These functions change the specified standard stream (stdin, stdout, or + // stderr) to binary mode. They return errc::success if the specified stream + // was changed. Otherwise a platform dependent error is returned. + error_code ChangeStdinToBinary(); + error_code ChangeStdoutToBinary(); + error_code ChangeStderrToBinary(); + + /// This function executes the program using the arguments provided. The + /// invoked program will inherit the stdin, stdout, and stderr file + /// descriptors, the environment and other configuration settings of the + /// invoking program. + /// This function waits the program to finish. + /// @returns an integer result code indicating the status of the program. + /// A zero or positive value indicates the result code of the program. + /// -1 indicates failure to execute + /// -2 indicates a crash during execution or timeout + int ExecuteAndWait( + const Path &path, ///< sys::Path object providing the path of the ///< program to be executed. It is presumed this is the result of ///< the FindProgramByName method. - const char** args, ///< A vector of strings that are passed to the + const char **args, ///< A vector of strings that are passed to the ///< program. The first element should be the name of the program. ///< The list *must* be terminated by a null char* entry. - const char ** env = 0, ///< An optional vector of strings to use for + const char **env = 0, ///< An optional vector of strings to use for ///< the program's environment. If not provided, the current program's ///< environment will be used. - const sys::Path** redirects = 0, ///< An optional array of pointers to + const sys::Path **redirects = 0, ///< An optional array of pointers to ///< Paths. If the array is null, no redirection is done. The array ///< should have a size of at least three. If the pointer in the array ///< are not null, then the inferior process's stdin(0), stdout(1), @@ -72,95 +65,25 @@ namespace sys { ///< When an empty Path is passed in, the corresponding file ///< descriptor will be disconnected (ie, /dev/null'd) in a portable ///< way. + unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount + ///< of time to wait for the child process to exit. If the time + ///< expires, the child is killed and this call returns. If zero, + ///< this function will wait until the child finishes or forever if + ///< it doesn't. unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount ///< of memory can be allocated by process. If memory usage will be ///< higher limit, the child is killed and this call returns. If zero ///< - no memory limit. - std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string + std::string *ErrMsg = 0, ///< If non-zero, provides a pointer to a string ///< instance in which error messages will be returned. If the string ///< is non-empty upon return an error occurred while invoking the ///< program. - ); - - /// This function waits for the program to exit. This function will block - /// the current program until the invoked program exits. - /// @returns an integer result code indicating the status of the program. - /// A zero or positive value indicates the result code of the program. - /// -1 indicates failure to execute - /// -2 indicates a crash during execution or timeout - /// @see Execute - /// @brief Waits for the program to exit. - int Wait - ( const Path& path, ///< The path to the child process executable. - unsigned secondsToWait, ///< If non-zero, this specifies the amount - ///< of time to wait for the child process to exit. If the time - ///< expires, the child is killed and this call returns. If zero, - ///< this function will wait until the child finishes or forever if - ///< it doesn't. - std::string* ErrMsg ///< If non-zero, provides a pointer to a string - ///< instance in which error messages will be returned. If the string - ///< is non-empty upon return an error occurred while waiting. - ); - - public: - /// This static constructor (factory) will attempt to locate a program in - /// the operating system's file system using some pre-determined set of - /// locations to search (e.g. the PATH on Unix). Paths with slashes are - /// returned unmodified. - /// @returns A Path object initialized to the path of the program or a - /// Path object that is empty (invalid) if the program could not be found. - /// @brief Construct a Program by finding it by name. - static Path FindProgramByName(const std::string& name); - - // These methods change the specified standard stream (stdin, stdout, or - // stderr) to binary mode. They return errc::success if the specified stream - // was changed. Otherwise a platform dependent error is returned. - static error_code ChangeStdinToBinary(); - static error_code ChangeStdoutToBinary(); - static error_code ChangeStderrToBinary(); - - /// A convenience function equivalent to Program prg; prg.Execute(..); - /// prg.Wait(..); - /// @see Execute, Wait - static int ExecuteAndWait(const Path& path, - const char** args, - const char ** env = 0, - const sys::Path** redirects = 0, - unsigned secondsToWait = 0, - unsigned memoryLimit = 0, - std::string* ErrMsg = 0, - bool *ExecutionFailed = 0); - - /// A convenience function equivalent to Program prg; prg.Execute(..); - /// @see Execute - static void ExecuteNoWait(const Path& path, - const char** args, - const char ** env = 0, - const sys::Path** redirects = 0, - unsigned memoryLimit = 0, - std::string* ErrMsg = 0); - - /// @} - - }; - - inline int ExecuteAndWait(const Path &path, const char **args, - const char **env = 0, - const sys::Path **redirects = 0, - unsigned secondsToWait = 0, - unsigned memoryLimit = 0, std::string *ErrMsg = 0, - bool *ExecutionFailed = 0) { - return Program::ExecuteAndWait(path, args, env, redirects, secondsToWait, - memoryLimit, ErrMsg, ExecutionFailed); - } - - inline Path FindProgramByName(const std::string& name) { - return Program::FindProgramByName(name); - } + bool *ExecutionFailed = 0); - inline error_code ChangeStdoutToBinary() { - return Program::ChangeStdoutToBinary(); - } + /// Similar to ExecuteAndWait, but return immediately. + void ExecuteNoWait(const Path &path, const char **args, const char **env = 0, + const sys::Path **redirects = 0, unsigned memoryLimit = 0, + std::string *ErrMsg = 0); // Return true if the given arguments fit within system-specific // argument length limits. diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp index 0a02281c25..7815d08092 100644 --- a/lib/Support/DataStream.cpp +++ b/lib/Support/DataStream.cpp @@ -66,7 +66,7 @@ public: error_code OpenFile(const std::string &Filename) { if (Filename == "-") { Fd = 0; - sys::Program::ChangeStdinToBinary(); + sys::ChangeStdinToBinary(); return error_code::success(); } diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index bff182f30e..41af06c239 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -69,7 +69,7 @@ static bool LLVM_ATTRIBUTE_UNUSED ExecGraphViewer(const sys::Path &ExecPath, std::vector &args, const sys::Path &Filename, bool wait, std::string &ErrMsg) { if (wait) { - if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { + if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) { errs() << "Error: " << ErrMsg << "\n"; return false; } @@ -77,7 +77,7 @@ ExecGraphViewer(const sys::Path &ExecPath, std::vector &args, errs() << " done. \n"; } else { - sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); + sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg); errs() << "Remember to erase graph file: " << Filename.str() << "\n"; } return true; diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 82812c0aed..e875d11ec3 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -419,7 +419,7 @@ error_code MemoryBuffer::getSTDIN(OwningPtr &result) { // // FIXME: That isn't necessarily true, we should try to mmap stdin and // fallback if it fails. - sys::Program::ChangeStdinToBinary(); + sys::ChangeStdinToBinary(); return getMemoryBufferForStream(0, "", result); } diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp index 201d5c0d30..ae7e291e2a 100644 --- a/lib/Support/Program.cpp +++ b/lib/Support/Program.cpp @@ -22,33 +22,31 @@ 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, +static bool Execute(void *&Data, const Path &path, const char **args, + const char **env, const sys::Path **redirects, + unsigned memoryLimit, std::string *ErrMsg); + +static int Wait(void *&Data, const Path &path, unsigned secondsToWait, + std::string *ErrMsg); + +int sys::ExecuteAndWait(const Path &path, const char **args, const char **envp, + const Path **redirects, unsigned secondsToWait, + unsigned memoryLimit, std::string *ErrMsg, bool *ExecutionFailed) { - Program prg; - if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) { + void *Data; + if (Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg)) { if (ExecutionFailed) *ExecutionFailed = false; - return prg.Wait(path, secondsToWait, ErrMsg); + return Wait(Data, path, secondsToWait, ErrMsg); } if (ExecutionFailed) *ExecutionFailed = true; 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); +void sys::ExecuteNoWait(const Path &path, const char **args, const char **envp, + const Path **redirects, unsigned memoryLimit, + std::string *ErrMsg) { + void *Data; + Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg); } // Include the platform-specific parts of this class. diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index aa03d48438..0d6543a8a8 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -47,13 +47,9 @@ namespace llvm { using namespace sys; -Program::Program() : Data_(0) {} - -Program::~Program() {} - // This function just uses the PATH environment variable to find the program. Path -Program::FindProgramByName(const std::string& progName) { +sys::FindProgramByName(const std::string& progName) { // Check some degenerate cases if (progName.length() == 0) // no program @@ -180,10 +176,11 @@ static void SetMemoryLimits (unsigned size) #endif } -bool -Program::Execute(const Path &path, const char **args, const char **envp, - const Path **redirects, unsigned memoryLimit, - std::string *ErrMsg) { +} + +static bool Execute(void *&Data, const Path &path, const char **args, + const char **envp, const Path **redirects, + unsigned memoryLimit, std::string *ErrMsg) { // 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 @@ -231,7 +228,7 @@ Program::Execute(const Path &path, const char **args, const char **envp, if (Err) return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); - Data_ = reinterpret_cast(PID); + Data = reinterpret_cast(PID); return true; } #endif @@ -293,20 +290,17 @@ Program::Execute(const Path &path, const char **args, const char **envp, break; } - Data_ = reinterpret_cast(child); + Data = reinterpret_cast(child); return true; } -int -Program::Wait(const sys::Path &path, - unsigned secondsToWait, - std::string* ErrMsg) -{ +static int Wait(void *&Data, const sys::Path &path, unsigned secondsToWait, + std::string *ErrMsg) { #ifdef HAVE_SYS_WAIT_H struct sigaction Act, Old; - if (Data_ == 0) { + if (Data == 0) { MakeErrMsg(ErrMsg, "Process not started!"); return -1; } @@ -324,7 +318,7 @@ Program::Wait(const sys::Path &path, // Parent process: Wait for the child process to terminate. int status; - uint64_t pid = reinterpret_cast(Data_); + uint64_t pid = reinterpret_cast(Data); pid_t child = static_cast(pid); while (waitpid(pid, &status, 0) != child) if (secondsToWait && errno == EINTR) { @@ -397,17 +391,19 @@ Program::Wait(const sys::Path &path, #endif } -error_code Program::ChangeStdinToBinary(){ +namespace llvm { + +error_code sys::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } -error_code Program::ChangeStdoutToBinary(){ +error_code sys::ChangeStdoutToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } -error_code Program::ChangeStderrToBinary(){ +error_code sys::ChangeStderrToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); } diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index a433088b19..9262945358 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -442,7 +442,7 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, // If user requested binary then put stdout into binary mode if // possible. if (Flags & F_Binary) - sys::Program::ChangeStdoutToBinary(); + sys::ChangeStdoutToBinary(); // Close stdout when we're done, to detect any output errors. ShouldClose = true; return; diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 87dc9f332c..6c491ff0f9 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -148,7 +148,7 @@ bool BugDriver::runPasses(Module *Program, return 1; } - sys::Path tool = sys::Program::FindProgramByName("opt"); + sys::Path tool = sys::FindProgramByName("opt"); if (tool.empty()) { errs() << "Cannot find `opt' in PATH!\n"; return 1; @@ -196,7 +196,7 @@ bool BugDriver::runPasses(Module *Program, sys::Path prog; if (UseValgrind) - prog = sys::Program::FindProgramByName("valgrind"); + prog = sys::FindProgramByName("valgrind"); else prog = tool; @@ -204,9 +204,9 @@ bool BugDriver::runPasses(Module *Program, sys::Path Nowhere; const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere}; - int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0, - (SilencePasses ? Redirects : 0), - Timeout, MemoryLimit, &ErrMsg); + int result = + sys::ExecuteAndWait(prog, Args.data(), 0, (SilencePasses ? Redirects : 0), + Timeout, MemoryLimit, &ErrMsg); // If we are supposed to delete the bitcode file or if the passes crashed, // remove it now. This may fail if the file was never created, but that's ok. diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 735061d8bc..54a48111f8 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -75,9 +75,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath, } #endif - return - sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, - NumSeconds, MemoryLimit, ErrMsg); + return sys::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds, + MemoryLimit, ErrMsg); } /// RunProgramRemotelyWithTimeout - This function runs the given program @@ -108,8 +107,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath, #endif // Run the program remotely with the remote client - int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args, - 0, redirects, NumSeconds, MemoryLimit); + int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, 0, redirects, + NumSeconds, MemoryLimit); // Has the remote client fail? if (255 == ReturnCode) { @@ -398,7 +397,7 @@ static void lexCommand(std::string &Message, const std::string &CommandLine, pos = CommandLine.find_first_of(delimiters, lastPos); } - CmdPath = sys::Program::FindProgramByName(Command).str(); + CmdPath = sys::FindProgramByName(Command).str(); if (CmdPath.empty()) { Message = std::string("Cannot find '") + Command + @@ -875,7 +874,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCC *GCC::create(std::string &Message, const std::string &GCCBinary, const std::vector *Args) { - sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary); + sys::Path GCCPath = sys::FindProgramByName(GCCBinary); if (GCCPath.isEmpty()) { Message = "Cannot find `"+ GCCBinary +"' in PATH!\n"; return 0; @@ -883,7 +882,7 @@ GCC *GCC::create(std::string &Message, sys::Path RemoteClientPath; if (!RemoteClient.empty()) - RemoteClientPath = sys::Program::FindProgramByName(RemoteClient); + RemoteClientPath = sys::FindProgramByName(RemoteClient); Message = "Found gcc: " + GCCPath.str() + "\n"; return new GCC(GCCPath, RemoteClientPath, Args); diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index a24aae6061..683f99d342 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -425,7 +425,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n"); // llvm-nm only reads binary files. - if (error(sys::Program::ChangeStdinToBinary())) + if (error(sys::ChangeStdinToBinary())) return 1; ToolName = argv[0]; diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 6cbb05454f..f132c03304 100644 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -79,9 +79,9 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { Path nul("/dev/null"); #endif const Path *redirects[] = { &nul, &nul, 0 }; - int rc = Program::ExecuteAndWait(my_exe, argv, &envp[0], redirects, - /*secondsToWait=*/10, /*memoryLimit=*/0, - &error, &ExecutionFailed); + int rc = + ExecuteAndWait(my_exe, argv, &envp[0], redirects, /*secondsToWait=*/ 10, + /*memoryLimit=*/ 0, &error, &ExecutionFailed); EXPECT_FALSE(ExecutionFailed) << error; EXPECT_EQ(0, rc); } diff --git a/utils/not/not.cpp b/utils/not/not.cpp index 9a924b56a7..bb2d87bb44 100644 --- a/utils/not/not.cpp +++ b/utils/not/not.cpp @@ -13,11 +13,10 @@ using namespace llvm; int main(int argc, const char **argv) { - sys::Path Program = sys::Program::FindProgramByName(argv[1]); + sys::Path Program = sys::FindProgramByName(argv[1]); std::string ErrMsg; - int Result = sys::Program::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0, - &ErrMsg); + int Result = sys::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0, &ErrMsg); if (Result < 0) { errs() << "Error: " << ErrMsg << "\n"; return 1; -- cgit v1.2.3