LLVM API Documentation
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 }