diff options
author | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-26 11:04:55 +0000 |
---|---|---|
committer | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-26 11:04:55 +0000 |
commit | 8d5db3be7fa1e561fc0a515bd0fb9933917806ee (patch) | |
tree | 71661b2b1c7359791a0a477ff92a266e94f1b9f5 /base/process_util.cc | |
parent | 501a7b4f0fcfe3e96b8e309ed765a620106a3f80 (diff) | |
download | chromium_src-8d5db3be7fa1e561fc0a515bd0fb9933917806ee.zip chromium_src-8d5db3be7fa1e561fc0a515bd0fb9933917806ee.tar.gz chromium_src-8d5db3be7fa1e561fc0a515bd0fb9933917806ee.tar.bz2 |
Move process_util.cc to process_util_win.cc to make way for posix.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1377 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util.cc')
-rw-r--r-- | base/process_util.cc | 587 |
1 files changed, 0 insertions, 587 deletions
diff --git a/base/process_util.cc b/base/process_util.cc deleted file mode 100644 index 940ee77..0000000 --- a/base/process_util.cc +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process_util.h" - -#include <windows.h> -#include <winternl.h> -#include <psapi.h> - -#include "base/histogram.h" -#include "base/logging.h" -#include "base/scoped_ptr.h" - -namespace { - -// System pagesize. This value remains constant on x86/64 architectures. -const int PAGESIZE_KB = 4; - -// HeapSetInformation function pointer. -typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); - -} // namespace - -namespace process_util { - -int GetCurrentProcId() { - return ::GetCurrentProcessId(); -} - -// Helper for GetProcId() -bool GetProcIdViaGetProcessId(ProcessHandle process, DWORD* id) { - // Dynamically get a pointer to GetProcessId(). - typedef DWORD (WINAPI *GetProcessIdFunction)(HANDLE); - static GetProcessIdFunction GetProcessIdPtr = NULL; - static bool initialize_get_process_id = true; - if (initialize_get_process_id) { - initialize_get_process_id = false; - HMODULE kernel32_handle = GetModuleHandle(L"kernel32.dll"); - if (!kernel32_handle) { - NOTREACHED(); - return false; - } - GetProcessIdPtr = reinterpret_cast<GetProcessIdFunction>(GetProcAddress( - kernel32_handle, "GetProcessId")); - } - if (!GetProcessIdPtr) - return false; - // Ask for the process ID. - *id = (*GetProcessIdPtr)(process); - return true; -} - -// Helper for GetProcId() -bool GetProcIdViaNtQueryInformationProcess(ProcessHandle process, DWORD* id) { - // Dynamically get a pointer to NtQueryInformationProcess(). - typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)( - HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); - static NtQueryInformationProcessFunction NtQueryInformationProcessPtr = NULL; - static bool initialize_query_information_process = true; - if (initialize_query_information_process) { - initialize_query_information_process = false; - // According to nsylvain, ntdll.dll is guaranteed to be loaded, even though - // the Windows docs seem to imply that you should LoadLibrary() it. - HMODULE ntdll_handle = GetModuleHandle(L"ntdll.dll"); - if (!ntdll_handle) { - NOTREACHED(); - return false; - } - NtQueryInformationProcessPtr = - reinterpret_cast<NtQueryInformationProcessFunction>(GetProcAddress( - ntdll_handle, "NtQueryInformationProcess")); - } - if (!NtQueryInformationProcessPtr) - return false; - // Ask for the process ID. - PROCESS_BASIC_INFORMATION info; - ULONG bytes_returned; - NTSTATUS status = (*NtQueryInformationProcessPtr)(process, - ProcessBasicInformation, - &info, sizeof info, - &bytes_returned); - if (!SUCCEEDED(status) || (bytes_returned != (sizeof info))) - return false; - - *id = static_cast<DWORD>(info.UniqueProcessId); - return true; -} - -int GetProcId(ProcessHandle process) { - // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights. - HANDLE current_process = GetCurrentProcess(); - HANDLE process_with_query_rights; - if (DuplicateHandle(current_process, process, current_process, - &process_with_query_rights, PROCESS_QUERY_INFORMATION, - false, 0)) { - // Try to use GetProcessId(), if it exists. Fall back on - // NtQueryInformationProcess() otherwise (< Win XP SP1). - DWORD id; - bool success = - GetProcIdViaGetProcessId(process_with_query_rights, &id) || - GetProcIdViaNtQueryInformationProcess(process_with_query_rights, &id); - CloseHandle(process_with_query_rights); - if (success) - return id; - } - - // We're screwed. - NOTREACHED(); - return 0; -} - -bool LaunchApp(const std::wstring& cmdline, - bool wait, bool start_hidden, ProcessHandle* process_handle) { - STARTUPINFO startup_info = {0}; - startup_info.cb = sizeof(startup_info); - if (start_hidden) { - startup_info.dwFlags = STARTF_USESHOWWINDOW; - startup_info.wShowWindow = SW_HIDE; - } - PROCESS_INFORMATION process_info; - if (!CreateProcess(NULL, - const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, - FALSE, 0, NULL, NULL, - &startup_info, &process_info)) - return false; - - // Handles must be closed or they will leak - CloseHandle(process_info.hThread); - - if (wait) - WaitForSingleObject(process_info.hProcess, INFINITE); - - // If the caller wants the process handle, we won't close it. - if (process_handle) { - *process_handle = process_info.hProcess; - } else { - CloseHandle(process_info.hProcess); - } - return true; -} - -// Attempts to kill the process identified by the given process -// entry structure, giving it the specified exit code. -// Returns true if this is successful, false otherwise. -bool KillProcess(int process_id, int exit_code, bool wait) { - bool result = false; - HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, - FALSE, // Don't inherit handle - process_id); - if (process) { - result = !!TerminateProcess(process, exit_code); - if (result && wait) { - // The process may not end immediately due to pending I/O - if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000)) - DLOG(ERROR) << "Error waiting for process exit: " << GetLastError(); - } else { - DLOG(ERROR) << "Unable to terminate process: " << GetLastError(); - } - CloseHandle(process); - } - return result; -} - -bool DidProcessCrash(ProcessHandle handle) { - DWORD exitcode = 0; - BOOL success = ::GetExitCodeProcess(handle, &exitcode); - DCHECK(success); - DCHECK(exitcode != STILL_ACTIVE); - - if (exitcode == 0 || // Normal termination. - exitcode == 1 || // Killed by task manager. - exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE - exitcode == 0xC000013A || // Control-C/end session. - exitcode == 0x40010004) { // Debugger terminated process/end session. - return false; - } - - // All other exit codes indicate crashes. - - // TODO(jar): Remove histogramming code when UMA stats are consistent with - // other crash metrics. - // Histogram the low order 3 nibbles for UMA - const int kLeastValue = 0; - const int kMaxValue = 0xFFF; - const int kBucketCount = kMaxValue - kLeastValue + 1; - static LinearHistogram least_significant_histogram(L"ExitCodes.LSNibbles", - kLeastValue + 1, kMaxValue, kBucketCount); - least_significant_histogram.SetFlags(kUmaTargetedHistogramFlag | - LinearHistogram::kHexRangePrintingFlag); - least_significant_histogram.Add(exitcode & 0xFFF); - - // Histogram the high order 3 nibbles - static LinearHistogram most_significant_histogram(L"ExitCodes.MSNibbles", - kLeastValue + 1, kMaxValue, kBucketCount); - most_significant_histogram.SetFlags(kUmaTargetedHistogramFlag | - LinearHistogram::kHexRangePrintingFlag); - // Avoid passing in negative numbers by shifting data into low end of dword. - most_significant_histogram.Add((exitcode >> 20) & 0xFFF); - - // Histogram the middle order 2 nibbles - static LinearHistogram mid_significant_histogram(L"ExitCodes.MidNibbles", - 1, 0xFF, 0x100); - mid_significant_histogram.SetFlags(kUmaTargetedHistogramFlag | - LinearHistogram::kHexRangePrintingFlag); - mid_significant_histogram.Add((exitcode >> 12) & 0xFF); - - return true; -} - -NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name, - const ProcessFilter* filter) : - started_iteration_(false), - executable_name_(executable_name), - filter_(filter) { - snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - } - -NamedProcessIterator::~NamedProcessIterator() { - CloseHandle(snapshot_); -} - - -const ProcessEntry* NamedProcessIterator::NextProcessEntry() { - bool result = false; - do { - result = CheckForNextProcess(); - } while (result && !IncludeEntry()); - - if (result) { - return &entry_; - } - - return NULL; -} - -bool NamedProcessIterator::CheckForNextProcess() { - InitProcessEntry(&entry_); - - if (!started_iteration_) { - started_iteration_ = true; - return !!Process32First(snapshot_, &entry_); - } - - return !!Process32Next(snapshot_, &entry_); -} - -bool NamedProcessIterator::IncludeEntry() { - return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 && - (!filter_ || filter_->Includes(entry_.th32ProcessID, - entry_.th32ParentProcessID)); -} - -void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) { - memset(entry, 0, sizeof(*entry)); - entry->dwSize = sizeof(*entry); -} - -int GetProcessCount(const std::wstring& executable_name, - const ProcessFilter* filter) { - int count = 0; - - NamedProcessIterator iter(executable_name, filter); - while (iter.NextProcessEntry()) - ++count; - return count; -} - -bool KillProcesses(const std::wstring& executable_name, int exit_code, - const ProcessFilter* filter) { - bool result = true; - const ProcessEntry* entry; - - NamedProcessIterator iter(executable_name, filter); - while (entry = iter.NextProcessEntry()) - result = KillProcess((*entry).th32ProcessID, exit_code, true) && result; - - return result; -} - -bool WaitForProcessesToExit(const std::wstring& executable_name, - int wait_milliseconds, - const ProcessFilter* filter) { - const ProcessEntry* entry; - bool result = true; - DWORD start_time = GetTickCount(); - - NamedProcessIterator iter(executable_name, filter); - while (entry = iter.NextProcessEntry()) { - DWORD remaining_wait = - std::max(0, wait_milliseconds - - static_cast<int>(GetTickCount() - start_time)); - HANDLE process = OpenProcess(SYNCHRONIZE, - FALSE, - entry->th32ProcessID); - DWORD wait_result = WaitForSingleObject(process, remaining_wait); - CloseHandle(process); - result = result && (wait_result == WAIT_OBJECT_0); - } - - return result; -} - -bool CleanupProcesses(const std::wstring& executable_name, - int wait_milliseconds, - int exit_code, - const ProcessFilter* filter) { - bool exited_cleanly = - process_util::WaitForProcessesToExit(executable_name, wait_milliseconds, - filter); - if (!exited_cleanly) - process_util::KillProcesses(executable_name, exit_code, filter); - return exited_cleanly; -} - - -/////////////////////////////////////////////////////////////////////////////// -// ProcesMetrics - -ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), - last_time_(0), - last_system_time_(0) { - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - processor_count_ = system_info.dwNumberOfProcessors; -} - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -ProcessMetrics::~ProcessMetrics() { } - -size_t ProcessMetrics::GetPagefileUsage() { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.PagefileUsage; - } - return 0; -} - -// Returns the peak space allocated for the pagefile, in bytes. -size_t ProcessMetrics::GetPeakPagefileUsage() { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.PeakPagefileUsage; - } - return 0; -} - -// Returns the current working set size, in bytes. -size_t ProcessMetrics::GetWorkingSetSize() { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.WorkingSetSize; - } - return 0; -} - -size_t ProcessMetrics::GetPrivateBytes() { - // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2. - // GetProcessMemoryInfo() will simply fail on prior OS. So the requested - // information is simply not available. Hence, we will return 0 on unsupported - // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member. - PROCESS_MEMORY_COUNTERS_EX pmcx; - if (GetProcessMemoryInfo(process_, - reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), - sizeof(pmcx))) { - return pmcx.PrivateUsage; - } - return 0; -} - -void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) { - MEMORY_BASIC_INFORMATION mbi = {0}; - size_t committed_private = 0; - size_t committed_mapped = 0; - size_t committed_image = 0; - void* base_address = NULL; - while (VirtualQueryEx(process_, base_address, &mbi, - sizeof(MEMORY_BASIC_INFORMATION)) == - sizeof(MEMORY_BASIC_INFORMATION)) { - if (mbi.State == MEM_COMMIT) { - if (mbi.Type == MEM_PRIVATE) { - committed_private += mbi.RegionSize; - } else if (mbi.Type == MEM_MAPPED) { - committed_mapped += mbi.RegionSize; - } else if (mbi.Type == MEM_IMAGE) { - committed_image += mbi.RegionSize; - } else { - NOTREACHED(); - } - } - base_address = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize; - } - usage->image = committed_image / 1024; - usage->mapped = committed_mapped / 1024; - usage->priv = committed_private / 1024; -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) { - size_t ws_private = 0; - size_t ws_shareable = 0; - size_t ws_shared = 0; - - DCHECK(ws_usage); - memset(ws_usage, 0, sizeof(*ws_usage)); - - DWORD number_of_entries = 4096; // Just a guess. - PSAPI_WORKING_SET_INFORMATION* buffer = NULL; - int retries = 5; - for (;;) { - DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + - (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); - - // if we can't expand the buffer, don't leak the previous - // contents or pass a NULL pointer to QueryWorkingSet - PSAPI_WORKING_SET_INFORMATION* new_buffer = - reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>( - realloc(buffer, buffer_size)); - if (!new_buffer) { - free(buffer); - return false; - } - buffer = new_buffer; - - // Call the function once to get number of items - if (QueryWorkingSet(process_, buffer, buffer_size)) - break; // Success - - if (GetLastError() != ERROR_BAD_LENGTH) { - free(buffer); - return false; - } - - number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries); - - // Maybe some entries are being added right now. Increase the buffer to - // take that into account. - number_of_entries = static_cast<DWORD>(number_of_entries * 1.25); - - if (--retries == 0) { - free(buffer); // If we're looping, eventually fail. - return false; - } - } - - // On windows 2000 the function returns 1 even when the buffer is too small. - // The number of entries that we are going to parse is the minimum between the - // size we allocated and the real number of entries. - number_of_entries = - std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries)); - for (unsigned int i = 0; i < number_of_entries; i++) { - if (buffer->WorkingSetInfo[i].Shared) { - ws_shareable++; - if (buffer->WorkingSetInfo[i].ShareCount > 1) - ws_shared++; - } else { - ws_private++; - } - } - - ws_usage->priv = ws_private * PAGESIZE_KB; - ws_usage->shareable = ws_shareable * PAGESIZE_KB; - ws_usage->shared = ws_shared * PAGESIZE_KB; - free(buffer); - return true; -} - -static uint64 FileTimeToUTC(const FILETIME& ftime) { - LARGE_INTEGER li; - li.LowPart = ftime.dwLowDateTime; - li.HighPart = ftime.dwHighDateTime; - return li.QuadPart; -} - -int ProcessMetrics::GetCPUUsage() { - FILETIME now; - FILETIME creation_time; - FILETIME exit_time; - FILETIME kernel_time; - FILETIME user_time; - - GetSystemTimeAsFileTime(&now); - - if (!GetProcessTimes(process_, &creation_time, &exit_time, - &kernel_time, &user_time)) { - // We don't assert here because in some cases (such as in the Task Manager) - // we may call this function on a process that has just exited but we have - // not yet received the notification. - return 0; - } - int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) / - processor_count_; - int64 time = FileTimeToUTC(now); - - if ((last_system_time_ == 0) || (last_time_ == 0)) { - // First call, just set the last values. - last_system_time_ = system_time; - last_time_ = time; - return 0; - } - - int64 system_time_delta = system_time - last_system_time_; - int64 time_delta = time - last_time_; - DCHECK(time_delta != 0); - if (time_delta == 0) - return 0; - - // We add time_delta / 2 so the result is rounded. - int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) / - time_delta); - - last_system_time_ = system_time; - last_time_ = time; - - return cpu; -} - -bool ProcessMetrics::GetIOCounters(IO_COUNTERS* io_counters) { - return GetProcessIoCounters(process_, io_counters) != FALSE; -} - -bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) { - const SIZE_T kTopAdress = 0x7F000000; - const SIZE_T kMegabyte = 1024 * 1024; - SIZE_T accumulated = 0; - - MEMORY_BASIC_INFORMATION largest = {0}; - UINT_PTR scan = 0; - while (scan < kTopAdress) { - MEMORY_BASIC_INFORMATION info; - if (!::VirtualQueryEx(process_, reinterpret_cast<void*>(scan), - &info, sizeof(info))) - return false; - if (info.State == MEM_FREE) { - accumulated += info.RegionSize; - UINT_PTR end = scan + info.RegionSize; - if (info.RegionSize > (largest.RegionSize)) - largest = info; - } - scan += info.RegionSize; - } - free->largest = largest.RegionSize / kMegabyte; - free->largest_ptr = largest.BaseAddress; - free->total = accumulated / kMegabyte; - return true; -} - -bool EnableLowFragmentationHeap() { - HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress( - kernel32, - "HeapSetInformation")); - - // On Windows 2000, the function is not exported. This is not a reason to - // fail. - if (!heap_set) - return true; - - unsigned number_heaps = GetProcessHeaps(0, NULL); - if (!number_heaps) - return false; - - // Gives us some extra space in the array in case a thread is creating heaps - // at the same time we're querying them. - static const int MARGIN = 8; - scoped_array<HANDLE> heaps(new HANDLE[number_heaps + MARGIN]); - number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get()); - if (!number_heaps) - return false; - - for (unsigned i = 0; i < number_heaps; ++i) { - ULONG lfh_flag = 2; - // Don't bother with the result code. It may fails on heaps that have the - // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all. - heap_set(heaps[i], - HeapCompatibilityInformation, - &lfh_flag, - sizeof(lfh_flag)); - } - return true; -} - -} // namespace process_util - |