Get rid of the Pid_ member in the Program class.
[oota-llvm.git] / lib / System / Win32 / Program.inc
1 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides the Win32 specific implementation of the Program class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "Win32.h"
15 #include <cstdio>
16 #include <malloc.h>
17 #include <io.h>
18 #include <fcntl.h>
19
20 //===----------------------------------------------------------------------===//
21 //=== WARNING: Implementation here must contain only Win32 specific code
22 //===          and must not be UNIX code
23 //===----------------------------------------------------------------------===//
24
25 namespace llvm {
26 using namespace sys;
27
28 Program::Program() : Data_(0) {}
29
30 Program::~Program() {
31   if (Data_) {
32     HANDLE hProcess = reinterpret_cast<HANDLE>(Data_);
33     CloseHandle(hProcess);
34     Data_ = 0;
35   }
36 }
37
38 unsigned Program::GetPid() {
39   HANDLE hProcess = reinterpret_cast<HANDLE>(Data_);
40   return GetProcessId(hProcess);
41 }
42
43 // This function just uses the PATH environment variable to find the program.
44 Path
45 Program::FindProgramByName(const std::string& progName) {
46
47   // Check some degenerate cases
48   if (progName.length() == 0) // no program
49     return Path();
50   Path temp;
51   if (!temp.set(progName)) // invalid name
52     return Path();
53   if (temp.canExecute()) // already executable as is
54     return temp;
55
56   // At this point, the file name is valid and its not executable.
57   // Let Windows search for it.
58   char buffer[MAX_PATH];
59   char *dummy = NULL;
60   DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH,
61                          buffer, &dummy);
62
63   // See if it wasn't found.
64   if (len == 0)
65     return Path();
66
67   // See if we got the entire path.
68   if (len < MAX_PATH)
69     return Path(buffer);
70
71   // Buffer was too small; grow and retry.
72   while (true) {
73     char *b = reinterpret_cast<char *>(_alloca(len+1));
74     DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy);
75
76     // It is unlikely the search failed, but it's always possible some file
77     // was added or removed since the last search, so be paranoid...
78     if (len2 == 0)
79       return Path();
80     else if (len2 <= len)
81       return Path(b);
82
83     len = len2;
84   }
85 }
86
87 static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) {
88   HANDLE h;
89   if (path == 0) {
90     DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
91                     GetCurrentProcess(), &h,
92                     0, TRUE, DUPLICATE_SAME_ACCESS);
93     return h;
94   }
95
96   const char *fname;
97   if (path->isEmpty())
98     fname = "NUL";
99   else
100     fname = path->c_str();
101
102   SECURITY_ATTRIBUTES sa;
103   sa.nLength = sizeof(sa);
104   sa.lpSecurityDescriptor = 0;
105   sa.bInheritHandle = TRUE;
106
107   h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ,
108                  &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
109                  FILE_ATTRIBUTE_NORMAL, NULL);
110   if (h == INVALID_HANDLE_VALUE) {
111     MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
112         (fd ? "input: " : "output: "));
113   }
114
115   return h;
116 }
117
118 #ifdef __MINGW32__
119   // Due to unknown reason, mingw32's w32api doesn't have this declaration.
120   extern "C"
121   BOOL WINAPI SetInformationJobObject(HANDLE hJob,
122                                       JOBOBJECTINFOCLASS JobObjectInfoClass,
123                                       LPVOID lpJobObjectInfo,
124                                       DWORD cbJobObjectInfoLength);
125 #endif
126
127 /// ArgNeedsQuotes - Check whether argument needs to be quoted when calling
128 /// CreateProcess.
129 static bool ArgNeedsQuotes(const char *Str) {
130   return Str[0] == '\0' || strchr(Str, ' ') != 0;
131 }
132
133 bool
134 Program::Execute(const Path& path,
135                  const char** args,
136                  const char** envp,
137                  const Path** redirects,
138                  unsigned memoryLimit,
139                  std::string* ErrMsg) {
140   if (Data_) {
141     HANDLE hProcess = reinterpret_cast<HANDLE>(Data_);
142     CloseHandle(Data_);
143     Data_ = 0;
144   }
145
146   if (!path.canExecute()) {
147     if (ErrMsg)
148       *ErrMsg = "program not executable";
149     return false;
150   }
151
152   // Windows wants a command line, not an array of args, to pass to the new
153   // process.  We have to concatenate them all, while quoting the args that
154   // have embedded spaces (or are empty).
155
156   // First, determine the length of the command line.
157   unsigned len = 0;
158   for (unsigned i = 0; args[i]; i++) {
159     len += strlen(args[i]) + 1;
160     if (ArgNeedsQuotes(args[i]))
161       len += 2;
162   }
163
164   // Now build the command line.
165   char *command = reinterpret_cast<char *>(_alloca(len+1));
166   char *p = command;
167
168   for (unsigned i = 0; args[i]; i++) {
169     const char *arg = args[i];
170     size_t len = strlen(arg);
171     bool needsQuoting = ArgNeedsQuotes(arg);
172     if (needsQuoting)
173       *p++ = '"';
174     memcpy(p, arg, len);
175     p += len;
176     if (needsQuoting)
177       *p++ = '"';
178     *p++ = ' ';
179   }
180
181   *p = 0;
182
183   // The pointer to the environment block for the new process.
184   char *envblock = 0;
185
186   if (envp) {
187     // An environment block consists of a null-terminated block of
188     // null-terminated strings. Convert the array of environment variables to
189     // an environment block by concatenating them.
190
191     // First, determine the length of the environment block.
192     len = 0;
193     for (unsigned i = 0; envp[i]; i++)
194       len += strlen(envp[i]) + 1;
195
196     // Now build the environment block.
197     envblock = reinterpret_cast<char *>(_alloca(len+1));
198     p = envblock;
199
200     for (unsigned i = 0; envp[i]; i++) {
201       const char *ev = envp[i];
202       size_t len = strlen(ev) + 1;
203       memcpy(p, ev, len);
204       p += len;
205     }
206
207     *p = 0;
208   }
209
210   // Create a child process.
211   STARTUPINFO si;
212   memset(&si, 0, sizeof(si));
213   si.cb = sizeof(si);
214   si.hStdInput = INVALID_HANDLE_VALUE;
215   si.hStdOutput = INVALID_HANDLE_VALUE;
216   si.hStdError = INVALID_HANDLE_VALUE;
217
218   if (redirects) {
219     si.dwFlags = STARTF_USESTDHANDLES;
220
221     si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
222     if (si.hStdInput == INVALID_HANDLE_VALUE) {
223       MakeErrMsg(ErrMsg, "can't redirect stdin");
224       return false;
225     }
226     si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
227     if (si.hStdOutput == INVALID_HANDLE_VALUE) {
228       CloseHandle(si.hStdInput);
229       MakeErrMsg(ErrMsg, "can't redirect stdout");
230       return false;
231     }
232     if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
233       // If stdout and stderr should go to the same place, redirect stderr
234       // to the handle already open for stdout.
235       DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
236                       GetCurrentProcess(), &si.hStdError,
237                       0, TRUE, DUPLICATE_SAME_ACCESS);
238     } else {
239       // Just redirect stderr
240       si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
241       if (si.hStdError == INVALID_HANDLE_VALUE) {
242         CloseHandle(si.hStdInput);
243         CloseHandle(si.hStdOutput);
244         MakeErrMsg(ErrMsg, "can't redirect stderr");
245         return false;
246       }
247     }
248   }
249
250   PROCESS_INFORMATION pi;
251   memset(&pi, 0, sizeof(pi));
252
253   fflush(stdout);
254   fflush(stderr);
255   BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0,
256                           envblock, NULL, &si, &pi);
257   DWORD err = GetLastError();
258
259   // Regardless of whether the process got created or not, we are done with
260   // the handles we created for it to inherit.
261   CloseHandle(si.hStdInput);
262   CloseHandle(si.hStdOutput);
263   CloseHandle(si.hStdError);
264
265   // Now return an error if the process didn't get created.
266   if (!rc) {
267     SetLastError(err);
268     MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
269                path.str() + "'");
270     return false;
271   }
272   Data_ = reinterpret_cast<void*>(pi.hProcess);
273
274   // Make sure these get closed no matter what.
275   AutoHandle hThread(pi.hThread);
276
277   // Assign the process to a job if a memory limit is defined.
278   AutoHandle hJob(0);
279   if (memoryLimit != 0) {
280     hJob = CreateJobObject(0, 0);
281     bool success = false;
282     if (hJob != 0) {
283       JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
284       memset(&jeli, 0, sizeof(jeli));
285       jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
286       jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576;
287       if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
288                                   &jeli, sizeof(jeli))) {
289         if (AssignProcessToJobObject(hJob, pi.hProcess))
290           success = true;
291       }
292     }
293     if (!success) {
294       SetLastError(GetLastError());
295       MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
296       TerminateProcess(pi.hProcess, 1);
297       WaitForSingleObject(pi.hProcess, INFINITE);
298       return false;
299     }
300   }
301
302   return true;
303 }
304
305 int
306 Program::Wait(unsigned secondsToWait,
307               std::string* ErrMsg) {
308   if (Data_ == 0) {
309     MakeErrMsg(ErrMsg, "Process not started!");
310     return -1;
311   }
312
313   HANDLE hProcess = reinterpret_cast<HANDLE>(Data_);
314
315   // Wait for the process to terminate.
316   DWORD millisecondsToWait = INFINITE;
317   if (secondsToWait > 0)
318     millisecondsToWait = secondsToWait * 1000;
319
320   if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
321     if (!TerminateProcess(hProcess, 1)) {
322       MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
323       return -1;
324     }
325     WaitForSingleObject(hProcess, INFINITE);
326   }
327
328   // Get its exit status.
329   DWORD status;
330   BOOL rc = GetExitCodeProcess(hProcess, &status);
331   DWORD err = GetLastError();
332
333   if (!rc) {
334     SetLastError(err);
335     MakeErrMsg(ErrMsg, "Failed getting status for program.");
336     return -1;
337   }
338
339   return status;
340 }
341
342 bool
343 Program::Kill(std::string* ErrMsg) {
344   if (Data_ == 0) {
345     MakeErrMsg(ErrMsg, "Process not started!");
346     return true;
347   }
348
349   HANDLE hProcess = reinterpret_cast<HANDLE>(Data_);
350   return TerminateProcess(hProcess, 1);
351 }
352
353 bool Program::ChangeStdinToBinary(){
354   int result = _setmode( _fileno(stdin), _O_BINARY );
355   return result == -1;
356 }
357
358 bool Program::ChangeStdoutToBinary(){
359   int result = _setmode( _fileno(stdout), _O_BINARY );
360   return result == -1;
361 }
362
363 }