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