LLVM API Documentation

Win32/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 is distributed under the University of Illinois Open Source
00006 // 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 <cstdio>
00016 #include <malloc.h>
00017 #include <io.h>
00018 #include <fcntl.h>
00019 
00020 //===----------------------------------------------------------------------===//
00021 //=== WARNING: Implementation here must contain only Win32 specific code 
00022 //===          and must not be UNIX code
00023 //===----------------------------------------------------------------------===//
00024 
00025 namespace llvm {
00026 using namespace sys;
00027 
00028 // This function just uses the PATH environment variable to find the program.
00029 Path
00030 Program::FindProgramByName(const std::string& progName) {
00031 
00032   // Check some degenerate cases
00033   if (progName.length() == 0) // no program
00034     return Path();
00035   Path temp;
00036   if (!temp.set(progName)) // invalid name
00037     return Path();
00038   if (temp.canExecute()) // already executable as is
00039     return temp;
00040 
00041   // At this point, the file name is valid and its not executable.
00042   // Let Windows search for it.
00043   char buffer[MAX_PATH];
00044   char *dummy = NULL;
00045   DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH,
00046                          buffer, &dummy);
00047 
00048   // See if it wasn't found.
00049   if (len == 0)
00050     return Path();
00051 
00052   // See if we got the entire path.
00053   if (len < MAX_PATH)
00054     return Path(buffer);
00055 
00056   // Buffer was too small; grow and retry.
00057   while (true) {
00058     char *b = reinterpret_cast<char *>(_alloca(len+1));
00059     DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy);
00060 
00061     // It is unlikely the search failed, but it's always possible some file
00062     // was added or removed since the last search, so be paranoid...
00063     if (len2 == 0)
00064       return Path();
00065     else if (len2 <= len)
00066       return Path(b);
00067 
00068     len = len2;
00069   }
00070 }
00071 
00072 static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) {
00073   HANDLE h;
00074   if (path == 0) {
00075     DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
00076                     GetCurrentProcess(), &h,
00077                     0, TRUE, DUPLICATE_SAME_ACCESS);
00078     return h;
00079   }
00080   
00081   const char *fname;
00082   if (path->isEmpty())
00083     fname = "NUL";
00084   else
00085     fname = path->toString().c_str();
00086 
00087   SECURITY_ATTRIBUTES sa;
00088   sa.nLength = sizeof(sa);
00089   sa.lpSecurityDescriptor = 0;
00090   sa.bInheritHandle = TRUE;
00091 
00092   h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ,
00093                  &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
00094                  FILE_ATTRIBUTE_NORMAL, NULL);
00095   if (h == INVALID_HANDLE_VALUE) {
00096     MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
00097         (fd ? "input: " : "output: "));
00098   }
00099 
00100   return h;
00101 }
00102 
00103 #ifdef __MINGW32__
00104   // Due to unknown reason, mingw32's w32api doesn't have this declaration.
00105   extern "C"
00106   BOOL WINAPI SetInformationJobObject(HANDLE hJob,
00107                                       JOBOBJECTINFOCLASS JobObjectInfoClass,
00108                                       LPVOID lpJobObjectInfo,
00109                                       DWORD cbJobObjectInfoLength);
00110 #endif
00111   
00112 int 
00113 Program::ExecuteAndWait(const Path& path, 
00114                         const char** args,
00115                         const char** envp,
00116                         const Path** redirects,
00117                         unsigned secondsToWait,
00118                         unsigned memoryLimit,
00119                         std::string* ErrMsg) {
00120   if (!path.canExecute()) {
00121     if (ErrMsg)
00122       *ErrMsg = "program not executable";
00123     return -1;
00124   }
00125 
00126   // Windows wants a command line, not an array of args, to pass to the new
00127   // process.  We have to concatenate them all, while quoting the args that
00128   // have embedded spaces.
00129 
00130   // First, determine the length of the command line.
00131   unsigned len = 0;
00132   for (unsigned i = 0; args[i]; i++) {
00133     len += strlen(args[i]) + 1;
00134     if (strchr(args[i], ' '))
00135       len += 2;
00136   }
00137 
00138   // Now build the command line.
00139   char *command = reinterpret_cast<char *>(_alloca(len+1));
00140   char *p = command;
00141 
00142   for (unsigned i = 0; args[i]; i++) {
00143     const char *arg = args[i];
00144     size_t len = strlen(arg);
00145     bool needsQuoting = strchr(arg, ' ') != 0;
00146     if (needsQuoting)
00147       *p++ = '"';
00148     memcpy(p, arg, len);
00149     p += len;
00150     if (needsQuoting)
00151       *p++ = '"';
00152     *p++ = ' ';
00153   }
00154 
00155   *p = 0;
00156 
00157   // The pointer to the environment block for the new process.
00158   char *envblock = 0;
00159   
00160   if (envp) {
00161     // An environment block consists of a null-terminated block of
00162     // null-terminated strings. Convert the array of environment variables to
00163     // an environment block by concatenating them.
00164 
00165     // First, determine the length of the environment block.
00166     len = 0;
00167     for (unsigned i = 0; envp[i]; i++)
00168       len += strlen(envp[i]) + 1;
00169 
00170     // Now build the environment block.
00171     envblock = reinterpret_cast<char *>(_alloca(len+1));
00172     p = envblock;
00173 
00174     for (unsigned i = 0; envp[i]; i++) {
00175       const char *ev = envp[i];
00176       size_t len = strlen(ev) + 1;
00177       memcpy(p, ev, len);
00178       p += len;
00179     }
00180 
00181     *p = 0;
00182   }
00183 
00184   // Create a child process.
00185   STARTUPINFO si;
00186   memset(&si, 0, sizeof(si));
00187   si.cb = sizeof(si);
00188   si.hStdInput = INVALID_HANDLE_VALUE;
00189   si.hStdOutput = INVALID_HANDLE_VALUE;
00190   si.hStdError = INVALID_HANDLE_VALUE;
00191 
00192   if (redirects) {
00193     si.dwFlags = STARTF_USESTDHANDLES;
00194     
00195     si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
00196     if (si.hStdInput == INVALID_HANDLE_VALUE) {
00197       MakeErrMsg(ErrMsg, "can't redirect stdin");
00198       return -1;
00199     }
00200     si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
00201     if (si.hStdOutput == INVALID_HANDLE_VALUE) {
00202       CloseHandle(si.hStdInput);
00203       MakeErrMsg(ErrMsg, "can't redirect stdout");
00204       return -1;
00205     }
00206     if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
00207       // If stdout and stderr should go to the same place, redirect stderr
00208       // to the handle already open for stdout.
00209       DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
00210                       GetCurrentProcess(), &si.hStdError,
00211                       0, TRUE, DUPLICATE_SAME_ACCESS);
00212     } else {
00213       // Just redirect stderr
00214       si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
00215       if (si.hStdError == INVALID_HANDLE_VALUE) {
00216         CloseHandle(si.hStdInput);
00217         CloseHandle(si.hStdOutput);
00218         MakeErrMsg(ErrMsg, "can't redirect stderr");
00219         return -1;
00220       }
00221     }
00222   }
00223   
00224   PROCESS_INFORMATION pi;
00225   memset(&pi, 0, sizeof(pi));
00226 
00227   fflush(stdout);
00228   fflush(stderr);
00229   BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, FALSE, 0,
00230                           envblock, NULL, &si, &pi);
00231   DWORD err = GetLastError();
00232 
00233   // Regardless of whether the process got created or not, we are done with
00234   // the handles we created for it to inherit.
00235   CloseHandle(si.hStdInput);
00236   CloseHandle(si.hStdOutput);
00237   CloseHandle(si.hStdError);
00238 
00239   // Now return an error if the process didn't get created.
00240   if (!rc)
00241   {
00242     SetLastError(err);
00243     MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + 
00244                path.toString() + "'");
00245     return -1;
00246   }
00247 
00248   // Make sure these get closed no matter what.
00249   AutoHandle hProcess(pi.hProcess);
00250   AutoHandle hThread(pi.hThread);
00251 
00252   // Assign the process to a job if a memory limit is defined.
00253   AutoHandle hJob(0);
00254   if (memoryLimit != 0) {
00255     hJob = CreateJobObject(0, 0);
00256     bool success = false;
00257     if (hJob != 0) {
00258       JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
00259       memset(&jeli, 0, sizeof(jeli));
00260       jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
00261       jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576;
00262       if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
00263                                   &jeli, sizeof(jeli))) {
00264         if (AssignProcessToJobObject(hJob, pi.hProcess))
00265           success = true;
00266       }
00267     }
00268     if (!success) {
00269       SetLastError(GetLastError());
00270       MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
00271       TerminateProcess(pi.hProcess, 1);
00272       WaitForSingleObject(pi.hProcess, INFINITE);
00273       return -1;
00274     }
00275   }
00276 
00277   // Wait for it to terminate.
00278   DWORD millisecondsToWait = INFINITE;
00279   if (secondsToWait > 0)
00280     millisecondsToWait = secondsToWait * 1000;
00281 
00282   if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
00283     if (!TerminateProcess(pi.hProcess, 1)) {
00284       MakeErrMsg(ErrMsg, std::string("Failed to terminate timed-out program '")
00285           + path.toString() + "'");
00286       return -1;
00287     }
00288     WaitForSingleObject(pi.hProcess, INFINITE);
00289   }
00290   
00291   // Get its exit status.
00292   DWORD status;
00293   rc = GetExitCodeProcess(pi.hProcess, &status);
00294   err = GetLastError();
00295 
00296   if (!rc) {
00297     SetLastError(err);
00298     MakeErrMsg(ErrMsg, std::string("Failed getting status for program '") + 
00299                path.toString() + "'");
00300     return -1;
00301   }
00302 
00303   return status;
00304 }
00305 
00306 bool Program::ChangeStdinToBinary(){
00307   int result = _setmode( _fileno(stdin), _O_BINARY );
00308   return result == -1;
00309 }
00310 
00311 bool Program::ChangeStdoutToBinary(){
00312   int result = _setmode( _fileno(stdout), _O_BINARY );
00313   return result == -1;
00314 }
00315 
00316 }