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 "Windows.h"
     15 #include <direct.h>
     16 #include <io.h>
     17 #include <malloc.h>
     18 #include <psapi.h>
     19 
     20 #ifdef __MINGW32__
     21  #if (HAVE_LIBPSAPI != 1)
     22   #error "libpsapi.a should be present"
     23  #endif
     24 #else
     25  #pragma comment(lib, "psapi.lib")
     26 #endif
     27 
     28 //===----------------------------------------------------------------------===//
     29 //=== WARNING: Implementation here must contain only Win32 specific code
     30 //===          and must not be UNIX code
     31 //===----------------------------------------------------------------------===//
     32 
     33 #ifdef __MINGW32__
     34 // This ban should be lifted when MinGW 1.0+ has defined this value.
     35 #  define _HEAPOK (-2)
     36 #endif
     37 
     38 using namespace llvm;
     39 using namespace sys;
     40 
     41 
     42 process::id_type self_process::get_id() {
     43   return GetCurrentProcessId();
     44 }
     45 
     46 static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
     47   ULARGE_INTEGER TimeInteger;
     48   TimeInteger.LowPart = Time.dwLowDateTime;
     49   TimeInteger.HighPart = Time.dwHighDateTime;
     50 
     51   // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
     52   return TimeValue(
     53       static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000),
     54       static_cast<TimeValue::NanoSecondsType>(
     55           (TimeInteger.QuadPart % 10000000) * 100));
     56 }
     57 
     58 TimeValue self_process::get_user_time() const {
     59   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
     60   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
     61                       &UserTime) == 0)
     62     return TimeValue();
     63 
     64   return getTimeValueFromFILETIME(UserTime);
     65 }
     66 
     67 TimeValue self_process::get_system_time() const {
     68   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
     69   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
     70                       &UserTime) == 0)
     71     return TimeValue();
     72 
     73   return getTimeValueFromFILETIME(KernelTime);
     74 }
     75 
     76 // This function retrieves the page size using GetSystemInfo and is present
     77 // solely so it can be called once to initialize the self_process member below.
     78 static unsigned getPageSize() {
     79   // NOTE: A 32-bit application running under WOW64 is supposed to use
     80   // GetNativeSystemInfo.  However, this interface is not present prior
     81   // to Windows XP so to use it requires dynamic linking.  It is not clear
     82   // how this affects the reported page size, if at all.  One could argue
     83   // that LLVM ought to run as 64-bits on a 64-bit system, anyway.
     84   SYSTEM_INFO info;
     85   GetSystemInfo(&info);
     86   return static_cast<unsigned>(info.dwPageSize);
     87 }
     88 
     89 // This constructor guaranteed to be run exactly once on a single thread, and
     90 // sets up various process invariants that can be queried cheaply from then on.
     91 self_process::self_process() : PageSize(getPageSize()) {
     92 }
     93 
     94 
     95 size_t
     96 Process::GetMallocUsage()
     97 {
     98   _HEAPINFO hinfo;
     99   hinfo._pentry = NULL;
    100 
    101   size_t size = 0;
    102 
    103   while (_heapwalk(&hinfo) == _HEAPOK)
    104     size += hinfo._size;
    105 
    106   return size;
    107 }
    108 
    109 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
    110                            TimeValue &sys_time) {
    111   elapsed = TimeValue::now();
    112 
    113   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
    114   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
    115                       &UserTime) == 0)
    116     return;
    117 
    118   user_time = getTimeValueFromFILETIME(UserTime);
    119   sys_time = getTimeValueFromFILETIME(KernelTime);
    120 }
    121 
    122 int Process::GetCurrentUserId()
    123 {
    124   return 65536;
    125 }
    126 
    127 int Process::GetCurrentGroupId()
    128 {
    129   return 65536;
    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 item
    134 // does what's necessary to prevent their generation.
    135 void Process::PreventCoreFiles() {
    136   // Windows doesn't do core files, but it does do modal pop-up message
    137   // boxes.  As this method is used by bugpoint, preventing these pop-ups
    138   // is the moral equivalent of suppressing core files.
    139   SetErrorMode(SEM_FAILCRITICALERRORS |
    140                SEM_NOGPFAULTERRORBOX |
    141                SEM_NOOPENFILEERRORBOX);
    142 }
    143 
    144 bool Process::StandardInIsUserInput() {
    145   return FileDescriptorIsDisplayed(0);
    146 }
    147 
    148 bool Process::StandardOutIsDisplayed() {
    149   return FileDescriptorIsDisplayed(1);
    150 }
    151 
    152 bool Process::StandardErrIsDisplayed() {
    153   return FileDescriptorIsDisplayed(2);
    154 }
    155 
    156 bool Process::FileDescriptorIsDisplayed(int fd) {
    157   DWORD Mode;  // Unused
    158   return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
    159 }
    160 
    161 unsigned Process::StandardOutColumns() {
    162   unsigned Columns = 0;
    163   CONSOLE_SCREEN_BUFFER_INFO csbi;
    164   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
    165     Columns = csbi.dwSize.X;
    166   return Columns;
    167 }
    168 
    169 unsigned Process::StandardErrColumns() {
    170   unsigned Columns = 0;
    171   CONSOLE_SCREEN_BUFFER_INFO csbi;
    172   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
    173     Columns = csbi.dwSize.X;
    174   return Columns;
    175 }
    176 
    177 // The terminal always has colors.
    178 bool Process::FileDescriptorHasColors(int fd) {
    179   return FileDescriptorIsDisplayed(fd);
    180 }
    181 
    182 bool Process::StandardOutHasColors() {
    183   return FileDescriptorHasColors(1);
    184 }
    185 
    186 bool Process::StandardErrHasColors() {
    187   return FileDescriptorHasColors(2);
    188 }
    189 
    190 namespace {
    191 class DefaultColors
    192 {
    193   private:
    194     WORD defaultColor;
    195   public:
    196     DefaultColors()
    197      :defaultColor(GetCurrentColor()) {}
    198     static unsigned GetCurrentColor() {
    199       CONSOLE_SCREEN_BUFFER_INFO csbi;
    200       if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
    201         return csbi.wAttributes;
    202       return 0;
    203     }
    204     WORD operator()() const { return defaultColor; }
    205 };
    206 
    207 DefaultColors defaultColors;
    208 }
    209 
    210 bool Process::ColorNeedsFlush() {
    211   return true;
    212 }
    213 
    214 const char *Process::OutputBold(bool bg) {
    215   WORD colors = DefaultColors::GetCurrentColor();
    216   if (bg)
    217     colors |= BACKGROUND_INTENSITY;
    218   else
    219     colors |= FOREGROUND_INTENSITY;
    220   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
    221   return 0;
    222 }
    223 
    224 const char *Process::OutputColor(char code, bool bold, bool bg) {
    225   WORD colors;
    226   if (bg) {
    227     colors = ((code&1) ? BACKGROUND_RED : 0) |
    228       ((code&2) ? BACKGROUND_GREEN : 0 ) |
    229       ((code&4) ? BACKGROUND_BLUE : 0);
    230     if (bold)
    231       colors |= BACKGROUND_INTENSITY;
    232   } else {
    233     colors = ((code&1) ? FOREGROUND_RED : 0) |
    234       ((code&2) ? FOREGROUND_GREEN : 0 ) |
    235       ((code&4) ? FOREGROUND_BLUE : 0);
    236     if (bold)
    237       colors |= FOREGROUND_INTENSITY;
    238   }
    239   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
    240   return 0;
    241 }
    242 
    243 static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
    244   CONSOLE_SCREEN_BUFFER_INFO info;
    245   GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
    246   return info.wAttributes;
    247 }
    248 
    249 const char *Process::OutputReverse() {
    250   const WORD attributes
    251    = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
    252 
    253   const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
    254     FOREGROUND_RED | FOREGROUND_INTENSITY;
    255   const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
    256     BACKGROUND_RED | BACKGROUND_INTENSITY;
    257   const WORD color_mask = foreground_mask | background_mask;
    258 
    259   WORD new_attributes =
    260     ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
    261     ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
    262     ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
    263     ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
    264     ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
    265     ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
    266     ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
    267     ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
    268     0;
    269   new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
    270 
    271   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
    272   return 0;
    273 }
    274 
    275 const char *Process::ResetColor() {
    276   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
    277   return 0;
    278 }
    279