LLVM API Documentation

Windows/Process.inc
Go to the documentation of this file.
00001 //===- Win32/Process.cpp - Win32 Process 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 Process class.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "llvm/Support/Allocator.h"
00015 #include "llvm/Support/ErrorHandling.h"
00016 #include "llvm/Support/WindowsError.h"
00017 #include <malloc.h>
00018 
00019 // The Windows.h header must be after LLVM and standard headers.
00020 #include "WindowsSupport.h"
00021 
00022 #include <direct.h>
00023 #include <io.h>
00024 #include <psapi.h>
00025 #include <shellapi.h>
00026 
00027 #ifdef __MINGW32__
00028  #if (HAVE_LIBPSAPI != 1)
00029   #error "libpsapi.a should be present"
00030  #endif
00031  #if (HAVE_LIBSHELL32 != 1)
00032   #error "libshell32.a should be present"
00033  #endif
00034 #else
00035  #pragma comment(lib, "psapi.lib")
00036  #pragma comment(lib, "shell32.lib")
00037 #endif
00038 
00039 //===----------------------------------------------------------------------===//
00040 //=== WARNING: Implementation here must contain only Win32 specific code
00041 //===          and must not be UNIX code
00042 //===----------------------------------------------------------------------===//
00043 
00044 #ifdef __MINGW32__
00045 // This ban should be lifted when MinGW 1.0+ has defined this value.
00046 #  define _HEAPOK (-2)
00047 #endif
00048 
00049 using namespace llvm;
00050 using namespace sys;
00051 
00052 process::id_type self_process::get_id() {
00053   return GetCurrentProcessId();
00054 }
00055 
00056 static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
00057   ULARGE_INTEGER TimeInteger;
00058   TimeInteger.LowPart = Time.dwLowDateTime;
00059   TimeInteger.HighPart = Time.dwHighDateTime;
00060 
00061   // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
00062   return TimeValue(
00063       static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000),
00064       static_cast<TimeValue::NanoSecondsType>(
00065           (TimeInteger.QuadPart % 10000000) * 100));
00066 }
00067 
00068 TimeValue self_process::get_user_time() const {
00069   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
00070   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
00071                       &UserTime) == 0)
00072     return TimeValue();
00073 
00074   return getTimeValueFromFILETIME(UserTime);
00075 }
00076 
00077 TimeValue self_process::get_system_time() const {
00078   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
00079   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
00080                       &UserTime) == 0)
00081     return TimeValue();
00082 
00083   return getTimeValueFromFILETIME(KernelTime);
00084 }
00085 
00086 // This function retrieves the page size using GetNativeSystemInfo() and is
00087 // present solely so it can be called once to initialize the self_process member
00088 // below.
00089 static unsigned getPageSize() {
00090   // GetNativeSystemInfo() provides the physical page size which may differ
00091   // from GetSystemInfo() in 32-bit applications running under WOW64.
00092   SYSTEM_INFO info;
00093   GetNativeSystemInfo(&info);
00094   // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
00095   // but dwAllocationGranularity.
00096   return static_cast<unsigned>(info.dwPageSize);
00097 }
00098 
00099 // This constructor guaranteed to be run exactly once on a single thread, and
00100 // sets up various process invariants that can be queried cheaply from then on.
00101 self_process::self_process() : PageSize(getPageSize()) {
00102 }
00103 
00104 
00105 size_t
00106 Process::GetMallocUsage()
00107 {
00108   _HEAPINFO hinfo;
00109   hinfo._pentry = NULL;
00110 
00111   size_t size = 0;
00112 
00113   while (_heapwalk(&hinfo) == _HEAPOK)
00114     size += hinfo._size;
00115 
00116   return size;
00117 }
00118 
00119 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
00120                            TimeValue &sys_time) {
00121   elapsed = TimeValue::now();
00122 
00123   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
00124   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
00125                       &UserTime) == 0)
00126     return;
00127 
00128   user_time = getTimeValueFromFILETIME(UserTime);
00129   sys_time = getTimeValueFromFILETIME(KernelTime);
00130 }
00131 
00132 // Some LLVM programs such as bugpoint produce core files as a normal part of
00133 // their operation. To prevent the disk from filling up, this configuration
00134 // item does what's necessary to prevent their generation.
00135 void Process::PreventCoreFiles() {
00136   // Windows does have the concept of core files, called minidumps.  However,
00137   // disabling minidumps for a particular application extends past the lifetime
00138   // of that application, which is the incorrect behavior for this API.
00139   // Additionally, the APIs require elevated privileges to disable and re-
00140   // enable minidumps, which makes this untenable. For more information, see
00141   // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
00142   // later).
00143   //
00144   // Windows also has modal pop-up message boxes.  As this method is used by
00145   // bugpoint, preventing these pop-ups is additionally important.
00146   SetErrorMode(SEM_FAILCRITICALERRORS |
00147                SEM_NOGPFAULTERRORBOX |
00148                SEM_NOOPENFILEERRORBOX);
00149 }
00150 
00151 /// Returns the environment variable \arg Name's value as a string encoded in
00152 /// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
00153 Optional<std::string> Process::GetEnv(StringRef Name) {
00154   // Convert the argument to UTF-16 to pass it to _wgetenv().
00155   SmallVector<wchar_t, 128> NameUTF16;
00156   if (windows::UTF8ToUTF16(Name, NameUTF16))
00157     return None;
00158 
00159   // Environment variable can be encoded in non-UTF8 encoding, and there's no
00160   // way to know what the encoding is. The only reliable way to look up
00161   // multibyte environment variable is to use GetEnvironmentVariableW().
00162   SmallVector<wchar_t, MAX_PATH> Buf;
00163   size_t Size = MAX_PATH;
00164   do {
00165     Buf.reserve(Size);
00166     Size =
00167         GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
00168     if (Size == 0)
00169       return None;
00170 
00171     // Try again with larger buffer.
00172   } while (Size > Buf.capacity());
00173   Buf.set_size(Size);
00174 
00175   // Convert the result from UTF-16 to UTF-8.
00176   SmallVector<char, MAX_PATH> Res;
00177   if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
00178     return None;
00179   return std::string(Res.data());
00180 }
00181 
00182 static std::error_code windows_error(DWORD E) {
00183   return mapWindowsError(E);
00184 }
00185 
00186 static void AllocateAndPush(const SmallVectorImpl<char> &S,
00187                             SmallVectorImpl<const char *> &Vector,
00188                             SpecificBumpPtrAllocator<char> &Allocator) {
00189   char *Buffer = Allocator.Allocate(S.size() + 1);
00190   ::memcpy(Buffer, S.data(), S.size());
00191   Buffer[S.size()] = '\0';
00192   Vector.push_back(Buffer);
00193 }
00194 
00195 /// Convert Arg from UTF-16 to UTF-8 and push it onto Args.
00196 static std::error_code
00197 ConvertAndPushArg(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
00198                   SpecificBumpPtrAllocator<char> &Allocator) {
00199   SmallVector<char, MAX_PATH> ArgString;
00200   if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), ArgString))
00201     return ec;
00202   AllocateAndPush(ArgString, Args, Allocator);
00203   return std::error_code();
00204 }
00205 
00206 /// \brief Perform wildcard expansion of Arg, or just push it into Args if it
00207 /// doesn't have wildcards or doesn't match any files.
00208 static std::error_code
00209 WildcardExpand(const wchar_t *Arg, SmallVectorImpl<const char *> &Args,
00210                SpecificBumpPtrAllocator<char> &Allocator) {
00211   if (!wcspbrk(Arg, L"*?")) {
00212     // Arg does not contain any wildcard characters. This is the common case.
00213     return ConvertAndPushArg(Arg, Args, Allocator);
00214   }
00215 
00216   if (wcscmp(Arg, L"/?") == 0 || wcscmp(Arg, L"-?") == 0) {
00217     // Don't wildcard expand /?. Always treat it as an option.
00218     return ConvertAndPushArg(Arg, Args, Allocator);
00219   }
00220 
00221   // Extract any directory part of the argument.
00222   SmallVector<char, MAX_PATH> Dir;
00223   if (std::error_code ec = windows::UTF16ToUTF8(Arg, wcslen(Arg), Dir))
00224     return ec;
00225   sys::path::remove_filename(Dir);
00226   const int DirSize = Dir.size();
00227 
00228   // Search for matching files.
00229   WIN32_FIND_DATAW FileData;
00230   HANDLE FindHandle = FindFirstFileW(Arg, &FileData);
00231   if (FindHandle == INVALID_HANDLE_VALUE) {
00232     return ConvertAndPushArg(Arg, Args, Allocator);
00233   }
00234 
00235   std::error_code ec;
00236   do {
00237     SmallVector<char, MAX_PATH> FileName;
00238     ec = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName),
00239                               FileName);
00240     if (ec)
00241       break;
00242 
00243     // Push the filename onto Dir, and remove it afterwards.
00244     llvm::sys::path::append(Dir, StringRef(FileName.data(), FileName.size()));
00245     AllocateAndPush(Dir, Args, Allocator);
00246     Dir.resize(DirSize);
00247   } while (FindNextFileW(FindHandle, &FileData));
00248 
00249   FindClose(FindHandle);
00250   return ec;
00251 }
00252 
00253 std::error_code
00254 Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
00255                            ArrayRef<const char *>,
00256                            SpecificBumpPtrAllocator<char> &ArgAllocator) {
00257   int ArgCount;
00258   wchar_t **UnicodeCommandLine =
00259       CommandLineToArgvW(GetCommandLineW(), &ArgCount);
00260   if (!UnicodeCommandLine)
00261     return windows_error(::GetLastError());
00262 
00263   Args.reserve(ArgCount);
00264   std::error_code ec;
00265 
00266   for (int i = 0; i < ArgCount; ++i) {
00267     ec = WildcardExpand(UnicodeCommandLine[i], Args, ArgAllocator);
00268     if (ec)
00269       break;
00270   }
00271 
00272   LocalFree(UnicodeCommandLine);
00273   return ec;
00274 }
00275 
00276 bool Process::StandardInIsUserInput() {
00277   return FileDescriptorIsDisplayed(0);
00278 }
00279 
00280 bool Process::StandardOutIsDisplayed() {
00281   return FileDescriptorIsDisplayed(1);
00282 }
00283 
00284 bool Process::StandardErrIsDisplayed() {
00285   return FileDescriptorIsDisplayed(2);
00286 }
00287 
00288 bool Process::FileDescriptorIsDisplayed(int fd) {
00289   DWORD Mode;  // Unused
00290   return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
00291 }
00292 
00293 unsigned Process::StandardOutColumns() {
00294   unsigned Columns = 0;
00295   CONSOLE_SCREEN_BUFFER_INFO csbi;
00296   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
00297     Columns = csbi.dwSize.X;
00298   return Columns;
00299 }
00300 
00301 unsigned Process::StandardErrColumns() {
00302   unsigned Columns = 0;
00303   CONSOLE_SCREEN_BUFFER_INFO csbi;
00304   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
00305     Columns = csbi.dwSize.X;
00306   return Columns;
00307 }
00308 
00309 // The terminal always has colors.
00310 bool Process::FileDescriptorHasColors(int fd) {
00311   return FileDescriptorIsDisplayed(fd);
00312 }
00313 
00314 bool Process::StandardOutHasColors() {
00315   return FileDescriptorHasColors(1);
00316 }
00317 
00318 bool Process::StandardErrHasColors() {
00319   return FileDescriptorHasColors(2);
00320 }
00321 
00322 static bool UseANSI = false;
00323 void Process::UseANSIEscapeCodes(bool enable) {
00324   UseANSI = enable;
00325 }
00326 
00327 namespace {
00328 class DefaultColors
00329 {
00330   private:
00331     WORD defaultColor;
00332   public:
00333     DefaultColors()
00334      :defaultColor(GetCurrentColor()) {}
00335     static unsigned GetCurrentColor() {
00336       CONSOLE_SCREEN_BUFFER_INFO csbi;
00337       if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
00338         return csbi.wAttributes;
00339       return 0;
00340     }
00341     WORD operator()() const { return defaultColor; }
00342 };
00343 
00344 DefaultColors defaultColors;
00345 }
00346 
00347 bool Process::ColorNeedsFlush() {
00348   return !UseANSI;
00349 }
00350 
00351 const char *Process::OutputBold(bool bg) {
00352   if (UseANSI) return "\033[1m";
00353 
00354   WORD colors = DefaultColors::GetCurrentColor();
00355   if (bg)
00356     colors |= BACKGROUND_INTENSITY;
00357   else
00358     colors |= FOREGROUND_INTENSITY;
00359   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
00360   return 0;
00361 }
00362 
00363 const char *Process::OutputColor(char code, bool bold, bool bg) {
00364   if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
00365 
00366   WORD colors;
00367   if (bg) {
00368     colors = ((code&1) ? BACKGROUND_RED : 0) |
00369       ((code&2) ? BACKGROUND_GREEN : 0 ) |
00370       ((code&4) ? BACKGROUND_BLUE : 0);
00371     if (bold)
00372       colors |= BACKGROUND_INTENSITY;
00373   } else {
00374     colors = ((code&1) ? FOREGROUND_RED : 0) |
00375       ((code&2) ? FOREGROUND_GREEN : 0 ) |
00376       ((code&4) ? FOREGROUND_BLUE : 0);
00377     if (bold)
00378       colors |= FOREGROUND_INTENSITY;
00379   }
00380   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
00381   return 0;
00382 }
00383 
00384 static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
00385   CONSOLE_SCREEN_BUFFER_INFO info;
00386   GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
00387   return info.wAttributes;
00388 }
00389 
00390 const char *Process::OutputReverse() {
00391   if (UseANSI) return "\033[7m";
00392 
00393   const WORD attributes
00394    = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
00395 
00396   const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
00397     FOREGROUND_RED | FOREGROUND_INTENSITY;
00398   const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
00399     BACKGROUND_RED | BACKGROUND_INTENSITY;
00400   const WORD color_mask = foreground_mask | background_mask;
00401 
00402   WORD new_attributes =
00403     ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
00404     ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
00405     ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
00406     ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
00407     ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
00408     ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
00409     ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
00410     ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
00411     0;
00412   new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
00413 
00414   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
00415   return 0;
00416 }
00417 
00418 const char *Process::ResetColor() {
00419   if (UseANSI) return "\033[0m";
00420   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
00421   return 0;
00422 }
00423 
00424 unsigned Process::GetRandomNumber() {
00425   HCRYPTPROV HCPC;
00426   if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
00427                               CRYPT_VERIFYCONTEXT))
00428     report_fatal_error("Could not acquire a cryptographic context");
00429 
00430   ScopedCryptContext CryptoProvider(HCPC);
00431   unsigned Ret;
00432   if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
00433                         reinterpret_cast<BYTE *>(&Ret)))
00434     report_fatal_error("Could not generate a random number");
00435   return Ret;
00436 }