Try to fix the windows build. The comments in other files don't seem to
[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 <malloc.h>
16
17 // The Windows.h header must be after LLVM and standard headers.
18 #include "Windows.h"
19
20 #include <direct.h>
21 #include <io.h>
22 #include <psapi.h>
23 #include <shellapi.h>
24
25 #ifdef __MINGW32__
26  #if (HAVE_LIBPSAPI != 1)
27   #error "libpsapi.a should be present"
28  #endif
29  #if (HAVE_LIBSHELL32 != 1)
30   #error "libshell32.a should be present"
31  #endif
32 #else
33  #pragma comment(lib, "psapi.lib")
34  #pragma comment(lib, "shell32.lib")
35 #endif
36
37 //===----------------------------------------------------------------------===//
38 //=== WARNING: Implementation here must contain only Win32 specific code
39 //===          and must not be UNIX code
40 //===----------------------------------------------------------------------===//
41
42 #ifdef __MINGW32__
43 // This ban should be lifted when MinGW 1.0+ has defined this value.
44 #  define _HEAPOK (-2)
45 #endif
46
47 using namespace llvm;
48 using namespace sys;
49
50
51 process::id_type self_process::get_id() {
52   return GetCurrentProcessId();
53 }
54
55 static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
56   ULARGE_INTEGER TimeInteger;
57   TimeInteger.LowPart = Time.dwLowDateTime;
58   TimeInteger.HighPart = Time.dwHighDateTime;
59
60   // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
61   return TimeValue(
62       static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000),
63       static_cast<TimeValue::NanoSecondsType>(
64           (TimeInteger.QuadPart % 10000000) * 100));
65 }
66
67 TimeValue self_process::get_user_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(UserTime);
74 }
75
76 TimeValue self_process::get_system_time() const {
77   FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
78   if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
79                       &UserTime) == 0)
80     return TimeValue();
81
82   return getTimeValueFromFILETIME(KernelTime);
83 }
84
85 // This function retrieves the page size using GetSystemInfo and is present
86 // solely so it can be called once to initialize the self_process member below.
87 static unsigned getPageSize() {
88   // NOTE: A 32-bit application running under WOW64 is supposed to use
89   // GetNativeSystemInfo.  However, this interface is not present prior
90   // to Windows XP so to use it requires dynamic linking.  It is not clear
91   // how this affects the reported page size, if at all.  One could argue
92   // that LLVM ought to run as 64-bits on a 64-bit system, anyway.
93   SYSTEM_INFO info;
94   GetSystemInfo(&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 (error_code ec = 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 (error_code ec = windows::UTF16ToUTF8(Buf.data(), Size, Res))
179     return None;
180   return std::string(Res.data());
181 }
182
183 error_code
184 Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
185                            ArrayRef<const char *>,
186                            SpecificBumpPtrAllocator<char> &ArgAllocator) {
187   int NewArgCount;
188   error_code ec;
189
190   wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(),
191                                                     &NewArgCount);
192   if (!UnicodeCommandLine)
193     return windows_error(::GetLastError());
194
195   Args.reserve(NewArgCount);
196
197   for (int i = 0; i < NewArgCount; ++i) {
198     SmallVector<char, MAX_PATH> NewArgString;
199     ec = windows::UTF16ToUTF8(UnicodeCommandLine[i],
200                               wcslen(UnicodeCommandLine[i]),
201                               NewArgString);
202     if (ec)
203       break;
204
205     char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1);
206     ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1);
207     Args.push_back(Buffer);
208   }
209   LocalFree(UnicodeCommandLine);
210   if (ec)
211     return ec;
212
213   return error_code::success();
214 }
215
216 bool Process::StandardInIsUserInput() {
217   return FileDescriptorIsDisplayed(0);
218 }
219
220 bool Process::StandardOutIsDisplayed() {
221   return FileDescriptorIsDisplayed(1);
222 }
223
224 bool Process::StandardErrIsDisplayed() {
225   return FileDescriptorIsDisplayed(2);
226 }
227
228 bool Process::FileDescriptorIsDisplayed(int fd) {
229   DWORD Mode;  // Unused
230   return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
231 }
232
233 unsigned Process::StandardOutColumns() {
234   unsigned Columns = 0;
235   CONSOLE_SCREEN_BUFFER_INFO csbi;
236   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
237     Columns = csbi.dwSize.X;
238   return Columns;
239 }
240
241 unsigned Process::StandardErrColumns() {
242   unsigned Columns = 0;
243   CONSOLE_SCREEN_BUFFER_INFO csbi;
244   if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
245     Columns = csbi.dwSize.X;
246   return Columns;
247 }
248
249 // The terminal always has colors.
250 bool Process::FileDescriptorHasColors(int fd) {
251   return FileDescriptorIsDisplayed(fd);
252 }
253
254 bool Process::StandardOutHasColors() {
255   return FileDescriptorHasColors(1);
256 }
257
258 bool Process::StandardErrHasColors() {
259   return FileDescriptorHasColors(2);
260 }
261
262 static bool UseANSI = false;
263 void Process::UseANSIEscapeCodes(bool enable) {
264   UseANSI = enable;
265 }
266
267 namespace {
268 class DefaultColors
269 {
270   private:
271     WORD defaultColor;
272   public:
273     DefaultColors()
274      :defaultColor(GetCurrentColor()) {}
275     static unsigned GetCurrentColor() {
276       CONSOLE_SCREEN_BUFFER_INFO csbi;
277       if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
278         return csbi.wAttributes;
279       return 0;
280     }
281     WORD operator()() const { return defaultColor; }
282 };
283
284 DefaultColors defaultColors;
285 }
286
287 bool Process::ColorNeedsFlush() {
288   return !UseANSI;
289 }
290
291 const char *Process::OutputBold(bool bg) {
292   if (UseANSI) return "\033[1m";
293
294   WORD colors = DefaultColors::GetCurrentColor();
295   if (bg)
296     colors |= BACKGROUND_INTENSITY;
297   else
298     colors |= FOREGROUND_INTENSITY;
299   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
300   return 0;
301 }
302
303 const char *Process::OutputColor(char code, bool bold, bool bg) {
304   if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
305
306   WORD colors;
307   if (bg) {
308     colors = ((code&1) ? BACKGROUND_RED : 0) |
309       ((code&2) ? BACKGROUND_GREEN : 0 ) |
310       ((code&4) ? BACKGROUND_BLUE : 0);
311     if (bold)
312       colors |= BACKGROUND_INTENSITY;
313   } else {
314     colors = ((code&1) ? FOREGROUND_RED : 0) |
315       ((code&2) ? FOREGROUND_GREEN : 0 ) |
316       ((code&4) ? FOREGROUND_BLUE : 0);
317     if (bold)
318       colors |= FOREGROUND_INTENSITY;
319   }
320   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
321   return 0;
322 }
323
324 static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
325   CONSOLE_SCREEN_BUFFER_INFO info;
326   GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
327   return info.wAttributes;
328 }
329
330 const char *Process::OutputReverse() {
331   if (UseANSI) return "\033[7m";
332
333   const WORD attributes
334    = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
335
336   const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
337     FOREGROUND_RED | FOREGROUND_INTENSITY;
338   const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
339     BACKGROUND_RED | BACKGROUND_INTENSITY;
340   const WORD color_mask = foreground_mask | background_mask;
341
342   WORD new_attributes =
343     ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
344     ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
345     ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
346     ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
347     ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
348     ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
349     ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
350     ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
351     0;
352   new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
353
354   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
355   return 0;
356 }
357
358 const char *Process::ResetColor() {
359   if (UseANSI) return "\033[0m";
360   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
361   return 0;
362 }