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