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