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