Process.inc revision 34e1444ebde9516422f08d8ddb4358b11b7e50c1
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.reserve(Size);
165    Size =
166        GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
167    if (Size == 0)
168      return None;
169
170    // Try again with larger buffer.
171  } while (Size > Buf.capacity());
172  Buf.set_size(Size);
173
174  // Convert the result from UTF-16 to UTF-8.
175  SmallVector<char, MAX_PATH> Res;
176  if (error_code ec = windows::UTF16ToUTF8(Buf.data(), Size, Res))
177    return None;
178  return std::string(Res.data());
179}
180
181error_code
182Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
183                           ArrayRef<const char *>,
184                           SpecificBumpPtrAllocator<char> &ArgAllocator) {
185  int NewArgCount;
186  error_code ec;
187
188  wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(),
189                                                    &NewArgCount);
190  if (!UnicodeCommandLine)
191    return windows_error(::GetLastError());
192
193  Args.reserve(NewArgCount);
194
195  for (int i = 0; i < NewArgCount; ++i) {
196    SmallVector<char, MAX_PATH> NewArgString;
197    ec = windows::UTF16ToUTF8(UnicodeCommandLine[i],
198                              wcslen(UnicodeCommandLine[i]),
199                              NewArgString);
200    if (ec)
201      break;
202
203    char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1);
204    ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1);
205    Args.push_back(Buffer);
206  }
207  LocalFree(UnicodeCommandLine);
208  if (ec)
209    return ec;
210
211  return error_code::success();
212}
213
214bool Process::StandardInIsUserInput() {
215  return FileDescriptorIsDisplayed(0);
216}
217
218bool Process::StandardOutIsDisplayed() {
219  return FileDescriptorIsDisplayed(1);
220}
221
222bool Process::StandardErrIsDisplayed() {
223  return FileDescriptorIsDisplayed(2);
224}
225
226bool Process::FileDescriptorIsDisplayed(int fd) {
227  DWORD Mode;  // Unused
228  return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
229}
230
231unsigned Process::StandardOutColumns() {
232  unsigned Columns = 0;
233  CONSOLE_SCREEN_BUFFER_INFO csbi;
234  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
235    Columns = csbi.dwSize.X;
236  return Columns;
237}
238
239unsigned Process::StandardErrColumns() {
240  unsigned Columns = 0;
241  CONSOLE_SCREEN_BUFFER_INFO csbi;
242  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
243    Columns = csbi.dwSize.X;
244  return Columns;
245}
246
247// The terminal always has colors.
248bool Process::FileDescriptorHasColors(int fd) {
249  return FileDescriptorIsDisplayed(fd);
250}
251
252bool Process::StandardOutHasColors() {
253  return FileDescriptorHasColors(1);
254}
255
256bool Process::StandardErrHasColors() {
257  return FileDescriptorHasColors(2);
258}
259
260static bool UseANSI = false;
261void Process::UseANSIEscapeCodes(bool enable) {
262  UseANSI = enable;
263}
264
265namespace {
266class DefaultColors
267{
268  private:
269    WORD defaultColor;
270  public:
271    DefaultColors()
272     :defaultColor(GetCurrentColor()) {}
273    static unsigned GetCurrentColor() {
274      CONSOLE_SCREEN_BUFFER_INFO csbi;
275      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
276        return csbi.wAttributes;
277      return 0;
278    }
279    WORD operator()() const { return defaultColor; }
280};
281
282DefaultColors defaultColors;
283}
284
285bool Process::ColorNeedsFlush() {
286  return !UseANSI;
287}
288
289const char *Process::OutputBold(bool bg) {
290  if (UseANSI) return "\033[1m";
291
292  WORD colors = DefaultColors::GetCurrentColor();
293  if (bg)
294    colors |= BACKGROUND_INTENSITY;
295  else
296    colors |= FOREGROUND_INTENSITY;
297  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
298  return 0;
299}
300
301const char *Process::OutputColor(char code, bool bold, bool bg) {
302  if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
303
304  WORD colors;
305  if (bg) {
306    colors = ((code&1) ? BACKGROUND_RED : 0) |
307      ((code&2) ? BACKGROUND_GREEN : 0 ) |
308      ((code&4) ? BACKGROUND_BLUE : 0);
309    if (bold)
310      colors |= BACKGROUND_INTENSITY;
311  } else {
312    colors = ((code&1) ? FOREGROUND_RED : 0) |
313      ((code&2) ? FOREGROUND_GREEN : 0 ) |
314      ((code&4) ? FOREGROUND_BLUE : 0);
315    if (bold)
316      colors |= FOREGROUND_INTENSITY;
317  }
318  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
319  return 0;
320}
321
322static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
323  CONSOLE_SCREEN_BUFFER_INFO info;
324  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
325  return info.wAttributes;
326}
327
328const char *Process::OutputReverse() {
329  if (UseANSI) return "\033[7m";
330
331  const WORD attributes
332   = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
333
334  const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
335    FOREGROUND_RED | FOREGROUND_INTENSITY;
336  const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
337    BACKGROUND_RED | BACKGROUND_INTENSITY;
338  const WORD color_mask = foreground_mask | background_mask;
339
340  WORD new_attributes =
341    ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
342    ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
343    ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
344    ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
345    ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
346    ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
347    ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
348    ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
349    0;
350  new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
351
352  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
353  return 0;
354}
355
356const char *Process::ResetColor() {
357  if (UseANSI) return "\033[0m";
358  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
359  return 0;
360}
361