Process.inc revision 44a61bde15d456527156ee2080f0964344b939fe
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
38using namespace llvm;
39using namespace sys;
40
41
42process::id_type self_process::get_id() {
43  return GetCurrentProcessId();
44}
45
46static 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
58TimeValue 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
67TimeValue 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.
78static 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  // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
87  // but dwAllocationGranularity.
88  return static_cast<unsigned>(info.dwPageSize);
89}
90
91// This constructor guaranteed to be run exactly once on a single thread, and
92// sets up various process invariants that can be queried cheaply from then on.
93self_process::self_process() : PageSize(getPageSize()) {
94}
95
96
97size_t
98Process::GetMallocUsage()
99{
100  _HEAPINFO hinfo;
101  hinfo._pentry = NULL;
102
103  size_t size = 0;
104
105  while (_heapwalk(&hinfo) == _HEAPOK)
106    size += hinfo._size;
107
108  return size;
109}
110
111void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
112                           TimeValue &sys_time) {
113  elapsed = TimeValue::now();
114
115  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
116  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
117                      &UserTime) == 0)
118    return;
119
120  user_time = getTimeValueFromFILETIME(UserTime);
121  sys_time = getTimeValueFromFILETIME(KernelTime);
122}
123
124// Some LLVM programs such as bugpoint produce core files as a normal part of
125// their operation. To prevent the disk from filling up, this configuration
126// item does what's necessary to prevent their generation.
127void Process::PreventCoreFiles() {
128  // Windows does have the concept of core files, called minidumps.  However,
129  // disabling minidumps for a particular application extends past the lifetime
130  // of that application, which is the incorrect behavior for this API.
131  // Additionally, the APIs require elevated privileges to disable and re-
132  // enable minidumps, which makes this untenable. For more information, see
133  // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
134  // later).
135  //
136  // Windows also has modal pop-up message boxes.  As this method is used by
137  // bugpoint, preventing these pop-ups is additionally important.
138  SetErrorMode(SEM_FAILCRITICALERRORS |
139               SEM_NOGPFAULTERRORBOX |
140               SEM_NOOPENFILEERRORBOX);
141}
142
143/// Returns the environment variable \arg Name's value as a string encoded in
144/// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
145Optional Process::GetEnv(StringRef Name) {
146  // Convert the argument to UTF-16 to pass it to _wgetenv().
147  SmallVector<wchar_t, 128> NameUTF16;
148  if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16))
149    return None;
150
151  // Environment variable can be encoded in non-UTF8 encoding, and there's no
152  // way to know what the encoding is. The only reliable way to look up
153  // multibyte environment variable is to use GetEnvironmentVariableW().
154  std::vector<wchar_t> Buf(16);
155  size_t Size = 0;
156  for (;;) {
157    Size = GetEnvironmentVariableW(&NameUTF16[0], &Buf[0], Buf.size());
158    if (Size < Buf.size())
159      break;
160    // Try again with larger buffer.
161    Buf.resize(Size + 1);
162  }
163  if (Size == 0)
164    return None;
165
166  // Convert the result from UTF-16 to UTF-8.
167  SmallVector<char, 128> Res;
168  if (error_code ec = windows::UTF16ToUTF8(&Buf[0], Size, Res))
169    return None;
170  return std::string(&Res[0]);
171}
172
173bool Process::StandardInIsUserInput() {
174  return FileDescriptorIsDisplayed(0);
175}
176
177bool Process::StandardOutIsDisplayed() {
178  return FileDescriptorIsDisplayed(1);
179}
180
181bool Process::StandardErrIsDisplayed() {
182  return FileDescriptorIsDisplayed(2);
183}
184
185bool Process::FileDescriptorIsDisplayed(int fd) {
186  DWORD Mode;  // Unused
187  return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
188}
189
190unsigned Process::StandardOutColumns() {
191  unsigned Columns = 0;
192  CONSOLE_SCREEN_BUFFER_INFO csbi;
193  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
194    Columns = csbi.dwSize.X;
195  return Columns;
196}
197
198unsigned Process::StandardErrColumns() {
199  unsigned Columns = 0;
200  CONSOLE_SCREEN_BUFFER_INFO csbi;
201  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
202    Columns = csbi.dwSize.X;
203  return Columns;
204}
205
206// The terminal always has colors.
207bool Process::FileDescriptorHasColors(int fd) {
208  return FileDescriptorIsDisplayed(fd);
209}
210
211bool Process::StandardOutHasColors() {
212  return FileDescriptorHasColors(1);
213}
214
215bool Process::StandardErrHasColors() {
216  return FileDescriptorHasColors(2);
217}
218
219static bool UseANSI = false;
220void Process::UseANSIEscapeCodes(bool enable) {
221  UseANSI = enable;
222}
223
224namespace {
225class DefaultColors
226{
227  private:
228    WORD defaultColor;
229  public:
230    DefaultColors()
231     :defaultColor(GetCurrentColor()) {}
232    static unsigned GetCurrentColor() {
233      CONSOLE_SCREEN_BUFFER_INFO csbi;
234      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
235        return csbi.wAttributes;
236      return 0;
237    }
238    WORD operator()() const { return defaultColor; }
239};
240
241DefaultColors defaultColors;
242}
243
244bool Process::ColorNeedsFlush() {
245  return !UseANSI;
246}
247
248const char *Process::OutputBold(bool bg) {
249  if (UseANSI) return "\033[1m";
250
251  WORD colors = DefaultColors::GetCurrentColor();
252  if (bg)
253    colors |= BACKGROUND_INTENSITY;
254  else
255    colors |= FOREGROUND_INTENSITY;
256  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
257  return 0;
258}
259
260const char *Process::OutputColor(char code, bool bold, bool bg) {
261  if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
262
263  WORD colors;
264  if (bg) {
265    colors = ((code&1) ? BACKGROUND_RED : 0) |
266      ((code&2) ? BACKGROUND_GREEN : 0 ) |
267      ((code&4) ? BACKGROUND_BLUE : 0);
268    if (bold)
269      colors |= BACKGROUND_INTENSITY;
270  } else {
271    colors = ((code&1) ? FOREGROUND_RED : 0) |
272      ((code&2) ? FOREGROUND_GREEN : 0 ) |
273      ((code&4) ? FOREGROUND_BLUE : 0);
274    if (bold)
275      colors |= FOREGROUND_INTENSITY;
276  }
277  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
278  return 0;
279}
280
281static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
282  CONSOLE_SCREEN_BUFFER_INFO info;
283  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
284  return info.wAttributes;
285}
286
287const char *Process::OutputReverse() {
288  if (UseANSI) return "\033[7m";
289
290  const WORD attributes
291   = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
292
293  const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
294    FOREGROUND_RED | FOREGROUND_INTENSITY;
295  const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
296    BACKGROUND_RED | BACKGROUND_INTENSITY;
297  const WORD color_mask = foreground_mask | background_mask;
298
299  WORD new_attributes =
300    ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
301    ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
302    ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
303    ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
304    ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
305    ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
306    ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
307    ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
308    0;
309  new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
310
311  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
312  return 0;
313}
314
315const char *Process::ResetColor() {
316  if (UseANSI) return "\033[0m";
317  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
318  return 0;
319}
320