Cygwin doesn't have the RSS_LIMIT for get/setrlimit.
[oota-llvm.git] / lib / System / Unix / Program.inc
1 //===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Unix specific portion of the Program class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include <llvm/Config/config.h>
20 #include "Unix.h"
21 #include <iostream>
22 #if HAVE_SYS_STAT_H
23 #include <sys/stat.h>
24 #endif
25 #if HAVE_SYS_RESOURCE_H
26 #include <sys/resource.h>
27 #endif
28 #if HAVE_SIGNAL_H
29 #include <signal.h>
30 #endif
31 #if HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 namespace llvm {
36 using namespace sys;
37
38 // This function just uses the PATH environment variable to find the program.
39 Path
40 Program::FindProgramByName(const std::string& progName) {
41
42   // Check some degenerate cases
43   if (progName.length() == 0) // no program
44     return Path();
45   Path temp;
46   if (!temp.set(progName)) // invalid name
47     return Path();
48   // FIXME: have to check for absolute filename - we cannot assume anything
49   // about "." being in $PATH
50   if (temp.canExecute()) // already executable as is
51     return temp;
52
53   // At this point, the file name is valid and its not executable
54  
55   // Get the path. If its empty, we can't do anything to find it.
56   const char *PathStr = getenv("PATH");
57   if (PathStr == 0) 
58     return Path();
59
60   // Now we have a colon separated list of directories to search; try them.
61   unsigned PathLen = strlen(PathStr);
62   while (PathLen) {
63     // Find the first colon...
64     const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
65
66     // Check to see if this first directory contains the executable...
67     Path FilePath;
68     if (FilePath.set(std::string(PathStr,Colon))) {
69       FilePath.appendComponent(progName);
70       if (FilePath.canExecute())
71         return FilePath;                    // Found the executable!
72     }
73
74     // Nope it wasn't in this directory, check the next path in the list!
75     PathLen -= Colon-PathStr;
76     PathStr = Colon;
77
78     // Advance past duplicate colons
79     while (*PathStr == ':') {
80       PathStr++;
81       PathLen--;
82     }
83   }
84   return Path();
85 }
86
87 static bool RedirectFD(const std::string &File, int FD, std::string* ErrMsg) {
88   if (File.empty()) return false;  // Noop
89
90   // Open the file
91   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
92   if (InFD == -1) {
93     MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
94               + (FD == 0 ? "input" : "output") + "!\n");
95     return true;
96   }
97
98   // Install it as the requested FD
99   if (-1 == dup2(InFD, FD)) {
100     MakeErrMsg(ErrMsg, "Cannot dup2");
101     return true;
102   }
103   close(InFD);      // Close the original FD
104   return false;
105 }
106
107 static bool Timeout = false;
108 static void TimeOutHandler(int Sig) {
109   Timeout = true;
110 }
111
112 static void SetMemoryLimits (unsigned size)
113 {
114 #if HAVE_SYS_RESOURCE_H
115   struct rlimit r;
116   __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
117
118   // Heap size
119   getrlimit (RLIMIT_DATA, &r);
120   r.rlim_cur = limit;
121   setrlimit (RLIMIT_DATA, &r);
122 #ifndef __CYGWIN__
123   // Resident set size.
124   getrlimit (RLIMIT_RSS, &r);
125   r.rlim_cur = limit;
126   setrlimit (RLIMIT_RSS, &r);
127 #endif
128   // Virtual memory.
129   getrlimit (RLIMIT_AS, &r);
130   r.rlim_cur = limit;
131   setrlimit (RLIMIT_AS, &r);
132 #endif
133 }
134
135 int 
136 Program::ExecuteAndWait(const Path& path, 
137                         const char** args,
138                         const char** envp,
139                         const Path** redirects,
140                         unsigned secondsToWait,
141                         unsigned memoryLimit,
142                         std::string* ErrMsg) 
143 {
144   if (!path.canExecute()) {
145     if (ErrMsg)
146       *ErrMsg = path.toString() + " is not executable";
147     return -1;
148   }
149
150 #ifdef HAVE_SYS_WAIT_H
151   // Create a child process.
152   int child = fork();
153   switch (child) {
154     // An error occured:  Return to the caller.
155     case -1:
156       MakeErrMsg(ErrMsg, "Couldn't fork");
157       return -1;
158
159     // Child process: Execute the program.
160     case 0: {
161       // Redirect file descriptors...
162       if (redirects) {
163         if (redirects[0]) {
164           if (redirects[0]->isEmpty()) {
165             if (RedirectFD("/dev/null",0,ErrMsg)) { return -1; }
166           } else {
167             if (RedirectFD(redirects[0]->toString(), 0,ErrMsg)) { return -1; }
168           }
169         }
170         if (redirects[1]) {
171           if (redirects[1]->isEmpty()) {
172             if (RedirectFD("/dev/null",1,ErrMsg)) { return -1; }
173           } else {
174             if (RedirectFD(redirects[1]->toString(),1,ErrMsg)) { return -1; }
175           }
176         }
177         if (redirects[1] && redirects[2] && 
178             *(redirects[1]) != *(redirects[2])) {
179           if (redirects[2]->isEmpty()) {
180             if (RedirectFD("/dev/null",2,ErrMsg)) { return -1; }
181           } else {
182             if (RedirectFD(redirects[2]->toString(), 2,ErrMsg)) { return -1; }
183           }
184         } else if (-1 == dup2(1,2)) {
185           MakeErrMsg(ErrMsg, "Can't redirect");
186           return -1;
187         }
188       }
189
190       // Set memory limits
191       if (memoryLimit!=0) {
192         SetMemoryLimits(memoryLimit);
193       }
194       
195       // Execute!
196       if (envp != 0)
197         execve (path.c_str(), (char** const)args, (char**)envp);
198       else
199         execv (path.c_str(), (char** const)args);
200       // If the execve() failed, we should exit and let the parent pick up
201       // our non-zero exit status.
202       exit (errno);
203     }
204
205     // Parent process: Break out of the switch to do our processing.
206     default:
207       break;
208   }
209
210   // Make sure stderr and stdout have been flushed
211   std::cerr << std::flush;
212   std::cout << std::flush;
213   fsync(1);
214   fsync(2);
215
216   struct sigaction Act, Old;
217
218   // Install a timeout handler.
219   if (secondsToWait) {
220     Timeout = false;
221     Act.sa_sigaction = 0;
222     Act.sa_handler = TimeOutHandler;
223     sigemptyset(&Act.sa_mask);
224     Act.sa_flags = 0;
225     sigaction(SIGALRM, &Act, &Old);
226     alarm(secondsToWait);
227   }
228
229   // Parent process: Wait for the child process to terminate.
230   int status;
231   while (wait(&status) != child)
232     if (secondsToWait && errno == EINTR) {
233       // Kill the child.
234       kill(child, SIGKILL);
235         
236       // Turn off the alarm and restore the signal handler
237       alarm(0);
238       sigaction(SIGALRM, &Old, 0);
239
240       // Wait for child to die
241       if (wait(&status) != child)
242         MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
243         
244       return -1;   // Timeout detected
245     } else {
246       MakeErrMsg(ErrMsg, "Error waiting for child process");
247       return -1;
248     }
249
250   // We exited normally without timeout, so turn off the timer.
251   if (secondsToWait) {
252     alarm(0);
253     sigaction(SIGALRM, &Old, 0);
254   }
255
256   // Return the proper exit status. 0=success, >0 is programs' exit status,
257   // <0 means a signal was returned, -9999999 means the program dumped core.
258   int result = 0;
259   if (WIFEXITED(status))
260     result = WEXITSTATUS(status);
261   else if (WIFSIGNALED(status))
262     result = 0 - WTERMSIG(status);
263 #ifdef WCOREDUMP
264   else if (WCOREDUMP(status))
265     result |= 0x01000000;
266 #endif
267   return result;
268 #else
269   return -99;
270 #endif
271     
272 }
273
274 bool Program::ChangeStdinToBinary(){
275   // Do nothing, as Unix doesn't differentiate between text and binary.
276   return false;
277 }
278
279 bool Program::ChangeStdoutToBinary(){
280   // Do nothing, as Unix doesn't differentiate between text and binary.
281   return false;
282 }
283
284 }