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