Home | History | Annotate | Download | only in Windows
      1 //===- Win32/Process.cpp - Win32 Process 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 Process class.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/Support/Allocator.h"
     15 #include "llvm/Support/ErrorHandling.h"
     16 #include "llvm/Support/WindowsError.h"
     17 #include <malloc.h>
     18 
     19 // The Windows.h header must be after LLVM and standard headers.
     20 #include "WindowsSupport.h"
     21 
     22 #include <direct.h>
     23 #include <io.h>
     24 #include <psapi.h>
     25 #include <shellapi.h>
     26 
     27 #ifdef __MINGW32__
     28  #if (HAVE_LIBPSAPI != 1)
     29   #error "libpsapi.a should be present"
     30  #endif
     31  #if (HAVE_LIBSHELL32 != 1)
     32   #error "libshell32.a should be present"
     33  #endif
     34 #else
     35  #pragma comment(lib, "psapi.lib")
     36  #pragma comment(lib, "shell32.lib")
     37 #endif
     38 
     39 //===----------------------------------------------------------------------===//
     40 //=== WARNING: Implementation here must contain only Win32 specific code
     41 //===          and must not be UNIX code
     42 //===----------------------------------------------------------------------===//
     43 
     44 #ifdef __MINGW32__
     45 // This ban should be lifted when MinGW 1.0+ has defined this value.
     46 #  define _HEAPOK (-2)
     47 #endif
     48 
     49 using namespace llvm;
     50 using namespace sys;
     51 
     52 process::id_type self_process::get_id() {
     53   return GetCurrentProcessId();
     54 }
     55 
     56 static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
     57   ULARGE_INTEGER TimeInteger;
     58   TimeInteger.LowPart = Time.dwLowDateTime;
     59   TimeInteger.HighPart = Time.dwHighDateTime;
     60 
     61   // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
     62   return TimeValue(
     63       static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000),
     64       static_cast<TimeValue::NanoSecondsType>(
     65           (TimeInteger.QuadPart % 10000000) * 100));
     66 }
     67 
     68 TimeValue self_process::get_user_time() const {
     69   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
     70   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
     71                       &UserTime) == 0)
     72     return TimeValue();
     73 
     74   return getTimeValueFromFILETIME(UserTime);
     75 }
     76 
     77 TimeValue self_process::get_system_time() const {
     78   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
     79   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
     80                       &UserTime) == 0)
     81     return TimeValue();
     82 
     83   return getTimeValueFromFILETIME(KernelTime);
     84 }
     85 
     86 // This function retrieves the page size using GetNativeSystemInfo() and is
     87 // present solely so it can be called once to initialize the self_process member
     88 // below.
     89 static unsigned getPageSize() {
     90   // GetNativeSystemInfo() provides the physical page size which may differ
     91   // from GetSystemInfo() in 32-bit applications running under WOW64.
     92   SYSTEM_INFO info;
     93   GetNativeSystemInfo(&info);
     94   // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
     95   // but dwAllocationGranularity.
     96   return static_cast<unsigned>(info.dwPageSize);
     97 }
     98 
     99 // This constructor guaranteed to be run exactly once on a single thread, and
    100 // sets up various process invariants that can be queried cheaply from then on.
    101 self_process::self_process() : PageSize(getPageSize()) {
    102 }
    103 
    104 
    105 size_t
    106 Process::GetMallocUsage()
    107 {
    108   _HEAPINFO hinfo;
    109   hinfo._pentry = NULL;
    110 
    111   size_t size = 0;
    112 
    113   while (_heapwalk(&hinfo) == _HEAPOK)
    114     size += hinfo._size;
    115 
    116   return size;
    117 }
    118 
    119 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
    120                            TimeValue &sys_time) {
    121   elapsed = TimeValue::now();
    122 
    123   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
    124   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
    125                       &UserTime) == 0)
    126     return;
    127 
    128   user_time = getTimeValueFromFILETIME(UserTime);
    129   sys_time = getTimeValueFromFILETIME(KernelTime);
    130 }
    131 
    132 // Some LLVM programs such as bugpoint produce core files as a normal part of
    133 // their operation. To prevent the disk from filling up, this configuration
    134 // item does what's necessary to prevent their generation.
    135 void Process::PreventCoreFiles() {
    136   // Windows does have the concept of core files, called minidumps.  However,
    137   // disabling minidumps for a particular application extends past the lifetime
    138   // of that application, which is the incorrect behavior for this API.
    139   // Additionally, the APIs require elevated privileges to disable and re-
    140   // enable minidumps, which makes this untenable. For more information, see
    141   // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
    142   // later).
    143   //
    144   // Windows also has modal pop-up message boxes.  As this method is used by
    145   // bugpoint, preventing these pop-ups is additionally important.
    146   SetErrorMode(SEM_FAILCRITICALERRORS |
    147                SEM_NOGPFAULTERRORBOX |
    148                SEM_NOOPENFILEERRORBOX);
    149 }
    150 
    151 /// Returns the environment variable \arg Name's value as a string encoded in
    152 /// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
    153 Optional<std::string> Process::GetEnv(StringRef Name) {
    154   // Convert the argument to UTF-16 to pass it to _wgetenv().
    155   SmallVector<wchar_t, 128> NameUTF16;
    156   if (windows::UTF8ToUTF16(Name, NameUTF16))
    157     return None;
    158 
    159   // Environment variable can be encoded in non-UTF8 encoding, and there's no
    160   // way to know what the encoding is. The only reliable way to look up
    161   // multibyte environment variable is to use GetEnvironmentVariableW().
    162   SmallVector<wchar_t, MAX_PATH> Buf;
    163   size_t Size = MAX_PATH;
    164   do {
    165     Buf.reserve(Size);
    166     Size =
    167         GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
    168     if (Size == 0)
    169       return None;
    170 
    171     // Try again with larger buffer.
    172   } while (Size > Buf.capacity());
    173   Buf.set_size(Size);
    174 
    175   // Convert the result from UTF-16 to UTF-8.
    176   SmallVector<char, MAX_PATH> Res;
    177   if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
    178     return None;
    179   return std::string(Res.data());
    180 }
    181 
    182 static std::error_code windows_error(DWORD E) {
    183   return mapWindowsError(E);
    184 }
    185 
    186 std::error_code
    187 Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
    188                            ArrayRef<const char *>,
    189                            SpecificBumpPtrAllocator<char> &ArgAllocator) {
    190   int NewArgCount;
    191   std::error_code ec;
    192 
    193   wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(),
    194                                                     &NewArgCount);
    195   if (!UnicodeCommandLine)
    196     return windows_error(::GetLastError());
    197 
    198   Args.reserve(NewArgCount);
    199 
    200   for (int i = 0; i < NewArgCount; ++i) {
    201     SmallVector<char, MAX_PATH> NewArgString;
    202     ec = windows::UTF16ToUTF8(UnicodeCommandLine[i],
    203                               wcslen(UnicodeCommandLine[i]),
    204                               NewArgString);
    205     if (ec)
    206       break;
    207 
    208     char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1);
    209     ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1);
    210     Args.push_back(Buffer);
    211   }
    212   LocalFree(UnicodeCommandLine);
    213   if (ec)
    214     return ec;
    215 
    216   return std::error_code();
    217 }
    218 
    219 bool Process::StandardInIsUserInput() {
    220   return FileDescriptorIsDisplayed(0);
    221 }
    222 
    223 bool Process::StandardOutIsDisplayed() {
    224   return FileDescriptorIsDisplayed(1);
    225 }
    226 
    227 bool Process::StandardErrIsDisplayed() {
    228   return FileDescriptorIsDisplayed(2);
    229 }
    230 
    231 bool Process::FileDescriptorIsDisplayed(int fd) {
    232   DWORD Mode;  // Unused
    233   return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
    234 }
    235 
    236 unsigned Process::StandardOutColumns() {
    237   unsigned Columns = 0;
    238   CONSOLE_SCREEN_BUFFER_INFO csbi;
    239   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
    240     Columns = csbi.dwSize.X;
    241   return Columns;
    242 }
    243 
    244 unsigned Process::StandardErrColumns() {
    245   unsigned Columns = 0;
    246   CONSOLE_SCREEN_BUFFER_INFO csbi;
    247   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
    248     Columns = csbi.dwSize.X;
    249   return Columns;
    250 }
    251 
    252 // The terminal always has colors.
    253 bool Process::FileDescriptorHasColors(int fd) {
    254   return FileDescriptorIsDisplayed(fd);
    255 }
    256 
    257 bool Process::StandardOutHasColors() {
    258   return FileDescriptorHasColors(1);
    259 }
    260 
    261 bool Process::StandardErrHasColors() {
    262   return FileDescriptorHasColors(2);
    263 }
    264 
    265 static bool UseANSI = false;
    266 void Process::UseANSIEscapeCodes(bool enable) {
    267   UseANSI = enable;
    268 }
    269 
    270 namespace {
    271 class DefaultColors
    272 {
    273   private:
    274     WORD defaultColor;
    275   public:
    276     DefaultColors()
    277      :defaultColor(GetCurrentColor()) {}
    278     static unsigned GetCurrentColor() {
    279       CONSOLE_SCREEN_BUFFER_INFO csbi;
    280       if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
    281         return csbi.wAttributes;
    282       return 0;
    283     }
    284     WORD operator()() const { return defaultColor; }
    285 };
    286 
    287 DefaultColors defaultColors;
    288 }
    289 
    290 bool Process::ColorNeedsFlush() {
    291   return !UseANSI;
    292 }
    293 
    294 const char *Process::OutputBold(bool bg) {
    295   if (UseANSI) return "\033[1m";
    296 
    297   WORD colors = DefaultColors::GetCurrentColor();
    298   if (bg)
    299     colors |= BACKGROUND_INTENSITY;
    300   else
    301     colors |= FOREGROUND_INTENSITY;
    302   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
    303   return 0;
    304 }
    305 
    306 const char *Process::OutputColor(char code, bool bold, bool bg) {
    307   if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
    308 
    309   WORD colors;
    310   if (bg) {
    311     colors = ((code&1) ? BACKGROUND_RED : 0) |
    312       ((code&2) ? BACKGROUND_GREEN : 0 ) |
    313       ((code&4) ? BACKGROUND_BLUE : 0);
    314     if (bold)
    315       colors |= BACKGROUND_INTENSITY;
    316   } else {
    317     colors = ((code&1) ? FOREGROUND_RED : 0) |
    318       ((code&2) ? FOREGROUND_GREEN : 0 ) |
    319       ((code&4) ? FOREGROUND_BLUE : 0);
    320     if (bold)
    321       colors |= FOREGROUND_INTENSITY;
    322   }
    323   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
    324   return 0;
    325 }
    326 
    327 static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
    328   CONSOLE_SCREEN_BUFFER_INFO info;
    329   GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
    330   return info.wAttributes;
    331 }
    332 
    333 const char *Process::OutputReverse() {
    334   if (UseANSI) return "\033[7m";
    335 
    336   const WORD attributes
    337    = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
    338 
    339   const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
    340     FOREGROUND_RED | FOREGROUND_INTENSITY;
    341   const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
    342     BACKGROUND_RED | BACKGROUND_INTENSITY;
    343   const WORD color_mask = foreground_mask | background_mask;
    344 
    345   WORD new_attributes =
    346     ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
    347     ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
    348     ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
    349     ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
    350     ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
    351     ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
    352     ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
    353     ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
    354     0;
    355   new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
    356 
    357   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
    358   return 0;
    359 }
    360 
    361 const char *Process::ResetColor() {
    362   if (UseANSI) return "\033[0m";
    363   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
    364   return 0;
    365 }
    366 
    367 unsigned Process::GetRandomNumber() {
    368   HCRYPTPROV HCPC;
    369   if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
    370                               CRYPT_VERIFYCONTEXT))
    371     report_fatal_error("Could not acquire a cryptographic context");
    372 
    373   ScopedCryptContext CryptoProvider(HCPC);
    374   unsigned Ret;
    375   if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
    376                         reinterpret_cast<BYTE *>(&Ret)))
    377     report_fatal_error("Could not generate a random number");
    378   return Ret;
    379 }
    380