Process.inc revision f42d4247ae1138c6deed50f92dcd1a4f34e07dec
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
219namespace {
220class DefaultColors
221{
222  private:
223    WORD defaultColor;
224  public:
225    DefaultColors()
226     :defaultColor(GetCurrentColor()) {}
227    static unsigned GetCurrentColor() {
228      CONSOLE_SCREEN_BUFFER_INFO csbi;
229      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
230        return csbi.wAttributes;
231      return 0;
232    }
233    WORD operator()() const { return defaultColor; }
234};
235
236DefaultColors defaultColors;
237}
238
239bool Process::ColorNeedsFlush() {
240  return true;
241}
242
243const char *Process::OutputBold(bool bg) {
244  WORD colors = DefaultColors::GetCurrentColor();
245  if (bg)
246    colors |= BACKGROUND_INTENSITY;
247  else
248    colors |= FOREGROUND_INTENSITY;
249  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
250  return 0;
251}
252
253const char *Process::OutputColor(char code, bool bold, bool bg) {
254  WORD colors;
255  if (bg) {
256    colors = ((code&1) ? BACKGROUND_RED : 0) |
257      ((code&2) ? BACKGROUND_GREEN : 0 ) |
258      ((code&4) ? BACKGROUND_BLUE : 0);
259    if (bold)
260      colors |= BACKGROUND_INTENSITY;
261  } else {
262    colors = ((code&1) ? FOREGROUND_RED : 0) |
263      ((code&2) ? FOREGROUND_GREEN : 0 ) |
264      ((code&4) ? FOREGROUND_BLUE : 0);
265    if (bold)
266      colors |= FOREGROUND_INTENSITY;
267  }
268  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
269  return 0;
270}
271
272static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
273  CONSOLE_SCREEN_BUFFER_INFO info;
274  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
275  return info.wAttributes;
276}
277
278const char *Process::OutputReverse() {
279  const WORD attributes
280   = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
281
282  const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
283    FOREGROUND_RED | FOREGROUND_INTENSITY;
284  const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
285    BACKGROUND_RED | BACKGROUND_INTENSITY;
286  const WORD color_mask = foreground_mask | background_mask;
287
288  WORD new_attributes =
289    ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
290    ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
291    ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
292    ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
293    ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
294    ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
295    ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
296    ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
297    0;
298  new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
299
300  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
301  return 0;
302}
303
304const char *Process::ResetColor() {
305  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
306  return 0;
307}
308