Home | History | Annotate | Download | only in base
      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 
     24 namespace base {
     25 
     26 namespace {
     27 
     28 // System pagesize. This value remains constant on x86/64 architectures.
     29 const int PAGESIZE_KB = 4;
     30 
     31 // HeapSetInformation function pointer.
     32 typedef 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.
     36 LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
     37 
     38 // Prints the exception call stack.
     39 // This is the unit tests exception filter.
     40 long 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.
     49 void 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 
     83 ProcessId GetCurrentProcId() {
     84   return ::GetCurrentProcessId();
     85 }
     86 
     87 ProcessHandle GetCurrentProcessHandle() {
     88   return ::GetCurrentProcess();
     89 }
     90 
     91 bool 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 
    105 bool 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 
    120 void CloseProcessHandle(ProcessHandle process) {
    121   CloseHandle(process);
    122 }
    123 
    124 ProcessId 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 
    141 bool 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 
    170 bool 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 
    205 bool 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.
    214 bool 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 
    226 bool 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 
    299 bool 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 
    311 bool 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 
    343 bool 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 
    356 NamedProcessIterator::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 
    364 NamedProcessIterator::~NamedProcessIterator() {
    365   CloseHandle(snapshot_);
    366 }
    367 
    368 
    369 const 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 
    382 bool 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 
    393 bool NamedProcessIterator::IncludeEntry() {
    394   return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 &&
    395                   (!filter_ || filter_->Includes(entry_.th32ProcessID,
    396                                                  entry_.th32ParentProcessID));
    397 }
    398 
    399 void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) {
    400   memset(entry, 0, sizeof(*entry));
    401   entry->dwSize = sizeof(*entry);
    402 }
    403 
    404 int 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 
    414 bool 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 
    428 bool 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 
    450 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
    451   bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_OBJECT_0;
    452   return retval;
    453 }
    454 
    455 bool CrashAwareSleep(ProcessHandle handle, int64 wait_milliseconds) {
    456   bool retval = WaitForSingleObject(handle, wait_milliseconds) == WAIT_TIMEOUT;
    457   return retval;
    458 }
    459 
    460 bool 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 
    475 ProcessMetrics::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
    484 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
    485   return new ProcessMetrics(process);
    486 }
    487 
    488 ProcessMetrics::~ProcessMetrics() { }
    489 
    490 size_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.
    499 size_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.
    508 size_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.
    517 size_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 
    525 size_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 
    539 void 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 
    575 bool 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 
    644 static 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 
    651 double 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 
    694 bool ProcessMetrics::GetIOCounters(IO_COUNTERS* io_counters) const {
    695   return GetProcessIoCounters(process_, io_counters) != FALSE;
    696 }
    697 
    698 bool 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 
    724 bool 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 
    759 void EnableTerminationOnHeapCorruption() {
    760   // Ignore the result code. Supported on XP SP3 and Vista.
    761   HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
    762 }
    763 
    764 bool 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 
    772 void 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.
    778 const wchar_t kPsapiDllName[] = L"psapi.dll";
    779 typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
    780     PPERFORMANCE_INFORMATION pPerformanceInformation,
    781     DWORD cb);
    782 
    783 // Beware of races if called concurrently from multiple threads.
    784 static 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 
    802 size_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