LLVM API Documentation

Program.inc

Go to the documentation of this file.
00001 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===//
00002 // 
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by Jeff Cohen and is distributed under the 
00006 // University of Illinois Open Source License. See LICENSE.TXT for details.
00007 // 
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file provides the Win32 specific implementation of the Program class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "Win32.h"
00015 #include <malloc.h>
00016 #include <io.h>
00017 
00018 //===----------------------------------------------------------------------===//
00019 //=== WARNING: Implementation here must contain only Win32 specific code 
00020 //===          and must not be UNIX code
00021 //===----------------------------------------------------------------------===//
00022 
00023 namespace llvm {
00024 using namespace sys;
00025 
00026 // This function just uses the PATH environment variable to find the program.
00027 Path
00028 Program::FindProgramByName(const std::string& progName) {
00029 
00030   // Check some degenerate cases
00031   if (progName.length() == 0) // no program
00032     return Path();
00033   Path temp;
00034   if (!temp.set(progName)) // invalid name
00035     return Path();
00036   if (temp.canExecute()) // already executable as is
00037     return temp;
00038 
00039   // At this point, the file name is valid and its not executable.
00040   // Let Windows search for it.
00041   char buffer[MAX_PATH];
00042   char *dummy = NULL;
00043   DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH,
00044                          buffer, &dummy);
00045 
00046   // See if it wasn't found.
00047   if (len == 0)
00048     return Path();
00049 
00050   // See if we got the entire path.
00051   if (len < MAX_PATH)
00052     return Path(buffer);
00053 
00054   // Buffer was too small; grow and retry.
00055   while (true) {
00056     char *b = reinterpret_cast<char *>(_alloca(len+1));
00057     DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy);
00058 
00059     // It is unlikely the search failed, but it's always possible some file
00060     // was added or removed since the last search, so be paranoid...
00061     if (len2 == 0)
00062       return Path();
00063     else if (len2 <= len)
00064       return Path(b);
00065 
00066     len = len2;
00067   }
00068 }
00069 
00070 static HANDLE RedirectIO(const Path *path, int fd) {
00071   HANDLE h;
00072   if (path == 0) {
00073     DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
00074                     GetCurrentProcess(), &h,
00075                     0, TRUE, DUPLICATE_SAME_ACCESS);
00076     return h;
00077   }
00078 
00079   const char *fname = path->toString().c_str();
00080   if (*fname == 0)
00081     fname = "NUL";
00082 
00083   SECURITY_ATTRIBUTES sa;
00084   sa.nLength = sizeof(sa);
00085   sa.lpSecurityDescriptor = 0;
00086   sa.bInheritHandle = TRUE;
00087 
00088   h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ,
00089                  &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
00090                  FILE_ATTRIBUTE_NORMAL, NULL);
00091   if (h == INVALID_HANDLE_VALUE) {
00092     ThrowError(std::string(fname) + ": Can't open file for " +
00093         (fd ? "input: " : "output: "));
00094   }
00095   return h;
00096 }
00097 
00098 int 
00099 Program::ExecuteAndWait(const Path& path, 
00100                         const char** args,
00101                         const char** envp,
00102                         const Path** redirects,
00103                         unsigned secondsToWait) {
00104   if (!path.canExecute())
00105     throw path.toString() + " is not executable"; 
00106 
00107   // Windows wants a command line, not an array of args, to pass to the new
00108   // process.  We have to concatenate them all, while quoting the args that
00109   // have embedded spaces.
00110 
00111   // First, determine the length of the command line.
00112   unsigned len = 0;
00113   for (unsigned i = 0; args[i]; i++) {
00114     len += strlen(args[i]) + 1;
00115     if (strchr(args[i], ' '))
00116       len += 2;
00117   }
00118 
00119   // Now build the command line.
00120   char *command = reinterpret_cast<char *>(_alloca(len));
00121   char *p = command;
00122 
00123   for (unsigned i = 0; args[i]; i++) {
00124     const char *arg = args[i];
00125     size_t len = strlen(arg);
00126     bool needsQuoting = strchr(arg, ' ') != 0;
00127     if (needsQuoting)
00128       *p++ = '"';
00129     memcpy(p, arg, len);
00130     p += len;
00131     if (needsQuoting)
00132       *p++ = '"';
00133     *p++ = ' ';
00134   }
00135 
00136   *p = 0;
00137 
00138   // Create a child process.
00139   STARTUPINFO si;
00140   memset(&si, 0, sizeof(si));
00141   si.cb = sizeof(si);
00142   si.hStdInput = INVALID_HANDLE_VALUE;
00143   si.hStdOutput = INVALID_HANDLE_VALUE;
00144   si.hStdError = INVALID_HANDLE_VALUE;
00145 
00146   if (redirects) {
00147     si.dwFlags = STARTF_USESTDHANDLES;
00148     
00149     try {
00150       si.hStdInput = RedirectIO(redirects[0], 0);
00151       si.hStdOutput = RedirectIO(redirects[1], 1);
00152       if (redirects[1] && redirects[2] && *(redirects[1]) != *(redirects[2])) {
00153         si.hStdError = RedirectIO(redirects[2], 2);
00154       } else {
00155         DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
00156                         GetCurrentProcess(), &si.hStdError,
00157                         0, TRUE, DUPLICATE_SAME_ACCESS);
00158       }
00159     } catch (...) {
00160       CloseHandle(si.hStdInput);
00161       CloseHandle(si.hStdOutput);
00162       CloseHandle(si.hStdError);
00163       throw;
00164     }
00165   }
00166 
00167   PROCESS_INFORMATION pi;
00168   memset(&pi, 0, sizeof(pi));
00169 
00170   fflush(stdout);
00171   fflush(stderr);
00172   BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, FALSE, 0,
00173                           envp, NULL, &si, &pi);
00174   DWORD err = GetLastError();
00175 
00176   // Regardless of whether the process got created or not, we are done with
00177   // the handles we created for it to inherit.
00178   CloseHandle(si.hStdInput);
00179   CloseHandle(si.hStdOutput);
00180   CloseHandle(si.hStdError);
00181 
00182   // Now throw an error if the process didn't get created.
00183   if (!rc)
00184   {
00185     SetLastError(err);
00186     ThrowError(std::string("Couldn't execute program '") + 
00187                path.toString() + "'");
00188   }
00189 
00190   // Wait for it to terminate.
00191   DWORD millisecondsToWait = INFINITE;
00192   if (secondsToWait > 0)
00193     millisecondsToWait = secondsToWait * 1000;
00194 
00195   if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
00196     if (!TerminateProcess(pi.hProcess, 1)) {
00197       ThrowError(std::string("Failed to terminate timed-out program '") + 
00198                  path.toString() + "'");
00199     }
00200     WaitForSingleObject(pi.hProcess, INFINITE);
00201   }
00202   
00203   // Get its exit status.
00204   DWORD status;
00205   rc = GetExitCodeProcess(pi.hProcess, &status);
00206   err = GetLastError();
00207 
00208   // Done with the handles; go close them.
00209   CloseHandle(pi.hProcess);
00210   CloseHandle(pi.hThread);
00211 
00212   if (!rc) {
00213     SetLastError(err);
00214     ThrowError(std::string("Failed getting status for program '") + 
00215                path.toString() + "'");
00216   }
00217 
00218   return status;
00219 }
00220 
00221 }