1218885Sdim//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the Win32 specific implementation of the Process class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#include "Windows.h"
15249423Sdim#include <direct.h>
16249423Sdim#include <io.h>
17249423Sdim#include <malloc.h>
18218885Sdim#include <psapi.h>
19218885Sdim
20218885Sdim#ifdef __MINGW32__
21218885Sdim #if (HAVE_LIBPSAPI != 1)
22218885Sdim  #error "libpsapi.a should be present"
23218885Sdim #endif
24218885Sdim#else
25218885Sdim #pragma comment(lib, "psapi.lib")
26218885Sdim#endif
27218885Sdim
28218885Sdim//===----------------------------------------------------------------------===//
29218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code
30218885Sdim//===          and must not be UNIX code
31218885Sdim//===----------------------------------------------------------------------===//
32218885Sdim
33218885Sdim#ifdef __MINGW32__
34218885Sdim// This ban should be lifted when MinGW 1.0+ has defined this value.
35218885Sdim#  define _HEAPOK (-2)
36218885Sdim#endif
37218885Sdim
38249423Sdimusing namespace llvm;
39218885Sdimusing namespace sys;
40218885Sdim
41249423Sdim
42249423Sdimprocess::id_type self_process::get_id() {
43249423Sdim  return GetCurrentProcess();
44249423Sdim}
45249423Sdim
46249423Sdimstatic TimeValue getTimeValueFromFILETIME(FILETIME Time) {
47249423Sdim  ULARGE_INTEGER TimeInteger;
48249423Sdim  TimeInteger.LowPart = Time.dwLowDateTime;
49249423Sdim  TimeInteger.HighPart = Time.dwHighDateTime;
50249423Sdim
51249423Sdim  // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
52249423Sdim  return TimeValue(
53249423Sdim      static_cast<TimeValue::SecondsType>(TimeInteger.QuadPart / 10000000),
54249423Sdim      static_cast<TimeValue::NanoSecondsType>(
55249423Sdim          (TimeInteger.QuadPart % 10000000) * 100));
56249423Sdim}
57249423Sdim
58249423SdimTimeValue self_process::get_user_time() const {
59249423Sdim  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
60249423Sdim  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
61249423Sdim                      &UserTime) == 0)
62249423Sdim    return TimeValue();
63249423Sdim
64249423Sdim  return getTimeValueFromFILETIME(UserTime);
65249423Sdim}
66249423Sdim
67249423SdimTimeValue self_process::get_system_time() const {
68249423Sdim  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
69249423Sdim  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
70249423Sdim                      &UserTime) == 0)
71249423Sdim    return TimeValue();
72249423Sdim
73249423Sdim  return getTimeValueFromFILETIME(KernelTime);
74249423Sdim}
75249423Sdim
76218885Sdim// This function retrieves the page size using GetSystemInfo and is present
77249423Sdim// solely so it can be called once to initialize the self_process member below.
78249423Sdimstatic unsigned getPageSize() {
79218885Sdim  // NOTE: A 32-bit application running under WOW64 is supposed to use
80218885Sdim  // GetNativeSystemInfo.  However, this interface is not present prior
81218885Sdim  // to Windows XP so to use it requires dynamic linking.  It is not clear
82218885Sdim  // how this affects the reported page size, if at all.  One could argue
83218885Sdim  // that LLVM ought to run as 64-bits on a 64-bit system, anyway.
84218885Sdim  SYSTEM_INFO info;
85218885Sdim  GetSystemInfo(&info);
86218885Sdim  return static_cast<unsigned>(info.dwPageSize);
87218885Sdim}
88218885Sdim
89249423Sdim// This constructor guaranteed to be run exactly once on a single thread, and
90249423Sdim// sets up various process invariants that can be queried cheaply from then on.
91249423Sdimself_process::self_process() : PageSize(getPageSize()) {
92218885Sdim}
93218885Sdim
94249423Sdim
95218885Sdimsize_t
96218885SdimProcess::GetMallocUsage()
97218885Sdim{
98218885Sdim  _HEAPINFO hinfo;
99218885Sdim  hinfo._pentry = NULL;
100218885Sdim
101218885Sdim  size_t size = 0;
102218885Sdim
103218885Sdim  while (_heapwalk(&hinfo) == _HEAPOK)
104218885Sdim    size += hinfo._size;
105218885Sdim
106218885Sdim  return size;
107218885Sdim}
108218885Sdim
109249423Sdimvoid Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
110249423Sdim                           TimeValue &sys_time) {
111218885Sdim  elapsed = TimeValue::now();
112218885Sdim
113249423Sdim  FILETIME ProcCreate, ProcExit, KernelTime, UserTime;
114249423Sdim  if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime,
115249423Sdim                      &UserTime) == 0)
116249423Sdim    return;
117218885Sdim
118249423Sdim  user_time = getTimeValueFromFILETIME(UserTime);
119249423Sdim  sys_time = getTimeValueFromFILETIME(KernelTime);
120218885Sdim}
121218885Sdim
122218885Sdimint Process::GetCurrentUserId()
123218885Sdim{
124218885Sdim  return 65536;
125218885Sdim}
126218885Sdim
127218885Sdimint Process::GetCurrentGroupId()
128218885Sdim{
129218885Sdim  return 65536;
130218885Sdim}
131218885Sdim
132218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of
133218885Sdim// their operation. To prevent the disk from filling up, this configuration item
134218885Sdim// does what's necessary to prevent their generation.
135218885Sdimvoid Process::PreventCoreFiles() {
136218885Sdim  // Windows doesn't do core files, but it does do modal pop-up message
137218885Sdim  // boxes.  As this method is used by bugpoint, preventing these pop-ups
138218885Sdim  // is the moral equivalent of suppressing core files.
139218885Sdim  SetErrorMode(SEM_FAILCRITICALERRORS |
140218885Sdim               SEM_NOGPFAULTERRORBOX |
141218885Sdim               SEM_NOOPENFILEERRORBOX);
142218885Sdim}
143218885Sdim
144218885Sdimbool Process::StandardInIsUserInput() {
145218885Sdim  return FileDescriptorIsDisplayed(0);
146218885Sdim}
147218885Sdim
148218885Sdimbool Process::StandardOutIsDisplayed() {
149218885Sdim  return FileDescriptorIsDisplayed(1);
150218885Sdim}
151218885Sdim
152218885Sdimbool Process::StandardErrIsDisplayed() {
153218885Sdim  return FileDescriptorIsDisplayed(2);
154218885Sdim}
155218885Sdim
156218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) {
157239462Sdim  DWORD Mode;  // Unused
158218885Sdim  return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0);
159218885Sdim}
160218885Sdim
161218885Sdimunsigned Process::StandardOutColumns() {
162218885Sdim  unsigned Columns = 0;
163218885Sdim  CONSOLE_SCREEN_BUFFER_INFO csbi;
164218885Sdim  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
165218885Sdim    Columns = csbi.dwSize.X;
166218885Sdim  return Columns;
167218885Sdim}
168218885Sdim
169218885Sdimunsigned Process::StandardErrColumns() {
170218885Sdim  unsigned Columns = 0;
171218885Sdim  CONSOLE_SCREEN_BUFFER_INFO csbi;
172218885Sdim  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi))
173218885Sdim    Columns = csbi.dwSize.X;
174218885Sdim  return Columns;
175218885Sdim}
176218885Sdim
177239462Sdim// The terminal always has colors.
178239462Sdimbool Process::FileDescriptorHasColors(int fd) {
179239462Sdim  return FileDescriptorIsDisplayed(fd);
180218885Sdim}
181218885Sdim
182218885Sdimbool Process::StandardOutHasColors() {
183239462Sdim  return FileDescriptorHasColors(1);
184218885Sdim}
185218885Sdim
186239462Sdimbool Process::StandardErrHasColors() {
187239462Sdim  return FileDescriptorHasColors(2);
188239462Sdim}
189239462Sdim
190218885Sdimnamespace {
191218885Sdimclass DefaultColors
192218885Sdim{
193218885Sdim  private:
194218885Sdim    WORD defaultColor;
195218885Sdim  public:
196218885Sdim    DefaultColors()
197218885Sdim     :defaultColor(GetCurrentColor()) {}
198218885Sdim    static unsigned GetCurrentColor() {
199218885Sdim      CONSOLE_SCREEN_BUFFER_INFO csbi;
200218885Sdim      if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
201218885Sdim        return csbi.wAttributes;
202218885Sdim      return 0;
203218885Sdim    }
204218885Sdim    WORD operator()() const { return defaultColor; }
205218885Sdim};
206218885Sdim
207218885SdimDefaultColors defaultColors;
208218885Sdim}
209218885Sdim
210218885Sdimbool Process::ColorNeedsFlush() {
211218885Sdim  return true;
212218885Sdim}
213218885Sdim
214218885Sdimconst char *Process::OutputBold(bool bg) {
215218885Sdim  WORD colors = DefaultColors::GetCurrentColor();
216218885Sdim  if (bg)
217218885Sdim    colors |= BACKGROUND_INTENSITY;
218218885Sdim  else
219218885Sdim    colors |= FOREGROUND_INTENSITY;
220218885Sdim  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
221218885Sdim  return 0;
222218885Sdim}
223218885Sdim
224218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) {
225218885Sdim  WORD colors;
226218885Sdim  if (bg) {
227218885Sdim    colors = ((code&1) ? BACKGROUND_RED : 0) |
228218885Sdim      ((code&2) ? BACKGROUND_GREEN : 0 ) |
229218885Sdim      ((code&4) ? BACKGROUND_BLUE : 0);
230218885Sdim    if (bold)
231218885Sdim      colors |= BACKGROUND_INTENSITY;
232218885Sdim  } else {
233218885Sdim    colors = ((code&1) ? FOREGROUND_RED : 0) |
234218885Sdim      ((code&2) ? FOREGROUND_GREEN : 0 ) |
235218885Sdim      ((code&4) ? FOREGROUND_BLUE : 0);
236218885Sdim    if (bold)
237218885Sdim      colors |= FOREGROUND_INTENSITY;
238218885Sdim  }
239218885Sdim  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors);
240218885Sdim  return 0;
241218885Sdim}
242218885Sdim
243234982Sdimstatic WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
244234982Sdim  CONSOLE_SCREEN_BUFFER_INFO info;
245234982Sdim  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
246234982Sdim  return info.wAttributes;
247234982Sdim}
248234982Sdim
249234982Sdimconst char *Process::OutputReverse() {
250234982Sdim  const WORD attributes
251234982Sdim   = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
252234982Sdim
253234982Sdim  const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
254234982Sdim    FOREGROUND_RED | FOREGROUND_INTENSITY;
255234982Sdim  const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
256234982Sdim    BACKGROUND_RED | BACKGROUND_INTENSITY;
257234982Sdim  const WORD color_mask = foreground_mask | background_mask;
258234982Sdim
259234982Sdim  WORD new_attributes =
260234982Sdim    ((attributes & FOREGROUND_BLUE     )?BACKGROUND_BLUE     :0) |
261234982Sdim    ((attributes & FOREGROUND_GREEN    )?BACKGROUND_GREEN    :0) |
262234982Sdim    ((attributes & FOREGROUND_RED      )?BACKGROUND_RED      :0) |
263234982Sdim    ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) |
264234982Sdim    ((attributes & BACKGROUND_BLUE     )?FOREGROUND_BLUE     :0) |
265234982Sdim    ((attributes & BACKGROUND_GREEN    )?FOREGROUND_GREEN    :0) |
266234982Sdim    ((attributes & BACKGROUND_RED      )?FOREGROUND_RED      :0) |
267234982Sdim    ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) |
268234982Sdim    0;
269234982Sdim  new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask);
270234982Sdim
271234982Sdim  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes);
272234982Sdim  return 0;
273234982Sdim}
274234982Sdim
275218885Sdimconst char *Process::ResetColor() {
276218885Sdim  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
277218885Sdim  return 0;
278218885Sdim}
279