llvm.org GIT mirror llvm / 9f1d9fd
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 Rafael Espindola 6 years ago
12 changed file(s) with 97 addition(s) and 182 deletion(s). Raw diff Collapse all Expand all
2121 namespace llvm {
2222 class error_code;
2323 namespace sys {
24 /// This static constructor (factory) will attempt to locate a program in
25 /// the operating system's file system using some pre-determined set of
26 /// locations to search (e.g. the PATH on Unix). Paths with slashes are
27 /// returned unmodified.
28 /// @returns A Path object initialized to the path of the program or a
29 /// Path object that is empty (invalid) if the program could not be found.
30 /// @brief Construct a Program by finding it by name.
31 Path FindProgramByName(const std::string& name);
2432
25 // TODO: Add operations to communicate with the process, redirect its I/O,
26 // etc.
33 // These functions change the specified standard stream (stdin, stdout, or
34 // stderr) to binary mode. They return errc::success if the specified stream
35 // was changed. Otherwise a platform dependent error is returned.
36 error_code ChangeStdinToBinary();
37 error_code ChangeStdoutToBinary();
38 error_code ChangeStderrToBinary();
2739
28 /// This class provides an abstraction for programs that are executable by the
29 /// operating system. It provides a platform generic way to find executable
30 /// programs from the path and to execute them in various ways. The sys::Path
31 /// class is used to specify the location of the Program.
32 /// @since 1.4
33 /// @brief An abstraction for finding and executing programs.
34 class Program {
35 /// Opaque handle for target specific data.
36 void *Data_;
37
38 // Noncopyable.
39 Program(const Program& other) LLVM_DELETED_FUNCTION;
40 Program& operator=(const Program& other) LLVM_DELETED_FUNCTION;
41
42 /// @name Methods
43 /// @{
44
45 Program();
46 ~Program();
47
48 /// This function executes the program using the \p arguments provided. The
49 /// invoked program will inherit the stdin, stdout, and stderr file
50 /// descriptors, the environment and other configuration settings of the
51 /// invoking program. If Path::executable() does not return true when this
52 /// function is called then a std::string is thrown.
53 /// @returns false in case of error, true otherwise.
54 /// @see FindProgramByName
55 /// @brief Executes the program with the given set of \p args.
56 bool Execute
57 ( const Path& path, ///< sys::Path object providing the path of the
40 /// This function executes the program using the arguments provided. The
41 /// invoked program will inherit the stdin, stdout, and stderr file
42 /// descriptors, the environment and other configuration settings of the
43 /// invoking program.
44 /// This function waits the program to finish.
45 /// @returns an integer result code indicating the status of the program.
46 /// A zero or positive value indicates the result code of the program.
47 /// -1 indicates failure to execute
48 /// -2 indicates a crash during execution or timeout
49 int ExecuteAndWait(
50 const Path &path, ///< sys::Path object providing the path of the
5851 ///< program to be executed. It is presumed this is the result of
5952 ///< the FindProgramByName method.
60 const char** args, ///< A vector of strings that are passed to the
53 const char **args, ///< A vector of strings that are passed to the
6154 ///< program. The first element should be the name of the program.
6255 ///< The list *must* be terminated by a null char* entry.
63 const char ** env = 0, ///< An optional vector of strings to use for
56 const char **env = 0, ///< An optional vector of strings to use for
6457 ///< the program's environment. If not provided, the current program's
6558 ///< environment will be used.
66 const sys::Path** redirects = 0, ///< An optional array of pointers to
59 const sys::Path **redirects = 0, ///< An optional array of pointers to
6760 ///< Paths. If the array is null, no redirection is done. The array
6861 ///< should have a size of at least three. If the pointer in the array
6962 ///< are not null, then the inferior process's stdin(0), stdout(1),
7164 ///< When an empty Path is passed in, the corresponding file
7265 ///< descriptor will be disconnected (ie, /dev/null'd) in a portable
7366 ///< way.
67 unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount
68 ///< of time to wait for the child process to exit. If the time
69 ///< expires, the child is killed and this call returns. If zero,
70 ///< this function will wait until the child finishes or forever if
71 ///< it doesn't.
7472 unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
7573 ///< of memory can be allocated by process. If memory usage will be
7674 ///< higher limit, the child is killed and this call returns. If zero
7775 ///< - no memory limit.
78 std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
76 std::string *ErrMsg = 0, ///< If non-zero, provides a pointer to a string
7977 ///< instance in which error messages will be returned. If the string
8078 ///< is non-empty upon return an error occurred while invoking the
8179 ///< program.
82 );
80 bool *ExecutionFailed = 0);
8381
84 /// This function waits for the program to exit. This function will block
85 /// the current program until the invoked program exits.
86 /// @returns an integer result code indicating the status of the program.
87 /// A zero or positive value indicates the result code of the program.
88 /// -1 indicates failure to execute
89 /// -2 indicates a crash during execution or timeout
90 /// @see Execute
91 /// @brief Waits for the program to exit.
92 int Wait
93 ( const Path& path, ///< The path to the child process executable.
94 unsigned secondsToWait, ///< If non-zero, this specifies the amount
95 ///< of time to wait for the child process to exit. If the time
96 ///< expires, the child is killed and this call returns. If zero,
97 ///< this function will wait until the child finishes or forever if
98 ///< it doesn't.
99 std::string* ErrMsg ///< If non-zero, provides a pointer to a string
100 ///< instance in which error messages will be returned. If the string
101 ///< is non-empty upon return an error occurred while waiting.
102 );
103
104 public:
105 /// This static constructor (factory) will attempt to locate a program in
106 /// the operating system's file system using some pre-determined set of
107 /// locations to search (e.g. the PATH on Unix). Paths with slashes are
108 /// returned unmodified.
109 /// @returns A Path object initialized to the path of the program or a
110 /// Path object that is empty (invalid) if the program could not be found.
111 /// @brief Construct a Program by finding it by name.
112 static Path FindProgramByName(const std::string& name);
113
114 // These methods change the specified standard stream (stdin, stdout, or
115 // stderr) to binary mode. They return errc::success if the specified stream
116 // was changed. Otherwise a platform dependent error is returned.
117 static error_code ChangeStdinToBinary();
118 static error_code ChangeStdoutToBinary();
119 static error_code ChangeStderrToBinary();
120
121 /// A convenience function equivalent to Program prg; prg.Execute(..);
122 /// prg.Wait(..);
123 /// @see Execute, Wait
124 static int ExecuteAndWait(const Path& path,
125 const char** args,
126 const char ** env = 0,
127 const sys::Path** redirects = 0,
128 unsigned secondsToWait = 0,
129 unsigned memoryLimit = 0,
130 std::string* ErrMsg = 0,
131 bool *ExecutionFailed = 0);
132
133 /// A convenience function equivalent to Program prg; prg.Execute(..);
134 /// @see Execute
135 static void ExecuteNoWait(const Path& path,
136 const char** args,
137 const char ** env = 0,
138 const sys::Path** redirects = 0,
139 unsigned memoryLimit = 0,
140 std::string* ErrMsg = 0);
141
142 /// @}
143
144 };
145
146 inline int ExecuteAndWait(const Path &path, const char **args,
147 const char **env = 0,
148 const sys::Path **redirects = 0,
149 unsigned secondsToWait = 0,
150 unsigned memoryLimit = 0, std::string *ErrMsg = 0,
151 bool *ExecutionFailed = 0) {
152 return Program::ExecuteAndWait(path, args, env, redirects, secondsToWait,
153 memoryLimit, ErrMsg, ExecutionFailed);
154 }
155
156 inline Path FindProgramByName(const std::string& name) {
157 return Program::FindProgramByName(name);
158 }
159
160 inline error_code ChangeStdoutToBinary() {
161 return Program::ChangeStdoutToBinary();
162 }
82 /// Similar to ExecuteAndWait, but return immediately.
83 void ExecuteNoWait(const Path &path, const char **args, const char **env = 0,
84 const sys::Path **redirects = 0, unsigned memoryLimit = 0,
85 std::string *ErrMsg = 0);
16386
16487 // Return true if the given arguments fit within system-specific
16588 // argument length limits.
6565 error_code OpenFile(const std::string &Filename) {
6666 if (Filename == "-") {
6767 Fd = 0;
68 sys::Program::ChangeStdinToBinary();
68 sys::ChangeStdinToBinary();
6969 return error_code::success();
7070 }
7171
6868 ExecGraphViewer(const sys::Path &ExecPath, std::vector &args,
6969 const sys::Path &Filename, bool wait, std::string &ErrMsg) {
7070 if (wait) {
71 if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) {
71 if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) {
7272 errs() << "Error: " << ErrMsg << "\n";
7373 return false;
7474 }
7676 errs() << " done. \n";
7777 }
7878 else {
79 sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg);
79 sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg);
8080 errs() << "Remember to erase graph file: " << Filename.str() << "\n";
8181 }
8282 return true;
418418 //
419419 // FIXME: That isn't necessarily true, we should try to mmap stdin and
420420 // fallback if it fails.
421 sys::Program::ChangeStdinToBinary();
421 sys::ChangeStdinToBinary();
422422
423423 return getMemoryBufferForStream(0, "", result);
424424 }
2121 //=== independent code.
2222 //===----------------------------------------------------------------------===//
2323
24 int
25 Program::ExecuteAndWait(const Path& path,
26 const char** args,
27 const char** envp,
28 const Path** redirects,
29 unsigned secondsToWait,
30 unsigned memoryLimit,
31 std::string* ErrMsg,
24 static bool Execute(void *&Data, const Path &path, const char **args,
25 const char **env, const sys::Path **redirects,
26 unsigned memoryLimit, std::string *ErrMsg);
27
28 static int Wait(void *&Data, const Path &path, unsigned secondsToWait,
29 std::string *ErrMsg);
30
31 int sys::ExecuteAndWait(const Path &path, const char **args, const char **envp,
32 const Path **redirects, unsigned secondsToWait,
33 unsigned memoryLimit, std::string *ErrMsg,
3234 bool *ExecutionFailed) {
33 Program prg;
34 if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) {
35 void *Data;
36 if (Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg)) {
3537 if (ExecutionFailed) *ExecutionFailed = false;
36 return prg.Wait(path, secondsToWait, ErrMsg);
38 return Wait(Data, path, secondsToWait, ErrMsg);
3739 }
3840 if (ExecutionFailed) *ExecutionFailed = true;
3941 return -1;
4042 }
4143
42 void
43 Program::ExecuteNoWait(const Path& path,
44 const char** args,
45 const char** envp,
46 const Path** redirects,
47 unsigned memoryLimit,
48 std::string* ErrMsg) {
49 Program prg;
50 prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg);
44 void sys::ExecuteNoWait(const Path &path, const char **args, const char **envp,
45 const Path **redirects, unsigned memoryLimit,
46 std::string *ErrMsg) {
47 void *Data;
48 Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg);
5149 }
5250
5351 // Include the platform-specific parts of this class.
4646 namespace llvm {
4747 using namespace sys;
4848
49 Program::Program() : Data_(0) {}
50
51 Program::~Program() {}
52
5349 // This function just uses the PATH environment variable to find the program.
5450 Path
55 Program::FindProgramByName(const std::string& progName) {
51 sys::FindProgramByName(const std::string& progName) {
5652
5753 // Check some degenerate cases
5854 if (progName.length() == 0) // no program
179175 #endif
180176 }
181177
182 bool
183 Program::Execute(const Path &path, const char **args, const char **envp,
184 const Path **redirects, unsigned memoryLimit,
185 std::string *ErrMsg) {
178 }
179
180 static bool Execute(void *&Data, const Path &path, const char **args,
181 const char **envp, const Path **redirects,
182 unsigned memoryLimit, std::string *ErrMsg) {
186183 // If this OS has posix_spawn and there is no memory limit being implied, use
187184 // posix_spawn. It is more efficient than fork/exec.
188185 #ifdef HAVE_POSIX_SPAWN
230227 if (Err)
231228 return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
232229
233 Data_ = reinterpret_cast(PID);
230 Data = reinterpret_cast(PID);
234231 return true;
235232 }
236233 #endif
292289 break;
293290 }
294291
295 Data_ = reinterpret_cast(child);
292 Data = reinterpret_cast(child);
296293
297294 return true;
298295 }
299296
300 int
301 Program::Wait(const sys::Path &path,
302 unsigned secondsToWait,
303 std::string* ErrMsg)
304 {
297 static int Wait(void *&Data, const sys::Path &path, unsigned secondsToWait,
298 std::string *ErrMsg) {
305299 #ifdef HAVE_SYS_WAIT_H
306300 struct sigaction Act, Old;
307301
308 if (Data_ == 0) {
302 if (Data == 0) {
309303 MakeErrMsg(ErrMsg, "Process not started!");
310304 return -1;
311305 }
323317
324318 // Parent process: Wait for the child process to terminate.
325319 int status;
326 uint64_t pid = reinterpret_cast(Data_);
320 uint64_t pid = reinterpret_cast(Data);
327321 pid_t child = static_cast(pid);
328322 while (waitpid(pid, &status, 0) != child)
329323 if (secondsToWait && errno == EINTR) {
396390 #endif
397391 }
398392
399 error_code Program::ChangeStdinToBinary(){
393 namespace llvm {
394
395 error_code sys::ChangeStdinToBinary(){
400396 // Do nothing, as Unix doesn't differentiate between text and binary.
401397 return make_error_code(errc::success);
402398 }
403399
404 error_code Program::ChangeStdoutToBinary(){
400 error_code sys::ChangeStdoutToBinary(){
405401 // Do nothing, as Unix doesn't differentiate between text and binary.
406402 return make_error_code(errc::success);
407403 }
408404
409 error_code Program::ChangeStderrToBinary(){
405 error_code sys::ChangeStderrToBinary(){
410406 // Do nothing, as Unix doesn't differentiate between text and binary.
411407 return make_error_code(errc::success);
412408 }
441441 // If user requested binary then put stdout into binary mode if
442442 // possible.
443443 if (Flags & F_Binary)
444 sys::Program::ChangeStdoutToBinary();
444 sys::ChangeStdoutToBinary();
445445 // Close stdout when we're done, to detect any output errors.
446446 ShouldClose = true;
447447 return;
147147 return 1;
148148 }
149149
150 sys::Path tool = sys::Program::FindProgramByName("opt");
150 sys::Path tool = sys::FindProgramByName("opt");
151151 if (tool.empty()) {
152152 errs() << "Cannot find `opt' in PATH!\n";
153153 return 1;
195195
196196 sys::Path prog;
197197 if (UseValgrind)
198 prog = sys::Program::FindProgramByName("valgrind");
198 prog = sys::FindProgramByName("valgrind");
199199 else
200200 prog = tool;
201201
203203 sys::Path Nowhere;
204204 const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere};
205205
206 int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0,
207 (SilencePasses ? Redirects : 0),
208 Timeout, MemoryLimit, &ErrMsg);
206 int result =
207 sys::ExecuteAndWait(prog, Args.data(), 0, (SilencePasses ? Redirects : 0),
208 Timeout, MemoryLimit, &ErrMsg);
209209
210210 // If we are supposed to delete the bitcode file or if the passes crashed,
211211 // remove it now. This may fail if the file was never created, but that's ok.
7474 }
7575 #endif
7676
77 return
78 sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
79 NumSeconds, MemoryLimit, ErrMsg);
77 return sys::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds,
78 MemoryLimit, ErrMsg);
8079 }
8180
8281 /// RunProgramRemotelyWithTimeout - This function runs the given program
107106 #endif
108107
109108 // Run the program remotely with the remote client
110 int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args,
111 0, redirects, NumSeconds, MemoryLimit);
109 int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, 0, redirects,
110 NumSeconds, MemoryLimit);
112111
113112 // Has the remote client fail?
114113 if (255 == ReturnCode) {
397396 pos = CommandLine.find_first_of(delimiters, lastPos);
398397 }
399398
400 CmdPath = sys::Program::FindProgramByName(Command).str();
399 CmdPath = sys::FindProgramByName(Command).str();
401400 if (CmdPath.empty()) {
402401 Message =
403402 std::string("Cannot find '") + Command +
874873 GCC *GCC::create(std::string &Message,
875874 const std::string &GCCBinary,
876875 const std::vector *Args) {
877 sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary);
876 sys::Path GCCPath = sys::FindProgramByName(GCCBinary);
878877 if (GCCPath.isEmpty()) {
879878 Message = "Cannot find `"+ GCCBinary +"' in PATH!\n";
880879 return 0;
882881
883882 sys::Path RemoteClientPath;
884883 if (!RemoteClient.empty())
885 RemoteClientPath = sys::Program::FindProgramByName(RemoteClient);
884 RemoteClientPath = sys::FindProgramByName(RemoteClient);
886885
887886 Message = "Found gcc: " + GCCPath.str() + "\n";
888887 return new GCC(GCCPath, RemoteClientPath, Args);
424424 cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
425425
426426 // llvm-nm only reads binary files.
427 if (error(sys::Program::ChangeStdinToBinary()))
427 if (error(sys::ChangeStdinToBinary()))
428428 return 1;
429429
430430 ToolName = argv[0];
7878 Path nul("/dev/null");
7979 #endif
8080 const Path *redirects[] = { &nul, &nul, 0 };
81 int rc = Program::ExecuteAndWait(my_exe, argv, &envp[0], redirects,
82 /*secondsToWait=*/10, /*memoryLimit=*/0,
83 &error, &ExecutionFailed);
81 int rc =
82 ExecuteAndWait(my_exe, argv, &envp[0], redirects, /*secondsToWait=*/ 10,
83 /*memoryLimit=*/ 0, &error, &ExecutionFailed);
8484 EXPECT_FALSE(ExecutionFailed) << error;
8585 EXPECT_EQ(0, rc);
8686 }
1212 using namespace llvm;
1313
1414 int main(int argc, const char **argv) {
15 sys::Path Program = sys::Program::FindProgramByName(argv[1]);
15 sys::Path Program = sys::FindProgramByName(argv[1]);
1616
1717 std::string ErrMsg;
18 int Result = sys::Program::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0,
19 &ErrMsg);
18 int Result = sys::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0, &ErrMsg);
2019 if (Result < 0) {
2120 errs() << "Error: " << ErrMsg << "\n";
2221 return 1;