process_util_win.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process_util.h"
6
7#include <fcntl.h>
8#include <io.h>
9#include <windows.h>
10#include <userenv.h>
11#include <psapi.h>
12
13#include <ios>
14
15#include "base/debug_util.h"
16#include "base/histogram.h"
17#include "base/logging.h"
18#include "base/scoped_handle_win.h"
19#include "base/scoped_ptr.h"
20
21// userenv.dll is required for CreateEnvironmentBlock().
22#pragma comment(lib, "userenv.lib")
23
24namespace base {
25
26namespace {
27
28// System pagesize. This value remains constant on x86/64 architectures.
29const int PAGESIZE_KB = 4;
30
31// HeapSetInformation function pointer.
32typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
33
34// Previous unhandled filter. Will be called if not NULL when we intercept an
35// exception. Only used in unit tests.
36LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
37
38// Prints the exception call stack.
39// This is the unit tests exception filter.
40long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
41  StackTrace(info).PrintBacktrace();
42  if (g_previous_filter)
43    return g_previous_filter(info);
44  return EXCEPTION_CONTINUE_SEARCH;
45}
46
47// Connects back to a console if available.
48// Only necessary on Windows, no-op on other platforms.
49void AttachToConsole() {
50  if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
51    unsigned int result = GetLastError();
52    // Was probably already attached.
53    if (result == ERROR_ACCESS_DENIED)
54      return;
55
56    if (result == ERROR_INVALID_HANDLE || result == ERROR_INVALID_HANDLE) {
57      // TODO(maruel): Walk up the process chain if deemed necessary.
58    }
59    // Continue even if the function call fails.
60    AllocConsole();
61  }
62  // http://support.microsoft.com/kb/105305
63  int raw_out = _open_osfhandle(
64      reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE)), _O_TEXT);
65  *stdout = *_fdopen(raw_out, "w");
66  setvbuf(stdout, NULL, _IONBF, 0);
67
68  int raw_err = _open_osfhandle(
69      reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE)), _O_TEXT);
70  *stderr = *_fdopen(raw_err, "w");
71  setvbuf(stderr, NULL, _IONBF, 0);
72
73  int raw_in = _open_osfhandle(
74      reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE)), _O_TEXT);
75  *stdin = *_fdopen(raw_in, "r");
76  setvbuf(stdin, NULL, _IONBF, 0);
77  // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
78  std::ios::sync_with_stdio();
79}
80
81}  // namespace
82
83ProcessId GetCurrentProcId() {
84  return ::GetCurrentProcessId();
85}
86
87ProcessHandle GetCurrentProcessHandle() {
88  return ::GetCurrentProcess();
89}
90
91bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
92  // We try to limit privileges granted to the handle. If you need this
93  // for test code, consider using OpenPrivilegedProcessHandle instead of
94  // adding more privileges here.
95  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_TERMINATE,
96                                     FALSE, pid);
97
98  if (result == INVALID_HANDLE_VALUE)
99    return false;
100
101  *handle = result;
102  return true;
103}
104
105bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
106  ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
107                                         PROCESS_TERMINATE |
108                                         PROCESS_QUERY_INFORMATION |
109                                         PROCESS_VM_READ |
110                                         SYNCHRONIZE,
111                                     FALSE, pid);
112
113  if (result == INVALID_HANDLE_VALUE)
114    return false;
115
116  *handle = result;
117  return true;
118}
119
120void CloseProcessHandle(ProcessHandle process) {
121  CloseHandle(process);
122}
123
124ProcessId GetProcId(ProcessHandle process) {
125  // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
126  HANDLE current_process = GetCurrentProcess();
127  HANDLE process_with_query_rights;
128  if (DuplicateHandle(current_process, process, current_process,
129                      &process_with_query_rights, PROCESS_QUERY_INFORMATION,
130                      false, 0)) {
131    DWORD id = GetProcessId(process_with_query_rights);
132    CloseHandle(process_with_query_rights);
133    return id;
134  }
135
136  // We're screwed.
137  NOTREACHED();
138  return 0;
139}
140
141bool LaunchApp(const std::wstring& cmdline,
142               bool wait, bool start_hidden, ProcessHandle* process_handle) {
143  STARTUPINFO startup_info = {0};
144  startup_info.cb = sizeof(startup_info);
145  startup_info.dwFlags = STARTF_USESHOWWINDOW;
146  startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
147  PROCESS_INFORMATION process_info;
148  if (!CreateProcess(NULL,
149                     const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
150                     FALSE, 0, NULL, NULL,
151                     &startup_info, &process_info))
152    return false;
153
154  // Handles must be closed or they will leak
155  CloseHandle(process_info.hThread);
156
157  if (wait)
158    WaitForSingleObject(process_info.hProcess, INFINITE);
159
160  // If the caller wants the process handle, we won't close it.
161  if (process_handle) {
162    *process_handle = process_info.hProcess;
163  } else {
164    CloseHandle(process_info.hProcess);
165  }
166  return true;
167}
168
169
170bool LaunchAppAsUser(UserTokenHandle token, const std::wstring& cmdline,
171                     bool start_hidden, ProcessHandle* process_handle) {
172  STARTUPINFO startup_info = {0};
173  startup_info.cb = sizeof(startup_info);
174  PROCESS_INFORMATION process_info;
175  if (start_hidden) {
176    startup_info.dwFlags = STARTF_USESHOWWINDOW;
177    startup_info.wShowWindow = SW_HIDE;
178  }
179  DWORD flags = CREATE_UNICODE_ENVIRONMENT;
180  void* enviroment_block = NULL;
181
182  if(!CreateEnvironmentBlock(&enviroment_block, token, FALSE))
183    return false;
184
185  BOOL launched =
186      CreateProcessAsUser(token, NULL, const_cast<wchar_t*>(cmdline.c_str()),
187                          NULL, NULL, FALSE, flags, enviroment_block,
188                          NULL, &startup_info, &process_info);
189
190  DestroyEnvironmentBlock(enviroment_block);
191
192  if (!launched)
193    return false;
194
195  CloseHandle(process_info.hThread);
196
197  if (process_handle) {
198    *process_handle = process_info.hProcess;
199  } else {
200    CloseHandle(process_info.hProcess);
201  }
202  return true;
203}
204
205bool LaunchApp(const CommandLine& cl,
206               bool wait, bool start_hidden, ProcessHandle* process_handle) {
207  return LaunchApp(cl.command_line_string(), wait,
208                   start_hidden, process_handle);
209}
210
211// Attempts to kill the process identified by the given process
212// entry structure, giving it the specified exit code.
213// Returns true if this is successful, false otherwise.
214bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
215  HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
216                               FALSE,  // Don't inherit handle
217                               process_id);
218  if (!process)
219    return false;
220
221  bool ret = KillProcess(process, exit_code, wait);
222  CloseHandle(process);
223  return ret;
224}
225
226bool GetAppOutput(const CommandLine& cl, std::string* output) {
227  HANDLE out_read = NULL;
228  HANDLE out_write = NULL;
229
230  SECURITY_ATTRIBUTES sa_attr;
231  // Set the bInheritHandle flag so pipe handles are inherited.
232  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
233  sa_attr.bInheritHandle = TRUE;
234  sa_attr.lpSecurityDescriptor = NULL;
235
236  // Create the pipe for the child process's STDOUT.
237  if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
238    NOTREACHED() << "Failed to create pipe";
239    return false;
240  }
241
242  // Ensure we don't leak the handles.
243  ScopedHandle scoped_out_read(out_read);
244  ScopedHandle scoped_out_write(out_write);
245
246  // Ensure the read handle to the pipe for STDOUT is not inherited.
247  if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
248    NOTREACHED() << "Failed to disabled pipe inheritance";
249    return false;
250  }
251
252  // Now create the child process
253  PROCESS_INFORMATION proc_info = { 0 };
254  STARTUPINFO start_info = { 0 };
255
256  start_info.cb = sizeof(STARTUPINFO);
257  start_info.hStdOutput = out_write;
258  // Keep the normal stdin and stderr.
259  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
260  start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
261  start_info.dwFlags |= STARTF_USESTDHANDLES;
262
263  // Create the child process.
264  if (!CreateProcess(NULL,
265                     const_cast<wchar_t*>(cl.command_line_string().c_str()),
266                     NULL, NULL,
267                     TRUE,  // Handles are inherited.
268                     0, NULL, NULL, &start_info, &proc_info)) {
269    NOTREACHED() << "Failed to start process";
270    return false;
271  }
272
273  // We don't need the thread handle, close it now.
274  CloseHandle(proc_info.hThread);
275
276  // Close our writing end of pipe now. Otherwise later read would not be able
277  // to detect end of child's output.
278  scoped_out_write.Close();
279
280  // Read output from the child process's pipe for STDOUT
281  const int kBufferSize = 1024;
282  char buffer[kBufferSize];
283
284  for (;;) {
285    DWORD bytes_read = 0;
286    BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
287    if (!success || bytes_read == 0)
288      break;
289    output->append(buffer, bytes_read);
290  }
291
292  // Let's wait for the process to finish.
293  WaitForSingleObject(proc_info.hProcess, INFINITE);
294  CloseHandle(proc_info.hProcess);
295
296  return true;
297}
298
299bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
300  bool result = (TerminateProcess(process, exit_code) != FALSE);
301  if (result && wait) {
302    // The process may not end immediately due to pending I/O
303    if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
304      DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
305  } else if (!result) {
306    DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
307  }
308  return result;
309}
310
311bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
312  DWORD exitcode = 0;
313
314  if (child_exited)
315    *child_exited = true;  // On Windows it an error to call this function if
316                           // the child hasn't already exited.
317  if (!::GetExitCodeProcess(handle, &exitcode)) {
318    NOTREACHED();
319    return false;
320  }
321  if (exitcode == STILL_ACTIVE) {
322    // The process is likely not dead or it used 0x103 as exit code.
323    NOTREACHED();
324    return false;
325  }
326
327  // Warning, this is not generic code; it heavily depends on the way
328  // the rest of the code kills a process.
329
330  if (exitcode == PROCESS_END_NORMAL_TERMINATON ||
331      exitcode == PROCESS_END_KILLED_BY_USER ||
332      exitcode == PROCESS_END_PROCESS_WAS_HUNG ||
333      exitcode == 0xC0000354 ||     // STATUS_DEBUGGER_INACTIVE.
334      exitcode == 0xC000013A ||     // Control-C/end session.
335      exitcode == 0x40010004) {     // Debugger terminated process/end session.
336    return false;
337  }
338
339  // All other exit codes indicate crashes.
340  return true;
341}
342
343bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
344  ScopedHandle closer(handle);  // Ensure that we always close the handle.
345  if (::WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0) {
346    NOTREACHED();
347    return false;
348  }
349  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
350  if (!::GetExitCodeProcess(handle, &temp_code))
351    return false;
352  *exit_code = temp_code;
353  return true;
354}
355
356NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
357                                           const ProcessFilter* filter)
358    : started_iteration_(false),
359      executable_name_(executable_name),
360      filter_(filter) {
361  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
362}
363
364NamedProcessIterator::~NamedProcessIterator() {
365  CloseHandle(snapshot_);
366}
367
368
369const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
370  bool result = false;
371  do {
372    result = CheckForNextProcess();
373  } while (result && !IncludeEntry());
374
375  if (result) {
376    return &entry_;
377  }
378
379  return NULL;
380}
381
382bool NamedProcessIterator::CheckForNextProcess() {
383  InitProcessEntry(&entry_);
384
385  if (!started_iteration_) {
386    started_iteration_ = true;
387    return !!Process32First(snapshot_, &entry_);
388  }
389
390  return !!Process32Next(snapshot_, &entry_);
391}
392
393bool NamedProcessIterator::IncludeEntry() {
394  return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 &&
395                  (!filter_ || filter_->Includes(entry_.th32ProcessID,
396                                                 entry_.th32ParentProcessID));
397}
398
399void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) {
400  memset(entry, 0, sizeof(*entry));
401  entry->dwSize = sizeof(*entry);
402}
403
404int GetProcessCount(const std::wstring& executable_name,
405                    const ProcessFilter* filter) {
406  int count = 0;
407
408  NamedProcessIterator iter(executable_name, filter);
409  while (iter.NextProcessEntry())
410    ++count;
411  return count;
412}
413
414bool KillProcesses(const std::wstring& executable_name, int exit_code,
415                   const ProcessFilter* filter) {
416  bool result = true;
417  const ProcessEntry* entry;
418
419  NamedProcessIterator iter(executable_name, filter);
420  while (entry = iter.NextProcessEntry()) {
421    if (!KillProcessById((*entry).th32ProcessID, exit_code, true))
422      result = false;
423  }
424
425  return result;
426}
427
428bool WaitForProcessesToExit(const std::wstring& executable_name,
429                            int64 wait_milliseconds,
430                            const ProcessFilter* filter) {
431  const ProcessEntry* entry;
432  bool result = true;
433  DWORD start_time = GetTickCount();
434
435  NamedProcessIterator iter(executable_name, filter);
436  while (entry = iter.NextProcessEntry()) {
437    DWORD remaining_wait =
438        std::max<int64>(0, wait_milliseconds - (GetTickCount() - start_time));
439    HANDLE process = OpenProcess(SYNCHRONIZE,
440                                 FALSE,
441                                 entry->th32ProcessID);
442    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
443    CloseHandle(process);
444    result = result && (wait_result == WAIT_OBJECT_0);
445  }
446
447  return result;
448}
449
450bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
451  bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_OBJECT_0;
452  return retval;
453}
454
455bool CrashAwareSleep(ProcessHandle handle, int64 wait_milliseconds) {
456  bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_TIMEOUT;
457  return retval;
458}
459
460bool CleanupProcesses(const std::wstring& executable_name,
461                      int64 wait_milliseconds,
462                      int exit_code,
463                      const ProcessFilter* filter) {
464  bool exited_cleanly = WaitForProcessesToExit(executable_name,
465                                               wait_milliseconds,
466                                               filter);
467  if (!exited_cleanly)
468    KillProcesses(executable_name, exit_code, filter);
469  return exited_cleanly;
470}
471
472///////////////////////////////////////////////////////////////////////////////
473// ProcesMetrics
474
475ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
476                                                        last_time_(0),
477                                                        last_system_time_(0) {
478  SYSTEM_INFO system_info;
479  GetSystemInfo(&system_info);
480  processor_count_ = system_info.dwNumberOfProcessors;
481}
482
483// static
484ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
485  return new ProcessMetrics(process);
486}
487
488ProcessMetrics::~ProcessMetrics() { }
489
490size_t ProcessMetrics::GetPagefileUsage() const {
491  PROCESS_MEMORY_COUNTERS pmc;
492  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
493    return pmc.PagefileUsage;
494  }
495  return 0;
496}
497
498// Returns the peak space allocated for the pagefile, in bytes.
499size_t ProcessMetrics::GetPeakPagefileUsage() const {
500  PROCESS_MEMORY_COUNTERS pmc;
501  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
502    return pmc.PeakPagefileUsage;
503  }
504  return 0;
505}
506
507// Returns the current working set size, in bytes.
508size_t ProcessMetrics::GetWorkingSetSize() const {
509  PROCESS_MEMORY_COUNTERS pmc;
510  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
511    return pmc.WorkingSetSize;
512  }
513  return 0;
514}
515
516// Returns the peak working set size, in bytes.
517size_t ProcessMetrics::GetPeakWorkingSetSize() const {
518  PROCESS_MEMORY_COUNTERS pmc;
519  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
520    return pmc.PeakWorkingSetSize;
521  }
522  return 0;
523}
524
525size_t ProcessMetrics::GetPrivateBytes() const {
526  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
527  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
528  // information is simply not available. Hence, we will return 0 on unsupported
529  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
530  PROCESS_MEMORY_COUNTERS_EX pmcx;
531  if (GetProcessMemoryInfo(process_,
532                          reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
533                          sizeof(pmcx))) {
534      return pmcx.PrivateUsage;
535  }
536  return 0;
537}
538
539void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
540  MEMORY_BASIC_INFORMATION mbi = {0};
541  size_t committed_private = 0;
542  size_t committed_mapped = 0;
543  size_t committed_image = 0;
544  void* base_address = NULL;
545  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
546      sizeof(mbi)) {
547    if (mbi.State == MEM_COMMIT) {
548      if (mbi.Type == MEM_PRIVATE) {
549        committed_private += mbi.RegionSize;
550      } else if (mbi.Type == MEM_MAPPED) {
551        committed_mapped += mbi.RegionSize;
552      } else if (mbi.Type == MEM_IMAGE) {
553        committed_image += mbi.RegionSize;
554      } else {
555        NOTREACHED();
556      }
557    }
558    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
559    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
560    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
561    // returns such data.
562    if (new_base <= base_address) {
563      usage->image = 0;
564      usage->mapped = 0;
565      usage->priv = 0;
566      return;
567    }
568    base_address = new_base;
569  }
570  usage->image = committed_image / 1024;
571  usage->mapped = committed_mapped / 1024;
572  usage->priv = committed_private / 1024;
573}
574
575bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
576  size_t ws_private = 0;
577  size_t ws_shareable = 0;
578  size_t ws_shared = 0;
579
580  DCHECK(ws_usage);
581  memset(ws_usage, 0, sizeof(*ws_usage));
582
583  DWORD number_of_entries = 4096;  // Just a guess.
584  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
585  int retries = 5;
586  for (;;) {
587    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
588                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
589
590    // if we can't expand the buffer, don't leak the previous
591    // contents or pass a NULL pointer to QueryWorkingSet
592    PSAPI_WORKING_SET_INFORMATION* new_buffer =
593        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
594            realloc(buffer, buffer_size));
595    if (!new_buffer) {
596      free(buffer);
597      return false;
598    }
599    buffer = new_buffer;
600
601    // Call the function once to get number of items
602    if (QueryWorkingSet(process_, buffer, buffer_size))
603      break;  // Success
604
605    if (GetLastError() != ERROR_BAD_LENGTH) {
606      free(buffer);
607      return false;
608    }
609
610    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
611
612    // Maybe some entries are being added right now. Increase the buffer to
613    // take that into account.
614    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
615
616    if (--retries == 0) {
617      free(buffer);  // If we're looping, eventually fail.
618      return false;
619    }
620  }
621
622  // On windows 2000 the function returns 1 even when the buffer is too small.
623  // The number of entries that we are going to parse is the minimum between the
624  // size we allocated and the real number of entries.
625  number_of_entries =
626      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
627  for (unsigned int i = 0; i < number_of_entries; i++) {
628    if (buffer->WorkingSetInfo[i].Shared) {
629      ws_shareable++;
630      if (buffer->WorkingSetInfo[i].ShareCount > 1)
631        ws_shared++;
632    } else {
633      ws_private++;
634    }
635  }
636
637  ws_usage->priv = ws_private * PAGESIZE_KB;
638  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
639  ws_usage->shared = ws_shared * PAGESIZE_KB;
640  free(buffer);
641  return true;
642}
643
644static uint64 FileTimeToUTC(const FILETIME& ftime) {
645  LARGE_INTEGER li;
646  li.LowPart = ftime.dwLowDateTime;
647  li.HighPart = ftime.dwHighDateTime;
648  return li.QuadPart;
649}
650
651double ProcessMetrics::GetCPUUsage() {
652  FILETIME now;
653  FILETIME creation_time;
654  FILETIME exit_time;
655  FILETIME kernel_time;
656  FILETIME user_time;
657
658  GetSystemTimeAsFileTime(&now);
659
660  if (!GetProcessTimes(process_, &creation_time, &exit_time,
661                       &kernel_time, &user_time)) {
662    // We don't assert here because in some cases (such as in the Task Manager)
663    // we may call this function on a process that has just exited but we have
664    // not yet received the notification.
665    return 0;
666  }
667  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
668                        processor_count_;
669  int64 time = FileTimeToUTC(now);
670
671  if ((last_system_time_ == 0) || (last_time_ == 0)) {
672    // First call, just set the last values.
673    last_system_time_ = system_time;
674    last_time_ = time;
675    return 0;
676  }
677
678  int64 system_time_delta = system_time - last_system_time_;
679  int64 time_delta = time - last_time_;
680  DCHECK(time_delta != 0);
681  if (time_delta == 0)
682    return 0;
683
684  // We add time_delta / 2 so the result is rounded.
685  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
686                             time_delta);
687
688  last_system_time_ = system_time;
689  last_time_ = time;
690
691  return cpu;
692}
693
694bool ProcessMetrics::GetIOCounters(IO_COUNTERS* io_counters) const {
695  return GetProcessIoCounters(process_, io_counters) != FALSE;
696}
697
698bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const {
699  const SIZE_T kTopAdress = 0x7F000000;
700  const SIZE_T kMegabyte = 1024 * 1024;
701  SIZE_T accumulated = 0;
702
703  MEMORY_BASIC_INFORMATION largest = {0};
704  UINT_PTR scan = 0;
705  while (scan < kTopAdress) {
706    MEMORY_BASIC_INFORMATION info;
707    if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan),
708                          &info, sizeof(info)))
709      return false;
710    if (info.State == MEM_FREE) {
711      accumulated += info.RegionSize;
712      UINT_PTR end = scan + info.RegionSize;
713      if (info.RegionSize > (largest.RegionSize))
714        largest = info;
715    }
716    scan += info.RegionSize;
717  }
718  free->largest = largest.RegionSize / kMegabyte;
719  free->largest_ptr = largest.BaseAddress;
720  free->total = accumulated / kMegabyte;
721  return true;
722}
723
724bool EnableLowFragmentationHeap() {
725  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
726  HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
727      kernel32,
728      "HeapSetInformation"));
729
730  // On Windows 2000, the function is not exported. This is not a reason to
731  // fail.
732  if (!heap_set)
733    return true;
734
735  unsigned number_heaps = GetProcessHeaps(0, NULL);
736  if (!number_heaps)
737    return false;
738
739  // Gives us some extra space in the array in case a thread is creating heaps
740  // at the same time we're querying them.
741  static const int MARGIN = 8;
742  scoped_array<HANDLE> heaps(new HANDLE[number_heaps + MARGIN]);
743  number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
744  if (!number_heaps)
745    return false;
746
747  for (unsigned i = 0; i < number_heaps; ++i) {
748    ULONG lfh_flag = 2;
749    // Don't bother with the result code. It may fails on heaps that have the
750    // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
751    heap_set(heaps[i],
752             HeapCompatibilityInformation,
753             &lfh_flag,
754             sizeof(lfh_flag));
755  }
756  return true;
757}
758
759void EnableTerminationOnHeapCorruption() {
760  // Ignore the result code. Supported on XP SP3 and Vista.
761  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
762}
763
764bool EnableInProcessStackDumping() {
765  // Add stack dumping support on exception on windows. Similar to OS_POSIX
766  // signal() handling in process_util_posix.cc.
767  g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
768  AttachToConsole();
769  return true;
770}
771
772void RaiseProcessToHighPriority() {
773  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
774}
775
776// GetPerformanceInfo is not available on WIN2K.  So we'll
777// load it on-the-fly.
778const wchar_t kPsapiDllName[] = L"psapi.dll";
779typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
780    PPERFORMANCE_INFORMATION pPerformanceInformation,
781    DWORD cb);
782
783// Beware of races if called concurrently from multiple threads.
784static BOOL InternalGetPerformanceInfo(
785    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
786  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
787  if (!GetPerformanceInfo_func) {
788    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
789    if (psapi_dll)
790      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
791          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
792
793    if (!GetPerformanceInfo_func) {
794      // The function could be loaded!
795      memset(pPerformanceInformation, 0, cb);
796      return FALSE;
797    }
798  }
799  return GetPerformanceInfo_func(pPerformanceInformation, cb);
800}
801
802size_t GetSystemCommitCharge() {
803  // Get the System Page Size.
804  SYSTEM_INFO system_info;
805  GetSystemInfo(&system_info);
806
807  PERFORMANCE_INFORMATION info;
808  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
809    LOG(ERROR) << "Failed to fetch internal performance info.";
810    return 0;
811  }
812  return (info.CommitTotal * system_info.dwPageSize) / 1024;
813}
814
815}  // namespace base
816