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