diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-12 14:07:37 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 10:29:26 +0000 |
commit | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch) | |
tree | 25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/base/process | |
parent | bb09965444b5bb20b096a291445170876225268d (diff) |
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/process')
20 files changed, 643 insertions, 274 deletions
diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h index be8f6e73b9f..99a7280cb35 100644 --- a/chromium/base/process/launch.h +++ b/chromium/base/process/launch.h @@ -262,6 +262,11 @@ BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output); BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv, std::string* output); +// Like the above POSIX-specific version of GetAppOutput, but also includes +// stderr. +BASE_EXPORT bool GetAppOutputAndError(const std::vector<std::string>& argv, + std::string* output); + // A version of |GetAppOutput()| which also returns the exit code of the // executed command. Returns true if the application runs and exits cleanly. If // this is the case the exit code of the application is available in diff --git a/chromium/base/process/launch_posix.cc b/chromium/base/process/launch_posix.cc index 44eafcfb05a..2184051552d 100644 --- a/chromium/base/process/launch_posix.cc +++ b/chromium/base/process/launch_posix.cc @@ -663,6 +663,14 @@ bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { return result && exit_code == EXIT_SUCCESS; } +bool GetAppOutputAndError(const std::vector<std::string>& argv, + std::string* output) { + int exit_code; + bool result = + GetAppOutputInternal(argv, nullptr, true, output, true, &exit_code); + return result && exit_code == EXIT_SUCCESS; +} + bool GetAppOutputWithExitCode(const CommandLine& cl, std::string* output, int* exit_code) { diff --git a/chromium/base/process/launch_win.cc b/chromium/base/process/launch_win.cc index 97b59a5bfe4..f55c9684150 100644 --- a/chromium/base/process/launch_win.cc +++ b/chromium/base/process/launch_win.cc @@ -17,6 +17,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" +#include "base/debug/activity_tracker.h" #include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" @@ -94,7 +95,12 @@ bool GetAppOutputInternal(const StringPiece16& cl, NOTREACHED() << "Failed to start process"; return false; } + base::win::ScopedProcessInformation proc_info(temp_process_info); + base::debug::GlobalActivityTracker* tracker = + base::debug::GlobalActivityTracker::Get(); + if (tracker) + tracker->RecordProcessLaunch(proc_info.process_id(), cl.as_string()); // Close our writing end of pipe now. Otherwise later read would not be able // to detect end of child's output. @@ -119,6 +125,8 @@ bool GetAppOutputInternal(const StringPiece16& cl, int exit_code; base::TerminationStatus status = GetTerminationStatus( proc_info.process_handle(), &exit_code); + base::debug::GlobalActivityTracker::RecordProcessExitIfEnabled( + proc_info.process_id(), exit_code); return status != base::TERMINATION_STATUS_PROCESS_CRASHED && status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; } @@ -324,6 +332,8 @@ Process LaunchProcess(const string16& cmdline, if (options.wait) WaitForSingleObject(process_info.process_handle(), INFINITE); + base::debug::GlobalActivityTracker::RecordProcessLaunchIfEnabled( + process_info.process_id(), cmdline); return Process(process_info.TakeProcessHandle()); } @@ -351,6 +361,8 @@ Process LaunchElevatedProcess(const CommandLine& cmdline, if (options.wait) WaitForSingleObject(shex_info.hProcess, INFINITE); + base::debug::GlobalActivityTracker::RecordProcessLaunchIfEnabled( + GetProcessId(shex_info.hProcess), file, arguments); return Process(shex_info.hProcess); } diff --git a/chromium/base/process/memory_unittest.cc b/chromium/base/process/memory_unittest.cc index ecf0b871ecb..a097897c0b0 100644 --- a/chromium/base/process/memory_unittest.cc +++ b/chromium/base/process/memory_unittest.cc @@ -79,6 +79,10 @@ TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) { #else ADD_FAILURE() << "This test is not supported in this build configuration."; #endif + +#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM) + base::allocator::UninterceptMallocZonesForTesting(); +#endif } #endif // defined(OS_MACOSX) @@ -91,6 +95,10 @@ TEST(MemoryTest, AllocatorShimWorking) { base::allocator::InterceptAllocationsMac(); #endif ASSERT_TRUE(base::allocator::IsAllocatorInitialized()); + +#if defined(OS_MACOSX) + base::allocator::UninterceptMallocZonesForTesting(); +#endif } // OpenBSD does not support these tests. Don't test these on ASan/TSan/MSan @@ -146,6 +154,12 @@ class OutOfMemoryDeathTest : public OutOfMemoryTest { // should be done inside of the ASSERT_DEATH. base::EnableTerminationOnOutOfMemory(); } + +#if defined(OS_MACOSX) + void TearDown() override { + base::allocator::UninterceptMallocZonesForTesting(); + } +#endif }; TEST_F(OutOfMemoryDeathTest, New) { @@ -422,6 +436,12 @@ class OutOfMemoryHandledTest : public OutOfMemoryTest { // properly by-pass this in order to allow the caller to handle OOM. base::EnableTerminationOnOutOfMemory(); } + + void TearDown() override { +#if defined(OS_MACOSX) + base::allocator::UninterceptMallocZonesForTesting(); +#endif + } }; #if defined(OS_WIN) diff --git a/chromium/base/process/process_info_linux.cc b/chromium/base/process/process_info_linux.cc index 7cec8f4e4ec..2f227484f5f 100644 --- a/chromium/base/process/process_info_linux.cc +++ b/chromium/base/process/process_info_linux.cc @@ -17,10 +17,12 @@ namespace base { const Time CurrentProcessInfo::CreationTime() { int64_t start_ticks = internal::ReadProcSelfStatsAndGetFieldAsInt64(internal::VM_STARTTIME); - DCHECK(start_ticks); + if (!start_ticks) + return Time(); TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks); Time boot_time = internal::GetBootTime(); - DCHECK(!boot_time.is_null()); + if (boot_time.is_null()) + return Time(); return Time(boot_time + start_offset); } diff --git a/chromium/base/process/process_info_unittest.cc b/chromium/base/process/process_info_unittest.cc new file mode 100644 index 00000000000..a757774fdad --- /dev/null +++ b/chromium/base/process/process_info_unittest.cc @@ -0,0 +1,20 @@ +// Copyright 2017 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/process_info.h" + +#include "base/time/time.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { + +#if !defined(OS_IOS) +TEST(ProcessInfoTest, CreationTime) { + Time creation_time = CurrentProcessInfo::CreationTime(); + ASSERT_FALSE(creation_time.is_null()); +} +#endif // !defined(OS_IOS) + +} // namespace base diff --git a/chromium/base/process/process_linux.cc b/chromium/base/process/process_linux.cc index 2973ef3cbcc..f98bb4c0554 100644 --- a/chromium/base/process/process_linux.cc +++ b/chromium/base/process/process_linux.cc @@ -60,9 +60,12 @@ struct CGroups { foreground_type == FILE_SYSTEM_CGROUP && background_type == FILE_SYSTEM_CGROUP; } -}; -base::LazyInstance<CGroups> g_cgroups = LAZY_INSTANCE_INITIALIZER; + static CGroups& Get() { + static auto& groups = *new CGroups; + return groups; + } +}; #else const int kBackgroundPriority = 5; #endif // defined(OS_CHROMEOS) @@ -86,12 +89,12 @@ struct CheckForNicePermission { // static bool Process::CanBackgroundProcesses() { #if defined(OS_CHROMEOS) - if (g_cgroups.Get().enabled) + if (CGroups::Get().enabled) return true; #endif // defined(OS_CHROMEOS) - static LazyInstance<CheckForNicePermission> check_for_nice_permission = - LAZY_INSTANCE_INITIALIZER; + static LazyInstance<CheckForNicePermission>::DestructorAtExit + check_for_nice_permission = LAZY_INSTANCE_INITIALIZER; return check_for_nice_permission.Get().can_reraise_priority; } @@ -99,7 +102,7 @@ bool Process::IsProcessBackgrounded() const { DCHECK(IsValid()); #if defined(OS_CHROMEOS) - if (g_cgroups.Get().enabled) { + if (CGroups::Get().enabled) { // Used to allow reading the process priority from proc on thread launch. base::ThreadRestrictions::ScopedAllowIO allow_io; std::string proc; @@ -118,11 +121,10 @@ bool Process::SetProcessBackgrounded(bool background) { DCHECK(IsValid()); #if defined(OS_CHROMEOS) - if (g_cgroups.Get().enabled) { + if (CGroups::Get().enabled) { std::string pid = IntToString(process_); - const base::FilePath file = - background ? - g_cgroups.Get().background_file : g_cgroups.Get().foreground_file; + const base::FilePath file = background ? CGroups::Get().background_file + : CGroups::Get().foreground_file; return base::WriteFile(file, pid.c_str(), pid.size()) > 0; } #endif // defined(OS_CHROMEOS) diff --git a/chromium/base/process/process_metrics.cc b/chromium/base/process/process_metrics.cc index a38930a2088..ad555aedffe 100644 --- a/chromium/base/process/process_metrics.cc +++ b/chromium/base/process/process_metrics.cc @@ -12,6 +12,11 @@ namespace base { +SystemMemoryInfoKB::SystemMemoryInfoKB() = default; + +SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = + default; + SystemMetrics::SystemMetrics() { committed_memory_ = 0; } diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h index 2448a715ace..6e5e796a7c8 100644 --- a/chromium/base/process/process_metrics.h +++ b/chromium/base/process/process_metrics.h @@ -25,6 +25,14 @@ #if defined(OS_MACOSX) #include <mach/mach.h> #include "base/process/port_provider_mac.h" + +#if !defined(OS_IOS) +#include <mach/mach_vm.h> +#endif +#endif + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" #endif namespace base { @@ -63,8 +71,12 @@ struct IoCounters { // shareable: 0 // swapped Pages swapped out to zram. // -// On OS X: TODO(thakis): Revise. -// priv: Memory. +// On macOS: +// priv: Resident size (RSS) including shared memory. Warning: This +// does not include compressed size and does not always +// accurately account for shared memory due to things like +// copy-on-write. TODO(erikchen): Revamp this with something +// more accurate. // shared: 0 // shareable: 0 // @@ -136,8 +148,7 @@ class BASE_EXPORT ProcessMetrics { // memory currently allocated to a process that cannot be shared. Returns // false on platform specific error conditions. Note: |private_bytes| // returns 0 on unsupported OSes: prior to XP SP2. - bool GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes); + bool GetMemoryBytes(size_t* private_bytes, size_t* shared_bytes) const; // Fills a CommittedKBytes with both resident and paged // memory usage as per definition of CommittedBytes. void GetCommittedKBytes(CommittedKBytes* usage) const; @@ -155,6 +166,19 @@ class BASE_EXPORT ProcessMetrics { // system call. bool GetCommittedAndWorkingSetKBytes(CommittedKBytes* usage, WorkingSetKBytes* ws_usage) const; + + // Returns the physical footprint, only available on macOS 10.11+. This + // measures anonymous, non-discardable memory. Returns 0 on error, or if the + // measurement was unavailable. + size_t GetPhysicalFootprint() const; + + // Returns private, shared, and total resident bytes. |locked_bytes| refers to + // bytes that must stay resident. |locked_bytes| only counts bytes locked by + // this task, not bytes locked by the kernel. + bool GetMemoryBytes(size_t* private_bytes, + size_t* shared_bytes, + size_t* resident_bytes, + size_t* locked_bytes) const; #endif // Returns the CPU usage in percent since the last time this method or @@ -185,6 +209,10 @@ class BASE_EXPORT ProcessMetrics { // Returns the number of file descriptors currently open by the process, or // -1 on error. int GetOpenFdCount() const; + + // Returns the soft limit of file descriptors that can be opened by the + // process, or -1 on error. + int GetOpenFdSoftLimit() const; #endif // defined(OS_LINUX) private: @@ -206,7 +234,11 @@ class BASE_EXPORT ProcessMetrics { int CalculateIdleWakeupsPerSecond(uint64_t absolute_idle_wakeups); #endif +#if defined(OS_WIN) + win::ScopedHandle process_; +#else ProcessHandle process_; +#endif int processor_count_; @@ -261,11 +293,13 @@ BASE_EXPORT void SetFdLimit(unsigned int max_descriptors); // Data about system-wide memory consumption. Values are in KB. Available on // Windows, Mac, Linux, Android and Chrome OS. // -// Total/free memory are available on all platforms that implement +// Total memory are available on all platforms that implement // GetSystemMemoryInfo(). Total/free swap memory are available on all platforms // except on Mac. Buffers/cached/active_anon/inactive_anon/active_file/ -// inactive_file/dirty/pswpin/pswpout/pgmajfault are available on +// inactive_file/dirty/reclaimable/pswpin/pswpout/pgmajfault are available on // Linux/Android/Chrome OS. Shmem/slab/gem_objects/gem_size are Chrome OS only. +// Speculative/file_backed/purgeable are Mac and iOS only. +// Free is absent on Windows (see "avail_phys" below). struct BASE_EXPORT SystemMemoryInfoKB { SystemMemoryInfoKB(); SystemMemoryInfoKB(const SystemMemoryInfoKB& other); @@ -273,44 +307,64 @@ struct BASE_EXPORT SystemMemoryInfoKB { // Serializes the platform specific fields to value. std::unique_ptr<Value> ToValue() const; - int total; - int free; + int total = 0; -#if defined(OS_LINUX) +#if !defined(OS_WIN) + int free = 0; +#endif + +#if defined(OS_WIN) + // "This is the amount of physical memory that can be immediately reused + // without having to write its contents to disk first. It is the sum of the + // size of the standby, free, and zero lists." (MSDN). + // Standby: not modified pages of physical ram (file-backed memory) that are + // not actively being used. + int avail_phys = 0; +#endif + +#if defined(OS_LINUX) || defined(OS_ANDROID) // This provides an estimate of available memory as described here: // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773 // NOTE: this is ONLY valid in kernels 3.14 and up. Its value will always // be 0 in earlier kernel versions. - int available; + // Note: it includes _all_ file-backed memory (active + inactive). + int available = 0; #endif #if !defined(OS_MACOSX) - int swap_total; - int swap_free; + int swap_total = 0; + int swap_free = 0; #endif #if defined(OS_ANDROID) || defined(OS_LINUX) - int buffers; - int cached; - int active_anon; - int inactive_anon; - int active_file; - int inactive_file; - int dirty; + int buffers = 0; + int cached = 0; + int active_anon = 0; + int inactive_anon = 0; + int active_file = 0; + int inactive_file = 0; + int dirty = 0; + int reclaimable = 0; // vmstats data. - unsigned long pswpin; - unsigned long pswpout; - unsigned long pgmajfault; + unsigned long pswpin = 0; + unsigned long pswpout = 0; + unsigned long pgmajfault = 0; #endif // defined(OS_ANDROID) || defined(OS_LINUX) #if defined(OS_CHROMEOS) - int shmem; - int slab; + int shmem = 0; + int slab = 0; // Gem data will be -1 if not supported. - int gem_objects; - long long gem_size; + int gem_objects = -1; + long long gem_size = -1; #endif // defined(OS_CHROMEOS) + +#if defined(OS_MACOSX) + int speculative = 0; + int file_backed = 0; + int purgeable = 0; +#endif // defined(OS_MACOSX) }; // On Linux/Android/Chrome OS, system-wide memory consumption data is parsed @@ -434,6 +488,42 @@ class SystemMetrics { #endif }; +#if defined(OS_MACOSX) && !defined(OS_IOS) +enum class MachVMRegionResult { + // There were no more memory regions between |address| and the end of the + // virtual address space. + Finished, + + // All output parameters are invalid. + Error, + + // All output parameters are filled in. + Success +}; + +// Returns info on the first memory region at or after |address|, including +// resident memory and share mode. On Success, |size| reflects the size of the +// memory region. +// |size| and |info| are output parameters, only valid on Success. +// |address| is an in-out parameter, than represents both the address to start +// looking, and the start address of the memory region. +BASE_EXPORT MachVMRegionResult GetTopInfo(mach_port_t task, + mach_vm_size_t* size, + mach_vm_address_t* address, + vm_region_top_info_data_t* info); + +// Returns info on the first memory region at or after |address|, including +// protection values. On Success, |size| reflects the size of the +// memory region. +// Returns info on the first memory region at or after |address|, including +// resident memory and share mode. +// |size| and |info| are output parameters, only valid on Success. +BASE_EXPORT MachVMRegionResult GetBasicInfo(mach_port_t task, + mach_vm_size_t* size, + mach_vm_address_t* address, + vm_region_basic_info_64* info); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + } // namespace base #endif // BASE_PROCESS_PROCESS_METRICS_H_ diff --git a/chromium/base/process/process_metrics_freebsd.cc b/chromium/base/process/process_metrics_freebsd.cc index 686f6338724..4f5adf790f6 100644 --- a/chromium/base/process/process_metrics_freebsd.cc +++ b/chromium/base/process/process_metrics_freebsd.cc @@ -58,7 +58,7 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const { } bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { + size_t* shared_bytes) const { WorkingSetKBytes ws_usage; if (!GetWorkingSetKBytes(&ws_usage)) return false; diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc index e6b01192b59..2ed65ab37f9 100644 --- a/chromium/base/process/process_metrics_ios.cc +++ b/chromium/base/process/process_metrics_ios.cc @@ -9,7 +9,9 @@ #include <stddef.h> #include "base/logging.h" +#include "base/mac/scoped_mach_port.h" #include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" namespace base { @@ -26,11 +28,6 @@ bool GetTaskInfo(task_basic_info_64* task_info_data) { } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() : total(0), free(0) {} - -SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = - default; - ProcessMetrics::ProcessMetrics(ProcessHandle process) {} ProcessMetrics::~ProcessMetrics() {} @@ -91,11 +88,40 @@ size_t GetSystemCommitCharge() { return 0; } -// Bytes committed by the system. bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { - // Unimplemented. Must enable unittest for IOS when this gets implemented. - NOTIMPLEMENTED(); - return false; + struct host_basic_info hostinfo; + mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; + base::mac::ScopedMachSendRight host(mach_host_self()); + int result = host_info(host.get(), HOST_BASIC_INFO, + reinterpret_cast<host_info_t>(&hostinfo), &count); + if (result != KERN_SUCCESS) + return false; + + DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); + meminfo->total = static_cast<int>(hostinfo.max_mem / 1024); + + vm_statistics64_data_t vm_info; + count = HOST_VM_INFO64_COUNT; + + if (host_statistics64(host.get(), HOST_VM_INFO64, + reinterpret_cast<host_info64_t>(&vm_info), + &count) != KERN_SUCCESS) { + return false; + } + DCHECK_EQ(HOST_VM_INFO64_COUNT, count); + + // Check that PAGE_SIZE is divisible by 1024 (2^10). + CHECK_EQ(PAGE_SIZE, (PAGE_SIZE >> 10) << 10); + meminfo->free = saturated_cast<int>( + PAGE_SIZE / 1024 * (vm_info.free_count - vm_info.speculative_count)); + meminfo->speculative = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count); + meminfo->file_backed = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count); + meminfo->purgeable = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count); + + return true; } } // namespace base diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc index b14aa210bd5..ba0dfa76b96 100644 --- a/chromium/base/process/process_metrics_linux.cc +++ b/chromium/base/process/process_metrics_linux.cc @@ -192,7 +192,7 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const { } bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { + size_t* shared_bytes) const { WorkingSetKBytes ws_usage; if (!GetWorkingSetKBytes(&ws_usage)) return false; @@ -311,6 +311,32 @@ int ProcessMetrics::GetOpenFdCount() const { return total_count; } + +int ProcessMetrics::GetOpenFdSoftLimit() const { + // Use /proc/<pid>/limits to read the open fd limit. + FilePath fd_path = internal::GetProcPidDir(process_).Append("limits"); + + std::string limits_contents; + if (!ReadFileToString(fd_path, &limits_contents)) + return -1; + + for (const auto& line : + base::SplitStringPiece(limits_contents, "\n", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY)) { + if (line.starts_with("Max open files")) { + auto tokens = base::SplitStringPiece(line, " ", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + if (tokens.size() > 3) { + int limit = -1; + if (StringToInt(tokens[3], &limit)) + return limit; + return -1; + } + } + } + return -1; +} + #endif // defined(OS_LINUX) ProcessMetrics::ProcessMetrics(ProcessHandle process) @@ -532,45 +558,12 @@ const size_t kDiskWeightedIOTime = 13; } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() { - total = 0; - free = 0; -#if defined(OS_LINUX) - available = 0; -#endif - buffers = 0; - cached = 0; - active_anon = 0; - inactive_anon = 0; - active_file = 0; - inactive_file = 0; - swap_total = 0; - swap_free = 0; - dirty = 0; - - pswpin = 0; - pswpout = 0; - pgmajfault = 0; - -#ifdef OS_CHROMEOS - shmem = 0; - slab = 0; - gem_objects = -1; - gem_size = -1; -#endif -} - -SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = - default; - std::unique_ptr<Value> SystemMemoryInfoKB::ToValue() const { std::unique_ptr<DictionaryValue> res(new DictionaryValue()); res->SetInteger("total", total); res->SetInteger("free", free); -#if defined(OS_LINUX) res->SetInteger("available", available); -#endif res->SetInteger("buffers", buffers); res->SetInteger("cached", cached); res->SetInteger("active_anon", active_anon); @@ -581,6 +574,7 @@ std::unique_ptr<Value> SystemMemoryInfoKB::ToValue() const { res->SetInteger("swap_free", swap_free); res->SetInteger("swap_used", swap_total - swap_free); res->SetInteger("dirty", dirty); + res->SetInteger("reclaimable", reclaimable); res->SetInteger("pswpin", pswpin); res->SetInteger("pswpout", pswpout); res->SetInteger("pgmajfault", pgmajfault); @@ -628,10 +622,8 @@ bool ParseProcMeminfo(const std::string& meminfo_data, target = &meminfo->total; else if (tokens[0] == "MemFree:") target = &meminfo->free; -#if defined(OS_LINUX) else if (tokens[0] == "MemAvailable:") target = &meminfo->available; -#endif else if (tokens[0] == "Buffers:") target = &meminfo->buffers; else if (tokens[0] == "Cached:") @@ -650,6 +642,8 @@ bool ParseProcMeminfo(const std::string& meminfo_data, target = &meminfo->swap_free; else if (tokens[0] == "Dirty:") target = &meminfo->dirty; + else if (tokens[0] == "SReclaimable:") + target = &meminfo->reclaimable; #if defined(OS_CHROMEOS) // Chrome OS has a tweaked kernel that allows us to query Shmem, which is // usually video memory otherwise invisible to the OS. diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc index a3c2d6a14aa..19428fafef7 100644 --- a/chromium/base/process/process_metrics_mac.cc +++ b/chromium/base/process/process_metrics_mac.cc @@ -13,32 +13,50 @@ #include "base/containers/hash_tables.h" #include "base/logging.h" +#include "base/mac/mac_util.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" #include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" #include "base/sys_info.h" -#if !defined(TASK_POWER_INFO) -// Doesn't exist in the 10.6 or 10.7 SDKs. -#define TASK_POWER_INFO 21 -struct task_power_info { - uint64_t total_user; - uint64_t total_system; - uint64_t task_interrupt_wakeups; - uint64_t task_platform_idle_wakeups; - uint64_t task_timer_wakeups_bin_1; - uint64_t task_timer_wakeups_bin_2; -}; -typedef struct task_power_info task_power_info_data_t; -typedef struct task_power_info *task_power_info_t; -#define TASK_POWER_INFO_COUNT ((mach_msg_type_number_t) \ - (sizeof (task_power_info_data_t) / sizeof (natural_t))) -#endif - namespace base { namespace { +#if !defined(MAC_OS_X_VERSION_10_11) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11 +// The |phys_footprint| field was introduced in 10.11. +struct ChromeTaskVMInfo { + mach_vm_size_t virtual_size; + integer_t region_count; + integer_t page_size; + mach_vm_size_t resident_size; + mach_vm_size_t resident_size_peak; + mach_vm_size_t device; + mach_vm_size_t device_peak; + mach_vm_size_t internal; + mach_vm_size_t internal_peak; + mach_vm_size_t external; + mach_vm_size_t external_peak; + mach_vm_size_t reusable; + mach_vm_size_t reusable_peak; + mach_vm_size_t purgeable_volatile_pmap; + mach_vm_size_t purgeable_volatile_resident; + mach_vm_size_t purgeable_volatile_virtual; + mach_vm_size_t compressed; + mach_vm_size_t compressed_peak; + mach_vm_size_t compressed_lifetime; + mach_vm_size_t phys_footprint; +}; +mach_msg_type_number_t ChromeTaskVMInfoCount = + sizeof(ChromeTaskVMInfo) / sizeof(natural_t); +#else +using ChromeTaskVMInfo = task_vm_info; +mach_msg_type_number_t ChromeTaskVMInfoCount = TASK_VM_INFO_REV1_COUNT; +#endif // MAC_OS_X_VERSION_10_11 + bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) { if (task == MACH_PORT_NULL) return false; @@ -78,12 +96,17 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { } } -} // namespace - -SystemMemoryInfoKB::SystemMemoryInfoKB() : total(0), free(0) {} +MachVMRegionResult ParseOutputFromMachVMRegion(kern_return_t kr) { + if (kr == KERN_INVALID_ADDRESS) { + // We're at the end of the address space. + return MachVMRegionResult::Finished; + } else if (kr != KERN_SUCCESS) { + return MachVMRegionResult::Error; + } + return MachVMRegionResult::Success; +} -SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = - default; +} // namespace // Getting a mach task from a pid for another process requires permissions in // general, so there doesn't really seem to be a way to do these (and spinning @@ -110,26 +133,31 @@ size_t ProcessMetrics::GetPeakPagefileUsage() const { } size_t ProcessMetrics::GetWorkingSetSize() const { - task_basic_info_64 task_info_data; - if (!GetTaskInfo(TaskForPid(process_), &task_info_data)) + size_t resident_bytes = 0; + if (!GetMemoryBytes(nullptr, nullptr, &resident_bytes, nullptr)) return 0; - return task_info_data.resident_size; + return resident_bytes; } size_t ProcessMetrics::GetPeakWorkingSetSize() const { return 0; } +bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, + size_t* shared_bytes) const { + return GetMemoryBytes(private_bytes, shared_bytes, nullptr, nullptr); +} + // This is a rough approximation of the algorithm that libtop uses. // private_bytes is the size of private resident memory. // shared_bytes is the size of shared resident memory. bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { + size_t* shared_bytes, + size_t* resident_bytes, + size_t* locked_bytes) const { size_t private_pages_count = 0; size_t shared_pages_count = 0; - - if (!private_bytes && !shared_bytes) - return true; + size_t wired_pages_count = 0; mach_port_t task = TaskForPid(process_); if (task == MACH_PORT_NULL) { @@ -157,29 +185,31 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, // See libtop_update_vm_regions in // http://www.opensource.apple.com/source/top/top-67/libtop.c mach_vm_size_t size = 0; - for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { + mach_vm_address_t address = MACH_VM_MIN_ADDRESS; + while (true) { + base::CheckedNumeric<mach_vm_address_t> next_address(address); + next_address += size; + if (!next_address.IsValid()) + return false; + address = next_address.ValueOrDie(); + + mach_vm_address_t address_copy = address; vm_region_top_info_data_t info; - mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; - mach_port_t object_name; - kern_return_t kr = mach_vm_region(task, - &address, - &size, - VM_REGION_TOP_INFO, - reinterpret_cast<vm_region_info_t>(&info), - &info_count, - &object_name); - if (kr == KERN_INVALID_ADDRESS) { - // We're at the end of the address space. + MachVMRegionResult result = GetTopInfo(task, &size, &address, &info); + if (result == MachVMRegionResult::Error) + return false; + if (result == MachVMRegionResult::Finished) break; - } else if (kr != KERN_SUCCESS) { - MACH_DLOG(ERROR, kr) << "mach_vm_region"; + + vm_region_basic_info_64 basic_info; + mach_vm_size_t dummy_size = 0; + result = GetBasicInfo(task, &dummy_size, &address_copy, &basic_info); + if (result == MachVMRegionResult::Error) return false; - } + if (result == MachVMRegionResult::Finished) + break; - // The kernel always returns a null object for VM_REGION_TOP_INFO, but - // balance it with a deallocate in case this ever changes. See 10.9.2 - // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region. - mach_port_deallocate(mach_task_self(), object_name); + bool is_wired = basic_info.user_wired_count > 0; if (IsAddressInSharedRegion(address, cpu_type) && info.share_mode != SM_PRIVATE) @@ -189,6 +219,7 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, info.share_mode = SM_PRIVATE; switch (info.share_mode) { + case SM_LARGE_PAGE: case SM_PRIVATE: private_pages_count += info.private_pages_resident; private_pages_count += info.shared_pages_resident; @@ -197,6 +228,9 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, private_pages_count += info.private_pages_resident; // Fall through case SM_SHARED: + case SM_PRIVATE_ALIASED: + case SM_TRUESHARED: + case SM_SHARED_ALIASED: if (seen_objects.count(info.obj_id) == 0) { // Only count the first reference to this region. seen_objects.insert(info.obj_id); @@ -206,12 +240,20 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, default: break; } + if (is_wired) { + wired_pages_count += + info.private_pages_resident + info.shared_pages_resident; + } } if (private_bytes) *private_bytes = private_pages_count * PAGE_SIZE; if (shared_bytes) *shared_bytes = shared_pages_count * PAGE_SIZE; + if (resident_bytes) + *resident_bytes = (private_pages_count + shared_pages_count) * PAGE_SIZE; + if (locked_bytes) + *locked_bytes = wired_pages_count * PAGE_SIZE; return true; } @@ -246,6 +288,20 @@ bool ProcessMetrics::GetCommittedAndWorkingSetKBytes( return true; } +size_t ProcessMetrics::GetPhysicalFootprint() const { + if (mac::IsAtMostOS10_11()) + return 0; + + ChromeTaskVMInfo task_vm_info; + mach_msg_type_number_t count = ChromeTaskVMInfoCount; + kern_return_t result = + task_info(TaskForPid(process_), TASK_VM_INFO, + reinterpret_cast<task_info_t>(&task_vm_info), &count); + if (result != KERN_SUCCESS) + return 0; + return task_vm_info.phys_footprint; +} + #define TIME_VALUE_TO_TIMEVAL(a, r) do { \ (r)->tv_sec = (a)->seconds; \ (r)->tv_usec = (a)->microseconds; \ @@ -377,7 +433,6 @@ size_t GetSystemCommitCharge() { return (data.active_count * PAGE_SIZE) / 1024; } -// On Mac, We only get total memory and free memory from the system. bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { struct host_basic_info hostinfo; mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; @@ -390,19 +445,61 @@ bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); meminfo->total = static_cast<int>(hostinfo.max_mem / 1024); - vm_statistics_data_t vm_info; - count = HOST_VM_INFO_COUNT; + vm_statistics64_data_t vm_info; + count = HOST_VM_INFO64_COUNT; - if (host_statistics(host.get(), HOST_VM_INFO, - reinterpret_cast<host_info_t>(&vm_info), - &count) != KERN_SUCCESS) { + if (host_statistics64(host.get(), HOST_VM_INFO64, + reinterpret_cast<host_info64_t>(&vm_info), + &count) != KERN_SUCCESS) { return false; } - - meminfo->free = static_cast<int>( - (vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE / 1024); + DCHECK_EQ(HOST_VM_INFO64_COUNT, count); + + static_assert(PAGE_SIZE % 1024 == 0, "Invalid page size"); + meminfo->free = saturated_cast<int>( + PAGE_SIZE / 1024 * (vm_info.free_count - vm_info.speculative_count)); + meminfo->speculative = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.speculative_count); + meminfo->file_backed = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.external_page_count); + meminfo->purgeable = + saturated_cast<int>(PAGE_SIZE / 1024 * vm_info.purgeable_count); return true; } +// Both |size| and |address| are in-out parameters. +// |info| is an output parameter, only valid on Success. +MachVMRegionResult GetTopInfo(mach_port_t task, + mach_vm_size_t* size, + mach_vm_address_t* address, + vm_region_top_info_data_t* info) { + mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; + mach_port_t object_name; + kern_return_t kr = mach_vm_region(task, address, size, VM_REGION_TOP_INFO, + reinterpret_cast<vm_region_info_t>(info), + &info_count, &object_name); + // The kernel always returns a null object for VM_REGION_TOP_INFO, but + // balance it with a deallocate in case this ever changes. See 10.9.2 + // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region. + mach_port_deallocate(task, object_name); + return ParseOutputFromMachVMRegion(kr); +} + +MachVMRegionResult GetBasicInfo(mach_port_t task, + mach_vm_size_t* size, + mach_vm_address_t* address, + vm_region_basic_info_64* info) { + mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + kern_return_t kr = mach_vm_region( + task, address, size, VM_REGION_BASIC_INFO_64, + reinterpret_cast<vm_region_info_t>(info), &info_count, &object_name); + // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but + // balance it with a deallocate in case this ever changes. See 10.9.2 + // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region. + mach_port_deallocate(task, object_name); + return ParseOutputFromMachVMRegion(kr); +} + } // namespace base diff --git a/chromium/base/process/process_metrics_openbsd.cc b/chromium/base/process/process_metrics_openbsd.cc index 58033aef62e..d8fbe7e3710 100644 --- a/chromium/base/process/process_metrics_openbsd.cc +++ b/chromium/base/process/process_metrics_openbsd.cc @@ -64,7 +64,7 @@ size_t ProcessMetrics::GetPeakWorkingSetSize() const { } bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { + size_t* shared_bytes) const { WorkingSetKBytes ws_usage; if (!GetWorkingSetKBytes(&ws_usage)) diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc index 3e059b48a45..8abdb264075 100644 --- a/chromium/base/process/process_metrics_unittest.cc +++ b/chromium/base/process/process_metrics_unittest.cc @@ -17,12 +17,17 @@ #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h" +#include "base/sys_info.h" #include "base/test/multiprocess_test.h" #include "base/threading/thread.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" +#if defined(OS_MACOSX) +#include <sys/mman.h> +#endif + namespace base { namespace debug { @@ -52,6 +57,42 @@ class SystemMetricsTest : public testing::Test { ///////////////////////////////////////////////////////////////////////////// +#if defined(OS_MACOSX) && !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) +TEST_F(SystemMetricsTest, LockedBytes) { + ProcessHandle handle = GetCurrentProcessHandle(); + std::unique_ptr<ProcessMetrics> metrics( + ProcessMetrics::CreateProcessMetrics(handle, nullptr)); + + size_t initial_locked_bytes; + bool result = + metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &initial_locked_bytes); + ASSERT_TRUE(result); + + size_t size = 8 * 1024 * 1024; + std::unique_ptr<char[]> memory(new char[size]); + int r = mlock(memory.get(), size); + ASSERT_EQ(0, r); + + size_t new_locked_bytes; + result = + metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &new_locked_bytes); + ASSERT_TRUE(result); + + // There should be around |size| more locked bytes, but multi-threading might + // cause noise. + EXPECT_LT(initial_locked_bytes + size / 2, new_locked_bytes); + EXPECT_GT(initial_locked_bytes + size * 1.5, new_locked_bytes); + + r = munlock(memory.get(), size); + ASSERT_EQ(0, r); + + result = + metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &new_locked_bytes); + ASSERT_TRUE(result); + EXPECT_EQ(initial_locked_bytes, new_locked_bytes); +} +#endif // defined(OS_MACOSX) && !defined(OS_IOS) && !defined(ADDRESS_SANITIZER) + #if defined(OS_LINUX) || defined(OS_ANDROID) TEST_F(SystemMetricsTest, IsValidDiskName) { std::string invalid_input1 = ""; @@ -106,6 +147,7 @@ TEST_F(SystemMetricsTest, ParseMeminfo) { std::string valid_input1 = "MemTotal: 3981504 kB\n" "MemFree: 140764 kB\n" + "MemAvailable: 535413 kB\n" "Buffers: 116480 kB\n" "Cached: 406160 kB\n" "SwapCached: 21304 kB\n" @@ -171,6 +213,7 @@ TEST_F(SystemMetricsTest, ParseMeminfo) { EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo)); EXPECT_EQ(meminfo.total, 3981504); EXPECT_EQ(meminfo.free, 140764); + EXPECT_EQ(meminfo.available, 535413); EXPECT_EQ(meminfo.buffers, 116480); EXPECT_EQ(meminfo.cached, 406160); EXPECT_EQ(meminfo.active_anon, 2972352); @@ -180,18 +223,29 @@ TEST_F(SystemMetricsTest, ParseMeminfo) { EXPECT_EQ(meminfo.swap_total, 5832280); EXPECT_EQ(meminfo.swap_free, 3672368); EXPECT_EQ(meminfo.dirty, 184); + EXPECT_EQ(meminfo.reclaimable, 30936); #if defined(OS_CHROMEOS) EXPECT_EQ(meminfo.shmem, 140204); EXPECT_EQ(meminfo.slab, 54212); #endif + EXPECT_EQ(355725, + base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); + // Simulate as if there is no MemAvailable. + meminfo.available = 0; + EXPECT_EQ(374448, + base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); + meminfo = {}; EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo)); EXPECT_EQ(meminfo.total, 255908); EXPECT_EQ(meminfo.free, 69936); + EXPECT_EQ(meminfo.available, 0); EXPECT_EQ(meminfo.buffers, 15812); EXPECT_EQ(meminfo.cached, 115124); EXPECT_EQ(meminfo.swap_total, 524280); EXPECT_EQ(meminfo.swap_free, 524200); EXPECT_EQ(meminfo.dirty, 4); + EXPECT_EQ(69936, + base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024); } TEST_F(SystemMetricsTest, ParseVmstat) { @@ -323,9 +377,9 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { std::vector<std::string> vec2; std::vector<std::string> vec3; - thread1.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec1)); - thread2.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec2)); - thread3.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec3)); + thread1.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec1)); + thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2)); + thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3)); EXPECT_GE(metrics->GetCPUUsage(), 0.0); @@ -341,15 +395,19 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) -#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \ - defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ + defined(OS_ANDROID) TEST(SystemMetrics2Test, GetSystemMemoryInfo) { SystemMemoryInfoKB info; EXPECT_TRUE(GetSystemMemoryInfo(&info)); // Ensure each field received a value. EXPECT_GT(info.total, 0); +#if defined(OS_WIN) + EXPECT_GT(info.avail_phys, 0); +#else EXPECT_GT(info.free, 0); +#endif #if defined(OS_LINUX) || defined(OS_ANDROID) EXPECT_GT(info.buffers, 0); EXPECT_GT(info.cached, 0); @@ -360,7 +418,10 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) { #endif // defined(OS_LINUX) || defined(OS_ANDROID) // All the values should be less than the total amount of memory. +#if !defined(OS_WIN) && !defined(OS_IOS) + // TODO(crbug.com/711450): re-enable the following assertion on iOS. EXPECT_LT(info.free, info.total); +#endif #if defined(OS_LINUX) || defined(OS_ANDROID) EXPECT_LT(info.buffers, info.total); EXPECT_LT(info.cached, info.total); @@ -370,6 +431,10 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) { EXPECT_LT(info.inactive_file, info.total); #endif // defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(OS_MACOSX) || defined(OS_IOS) + EXPECT_GT(info.file_backed, 0); +#endif + #if defined(OS_CHROMEOS) // Chrome OS exposes shmem. EXPECT_GT(info.shmem, 0); @@ -378,8 +443,8 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) { // and gem_size cannot be tested here. #endif } -#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || - // defined(OS_LINUX) || defined(OS_ANDROID) +#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || + // defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID) TEST(ProcessMetricsTest, ParseProcStatCPU) { @@ -491,15 +556,15 @@ TEST(ProcessMetricsTest, GetOpenFdCount) { const FilePath temp_path = temp_dir.GetPath(); CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine()); child_command_line.AppendSwitchPath(kTempDirFlag, temp_path); - Process child = SpawnMultiProcessTestChild( + SpawnChildResult spawn_child = SpawnMultiProcessTestChild( ChildMainString, child_command_line, LaunchOptions()); - ASSERT_TRUE(child.IsValid()); + ASSERT_TRUE(spawn_child.process.IsValid()); WaitForEvent(temp_path, kSignalClosed); std::unique_ptr<ProcessMetrics> metrics( - ProcessMetrics::CreateProcessMetrics(child.Handle())); + ProcessMetrics::CreateProcessMetrics(spawn_child.process.Handle())); EXPECT_EQ(0, metrics->GetOpenFdCount()); - ASSERT_TRUE(child.Terminate(0, true)); + ASSERT_TRUE(spawn_child.process.Terminate(0, true)); } #endif // defined(OS_LINUX) diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc index d2f0c935531..f5b191dfc08 100644 --- a/chromium/base/process/process_metrics_win.cc +++ b/chromium/base/process/process_metrics_win.cc @@ -31,12 +31,6 @@ typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() - : total(0), free(0), swap_total(0), swap_free(0) {} - -SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = - default; - ProcessMetrics::~ProcessMetrics() { } // static @@ -47,7 +41,7 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( size_t ProcessMetrics::GetPagefileUsage() const { PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { + if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { return pmc.PagefileUsage; } return 0; @@ -56,7 +50,7 @@ size_t ProcessMetrics::GetPagefileUsage() const { // Returns the peak space allocated for the pagefile, in bytes. size_t ProcessMetrics::GetPeakPagefileUsage() const { PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { + if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { return pmc.PeakPagefileUsage; } return 0; @@ -65,7 +59,7 @@ size_t ProcessMetrics::GetPeakPagefileUsage() const { // Returns the current working set size, in bytes. size_t ProcessMetrics::GetWorkingSetSize() const { PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { + if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { return pmc.WorkingSetSize; } return 0; @@ -74,21 +68,21 @@ size_t ProcessMetrics::GetWorkingSetSize() const { // Returns the peak working set size, in bytes. size_t ProcessMetrics::GetPeakWorkingSetSize() const { PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { + if (GetProcessMemoryInfo(process_.Get(), &pmc, sizeof(pmc))) { return pmc.PeakWorkingSetSize; } return 0; } bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { + size_t* shared_bytes) const { // 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 (private_bytes && - GetProcessMemoryInfo(process_, + GetProcessMemoryInfo(process_.Get(), reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx), sizeof(pmcx))) { *private_bytes = pmcx.PrivateUsage; @@ -111,8 +105,8 @@ void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { size_t committed_mapped = 0; size_t committed_image = 0; void* base_address = NULL; - while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) == - sizeof(mbi)) { + while (VirtualQueryEx(process_.Get(), base_address, &mbi, sizeof(mbi)) == + sizeof(mbi)) { if (mbi.State == MEM_COMMIT) { if (mbi.Type == MEM_PRIVATE) { committed_private += mbi.RegionSize; @@ -160,7 +154,7 @@ class WorkingSetInformationBuffer { size_t GetPageEntryCount() const { return number_of_entries; } // This function is used to get page entries for a process. - bool QueryPageEntries(const ProcessHandle& process_) { + bool QueryPageEntries(const ProcessHandle& process) { int retries = 5; number_of_entries = 4096; // Just a guess. @@ -173,9 +167,9 @@ class WorkingSetInformationBuffer { return false; // On success, |buffer_| is populated with info about the working set of - // |process_|. On ERROR_BAD_LENGTH failure, increase the size of the + // |process|. On ERROR_BAD_LENGTH failure, increase the size of the // buffer and try again. - if (QueryWorkingSet(process_, buffer_, buffer_size)) + if (QueryWorkingSet(process, buffer_, buffer_size)) break; // Success if (GetLastError() != ERROR_BAD_LENGTH) @@ -232,7 +226,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { memset(ws_usage, 0, sizeof(*ws_usage)); WorkingSetInformationBuffer buffer; - if (!buffer.QueryPageEntries(process_)) + if (!buffer.QueryPageEntries(process_.Get())) return false; size_t num_page_entries = buffer.GetPageEntryCount(); @@ -258,7 +252,7 @@ bool ProcessMetrics::GetProportionalSetSizeBytes(uint64_t* pss_bytes) const { double ws_pss = 0.0; WorkingSetInformationBuffer buffer; - if (!buffer.QueryPageEntries(process_)) + if (!buffer.QueryPageEntries(process_.Get())) return false; size_t num_page_entries = buffer.GetPageEntryCount(); @@ -287,8 +281,8 @@ double ProcessMetrics::GetCPUUsage() { FILETIME kernel_time; FILETIME user_time; - if (!GetProcessTimes(process_, &creation_time, &exit_time, - &kernel_time, &user_time)) { + if (!GetProcessTimes(process_.Get(), &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. @@ -321,13 +315,20 @@ double ProcessMetrics::GetCPUUsage() { } bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - return GetProcessIoCounters(process_, io_counters) != FALSE; + return GetProcessIoCounters(process_.Get(), io_counters) != FALSE; } ProcessMetrics::ProcessMetrics(ProcessHandle process) - : process_(process), - processor_count_(SysInfo::NumberOfProcessors()), - last_system_time_(0) {} + : processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0) { + if (process) { + HANDLE duplicate_handle; + BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process, + ::GetCurrentProcess(), &duplicate_handle, + PROCESS_QUERY_INFORMATION, FALSE, 0); + DCHECK(result); + process_.Set(duplicate_handle); + } +} size_t GetSystemCommitCharge() { // Get the System Page Size. @@ -349,7 +350,7 @@ size_t GetPageSize() { // This function uses the following mapping between MEMORYSTATUSEX and // SystemMemoryInfoKB: // ullTotalPhys ==> total -// ullAvailPhys ==> free +// ullAvailPhys ==> avail_phys // ullTotalPageFile ==> swap_total // ullAvailPageFile ==> swap_free bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { @@ -359,7 +360,7 @@ bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { return false; meminfo->total = mem_status.ullTotalPhys / 1024; - meminfo->free = mem_status.ullAvailPhys / 1024; + meminfo->avail_phys = mem_status.ullAvailPhys / 1024; meminfo->swap_total = mem_status.ullTotalPageFile / 1024; meminfo->swap_free = mem_status.ullAvailPageFile / 1024; diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc index 9b94891dd96..bbb342c4cf4 100644 --- a/chromium/base/process/process_posix.cc +++ b/chromium/base/process/process_posix.cc @@ -225,7 +225,6 @@ Process::Process(Process&& other) : process_(other.process_) { } Process& Process::operator=(Process&& other) { - DCHECK_NE(this, &other); process_ = other.process_; other.Close(); return *this; diff --git a/chromium/base/process/process_unittest.cc b/chromium/base/process/process_unittest.cc index 619d22b5d95..839ec1359ff 100644 --- a/chromium/base/process/process_unittest.cc +++ b/chromium/base/process/process_unittest.cc @@ -42,11 +42,11 @@ class ProcessTest : public MultiProcessTest { }; TEST_F(ProcessTest, Create) { - Process process(SpawnChild("SimpleChildProcess")); - ASSERT_TRUE(process.IsValid()); - ASSERT_FALSE(process.is_current()); - process.Close(); - ASSERT_FALSE(process.IsValid()); + SpawnChildResult spawn_child = SpawnChild("SimpleChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); + ASSERT_FALSE(spawn_child.process.is_current()); + spawn_child.process.Close(); + ASSERT_FALSE(spawn_child.process.IsValid()); } TEST_F(ProcessTest, CreateCurrent) { @@ -58,7 +58,8 @@ TEST_F(ProcessTest, CreateCurrent) { } TEST_F(ProcessTest, Move) { - Process process1(SpawnChild("SimpleChildProcess")); + SpawnChildResult spawn_result = SpawnChild("SimpleChildProcess"); + Process& process1 = spawn_result.process; EXPECT_TRUE(process1.IsValid()); Process process2; @@ -77,7 +78,8 @@ TEST_F(ProcessTest, Move) { } TEST_F(ProcessTest, Duplicate) { - Process process1(SpawnChild("SimpleChildProcess")); + SpawnChildResult spawn_result = SpawnChild("SimpleChildProcess"); + Process& process1 = spawn_result.process; ASSERT_TRUE(process1.IsValid()); Process process2 = process1.Duplicate(); @@ -107,7 +109,8 @@ TEST_F(ProcessTest, DuplicateCurrent) { } TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) { - Process process1(SpawnChild("SimpleChildProcess")); + SpawnChildResult spawn_result = SpawnChild("SimpleChildProcess"); + Process& process1 = spawn_result.process; ASSERT_TRUE(process1.IsValid()); Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle()); @@ -127,7 +130,8 @@ MULTIPROCESS_TEST_MAIN(SleepyChildProcess) { } TEST_F(ProcessTest, Terminate) { - Process process(SpawnChild("SleepyChildProcess")); + SpawnChildResult spawn_result = SpawnChild("SleepyChildProcess"); + Process& process = spawn_result.process; ASSERT_TRUE(process.IsValid()); const int kDummyExitCode = 42; @@ -173,11 +177,12 @@ MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode0) { } TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithZeroExitCode) { - Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode0")); - ASSERT_TRUE(process.IsValid()); + SpawnChildResult spawn_child = + SpawnChild("TerminateCurrentProcessImmediatelyWithCode0"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); + ASSERT_TRUE(spawn_child.process.WaitForExitWithTimeout( + TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(0, exit_code); } @@ -188,11 +193,12 @@ MULTIPROCESS_TEST_MAIN(TerminateCurrentProcessImmediatelyWithCode250) { } TEST_F(ProcessTest, TerminateCurrentProcessImmediatelyWithNonZeroExitCode) { - Process process(SpawnChild("TerminateCurrentProcessImmediatelyWithCode250")); - ASSERT_TRUE(process.IsValid()); + SpawnChildResult spawn_child = + SpawnChild("TerminateCurrentProcessImmediatelyWithCode250"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(), - &exit_code)); + ASSERT_TRUE(spawn_child.process.WaitForExitWithTimeout( + TestTimeouts::action_max_timeout(), &exit_code)); EXPECT_EQ(250, exit_code); } @@ -202,26 +208,26 @@ MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) { } TEST_F(ProcessTest, WaitForExit) { - Process process(SpawnChild("FastSleepyChildProcess")); - ASSERT_TRUE(process.IsValid()); + SpawnChildResult spawn_child = SpawnChild("FastSleepyChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); const int kDummyExitCode = 42; int exit_code = kDummyExitCode; - EXPECT_TRUE(process.WaitForExit(&exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExit(&exit_code)); EXPECT_EQ(0, exit_code); } TEST_F(ProcessTest, WaitForExitWithTimeout) { - Process process(SpawnChild("SleepyChildProcess")); - ASSERT_TRUE(process.IsValid()); + SpawnChildResult spawn_child = SpawnChild("SleepyChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); const int kDummyExitCode = 42; int exit_code = kDummyExitCode; TimeDelta timeout = TestTimeouts::tiny_timeout(); - EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code)); + EXPECT_FALSE(spawn_child.process.WaitForExitWithTimeout(timeout, &exit_code)); EXPECT_EQ(kDummyExitCode, exit_code); - process.Terminate(kDummyExitCode, false); + spawn_child.process.Terminate(kDummyExitCode, false); } // Ensure that the priority of a process is restored correctly after @@ -231,13 +237,13 @@ TEST_F(ProcessTest, WaitForExitWithTimeout) { TEST_F(ProcessTest, SetProcessBackgrounded) { if (!Process::CanBackgroundProcesses()) return; - Process process(SpawnChild("SimpleChildProcess")); - int old_priority = process.GetPriority(); + SpawnChildResult spawn_child = SpawnChild("SimpleChildProcess"); + int old_priority = spawn_child.process.GetPriority(); #if defined(OS_WIN) - EXPECT_TRUE(process.SetProcessBackgrounded(true)); - EXPECT_TRUE(process.IsProcessBackgrounded()); - EXPECT_TRUE(process.SetProcessBackgrounded(false)); - EXPECT_FALSE(process.IsProcessBackgrounded()); + EXPECT_TRUE(spawn_child.process.SetProcessBackgrounded(true)); + EXPECT_TRUE(spawn_child.process.IsProcessBackgrounded()); + EXPECT_TRUE(spawn_child.process.SetProcessBackgrounded(false)); + EXPECT_FALSE(spawn_child.process.IsProcessBackgrounded()); #elif defined(OS_MACOSX) // On the Mac, backgrounding a process requires a port to that process. // In the browser it's available through the MachBroker class, which is not @@ -246,16 +252,16 @@ TEST_F(ProcessTest, SetProcessBackgrounded) { // the ability to background/foreground a process, we can use the current // process's port instead. FakePortProvider provider; - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, true)); - EXPECT_TRUE(process.IsProcessBackgrounded(&provider)); - EXPECT_TRUE(process.SetProcessBackgrounded(&provider, false)); - EXPECT_FALSE(process.IsProcessBackgrounded(&provider)); + EXPECT_TRUE(spawn_child.process.SetProcessBackgrounded(&provider, true)); + EXPECT_TRUE(spawn_child.process.IsProcessBackgrounded(&provider)); + EXPECT_TRUE(spawn_child.process.SetProcessBackgrounded(&provider, false)); + EXPECT_FALSE(spawn_child.process.IsProcessBackgrounded(&provider)); #else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); + spawn_child.process.SetProcessBackgrounded(true); + spawn_child.process.SetProcessBackgrounded(false); #endif - int new_priority = process.GetPriority(); + int new_priority = spawn_child.process.GetPriority(); EXPECT_EQ(old_priority, new_priority); } diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc index 7031706e0b7..3f28b89b827 100644 --- a/chromium/base/process/process_util_unittest.cc +++ b/chromium/base/process/process_util_unittest.cc @@ -160,11 +160,11 @@ MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { // TODO(viettrungluu): This should be in a "MultiProcessTestTest". TEST_F(ProcessUtilTest, SpawnChild) { - base::Process process = SpawnChild("SimpleChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("SimpleChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code; - EXPECT_TRUE(process.WaitForExitWithTimeout( - TestTimeouts::action_max_timeout(), &exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExitWithTimeout( + TestTimeouts::action_max_timeout(), &exit_code)); } MULTIPROCESS_TEST_MAIN(SlowChildProcess) { @@ -176,12 +176,12 @@ TEST_F(ProcessUtilTest, KillSlowChild) { const std::string signal_file = ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); remove(signal_file.c_str()); - base::Process process = SpawnChild("SlowChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("SlowChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); SignalChildren(signal_file.c_str()); int exit_code; - EXPECT_TRUE(process.WaitForExitWithTimeout( - TestTimeouts::action_max_timeout(), &exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExitWithTimeout( + TestTimeouts::action_max_timeout(), &exit_code)); remove(signal_file.c_str()); } @@ -190,18 +190,19 @@ TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) { const std::string signal_file = ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); remove(signal_file.c_str()); - base::Process process = SpawnChild("SlowChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("SlowChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(process.Handle(), &exit_code)); + EXPECT_EQ( + base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(spawn_child.process.Handle(), &exit_code)); EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); SignalChildren(signal_file.c_str()); exit_code = 42; base::TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); + WaitForChildTermination(spawn_child.process.Handle(), &exit_code); EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status); EXPECT_EQ(kSuccess, exit_code); remove(signal_file.c_str()); @@ -235,11 +236,12 @@ TEST_F(ProcessUtilTest, CurrentDirectory) { base::LaunchOptions options; options.current_directory = tmp_dir; - base::Process process(SpawnChildWithOptions("CheckCwdProcess", options)); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = + SpawnChildWithOptions("CheckCwdProcess", options); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExit(&exit_code)); EXPECT_EQ(kSuccess, exit_code); } #endif // !defined(OS_ANDROID) @@ -249,9 +251,9 @@ TEST_F(ProcessUtilTest, CurrentDirectory) { TEST_F(ProcessUtilTest, GetProcId) { base::ProcessId id1 = base::GetProcId(GetCurrentProcess()); EXPECT_NE(0ul, id1); - base::Process process = SpawnChild("SimpleChildProcess"); - ASSERT_TRUE(process.IsValid()); - base::ProcessId id2 = process.Pid(); + base::SpawnChildResult spawn_child = SpawnChild("SimpleChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); + base::ProcessId id2 = spawn_child.process.Pid(); EXPECT_NE(0ul, id2); EXPECT_NE(id1, id2); } @@ -295,18 +297,19 @@ TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) { const std::string signal_file = ProcessUtilTest::GetSignalFilePath(kSignalFileCrash); remove(signal_file.c_str()); - base::Process process = SpawnChild("CrashingChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("CrashingChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(process.Handle(), &exit_code)); + EXPECT_EQ( + base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(spawn_child.process.Handle(), &exit_code)); EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); SignalChildren(signal_file.c_str()); exit_code = 42; base::TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); + WaitForChildTermination(spawn_child.process.Handle(), &exit_code); EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); #if defined(OS_WIN) @@ -350,18 +353,19 @@ TEST_F(ProcessUtilTest, GetTerminationStatusSigKill) { const std::string signal_file = ProcessUtilTest::GetSignalFilePath(kSignalFileKill); remove(signal_file.c_str()); - base::Process process = SpawnChild("KilledChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("KilledChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(process.Handle(), &exit_code)); + EXPECT_EQ( + base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(spawn_child.process.Handle(), &exit_code)); EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); SignalChildren(signal_file.c_str()); exit_code = 42; base::TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); + WaitForChildTermination(spawn_child.process.Handle(), &exit_code); #if defined(OS_CHROMEOS) EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status); #else @@ -384,18 +388,19 @@ TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) { const std::string signal_file = ProcessUtilTest::GetSignalFilePath(kSignalFileTerm); remove(signal_file.c_str()); - base::Process process = SpawnChild("TerminatedChildProcess"); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = SpawnChild("TerminatedChildProcess"); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(process.Handle(), &exit_code)); + EXPECT_EQ( + base::TERMINATION_STATUS_STILL_RUNNING, + base::GetTerminationStatus(spawn_child.process.Handle(), &exit_code)); EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); SignalChildren(signal_file.c_str()); exit_code = 42; base::TerminationStatus status = - WaitForChildTermination(process.Handle(), &exit_code); + WaitForChildTermination(spawn_child.process.Handle(), &exit_code); EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); int signaled = WIFSIGNALED(exit_code); @@ -627,9 +632,9 @@ int ProcessUtilTest::CountOpenFDsInChild() { fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe)); base::LaunchOptions options; options.fds_to_remap = &fd_mapping_vec; - base::Process process = + base::SpawnChildResult spawn_child = SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options); - CHECK(process.IsValid()); + CHECK(spawn_child.process.IsValid()); int ret = IGNORE_EINTR(close(fds[1])); DPCHECK(ret == 0); @@ -646,7 +651,7 @@ int ProcessUtilTest::CountOpenFDsInChild() { base::TimeDelta timeout = base::TimeDelta::FromSeconds(1); #endif int exit_code; - CHECK(process.WaitForExitWithTimeout(timeout, &exit_code)); + CHECK(spawn_child.process.WaitForExitWithTimeout(timeout, &exit_code)); ret = IGNORE_EINTR(close(fds[0])); DPCHECK(ret == 0); @@ -869,15 +874,16 @@ bool IsProcessDead(base::ProcessHandle child) { } TEST_F(ProcessUtilTest, DelayedTermination) { - base::Process child_process = SpawnChild("process_util_test_never_die"); - ASSERT_TRUE(child_process.IsValid()); - base::EnsureProcessTerminated(child_process.Duplicate()); + base::SpawnChildResult spawn_child = + SpawnChild("process_util_test_never_die"); + ASSERT_TRUE(spawn_child.process.IsValid()); + base::EnsureProcessTerminated(spawn_child.process.Duplicate()); int exit_code; - child_process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5), - &exit_code); + spawn_child.process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5), + &exit_code); // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process.Handle())); + EXPECT_TRUE(IsProcessDead(spawn_child.process.Handle())); } MULTIPROCESS_TEST_MAIN(process_util_test_never_die) { @@ -888,14 +894,15 @@ MULTIPROCESS_TEST_MAIN(process_util_test_never_die) { } TEST_F(ProcessUtilTest, ImmediateTermination) { - base::Process child_process = SpawnChild("process_util_test_die_immediately"); - ASSERT_TRUE(child_process.IsValid()); + base::SpawnChildResult spawn_child = + SpawnChild("process_util_test_die_immediately"); + ASSERT_TRUE(spawn_child.process.IsValid()); // Give it time to die. sleep(2); - base::EnsureProcessTerminated(child_process.Duplicate()); + base::EnsureProcessTerminated(spawn_child.process.Duplicate()); // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process.Handle())); + EXPECT_TRUE(IsProcessDead(spawn_child.process.Handle())); } MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) { @@ -934,14 +941,15 @@ TEST_F(ProcessUtilTest, PreExecHook) { base::LaunchOptions options; options.fds_to_remap = &fds_to_remap; options.pre_exec_delegate = &read_from_pipe_delegate; - base::Process process(SpawnChildWithOptions("SimpleChildProcess", options)); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = + SpawnChildWithOptions("SimpleChildProcess", options); + ASSERT_TRUE(spawn_child.process.IsValid()); read_fd.reset(); ASSERT_EQ(1, HANDLE_EINTR(write(write_fd.get(), &kPipeValue, 1))); int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExit(&exit_code)); EXPECT_EQ(0, exit_code); } #endif // !defined(OS_ANDROID) @@ -969,11 +977,12 @@ TEST_F(ProcessUtilTest, CloneFlags) { base::LaunchOptions options; options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID; - base::Process process(SpawnChildWithOptions("CheckPidProcess", options)); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = + SpawnChildWithOptions("CheckPidProcess", options); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = 42; - EXPECT_TRUE(process.WaitForExit(&exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExit(&exit_code)); EXPECT_EQ(kSuccess, exit_code); } #endif // defined(CLONE_NEWUSER) && defined(CLONE_NEWPID) @@ -1010,11 +1019,12 @@ TEST_F(ProcessUtilTest, InvalidCurrentDirectory) { base::LaunchOptions options; options.current_directory = base::FilePath("/dev/null"); - base::Process process(SpawnChildWithOptions("SimpleChildProcess", options)); - ASSERT_TRUE(process.IsValid()); + base::SpawnChildResult spawn_child = + SpawnChildWithOptions("SimpleChildProcess", options); + ASSERT_TRUE(spawn_child.process.IsValid()); int exit_code = kSuccess; - EXPECT_TRUE(process.WaitForExit(&exit_code)); + EXPECT_TRUE(spawn_child.process.WaitForExit(&exit_code)); EXPECT_NE(kSuccess, exit_code); } #endif // defined(OS_LINUX) diff --git a/chromium/base/process/process_win.cc b/chromium/base/process/process_win.cc index 623212654ee..9232c6dbcac 100644 --- a/chromium/base/process/process_win.cc +++ b/chromium/base/process/process_win.cc @@ -139,6 +139,10 @@ bool Process::Terminate(int exit_code, bool wait) const { } else if (!result) { DPLOG(ERROR) << "Unable to terminate process"; } + if (result) { + base::debug::GlobalActivityTracker::RecordProcessExitIfEnabled(Pid(), + exit_code); + } return result; } @@ -162,6 +166,9 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const { if (exit_code) *exit_code = temp_code; + + base::debug::GlobalActivityTracker::RecordProcessExitIfEnabled( + Pid(), static_cast<int>(temp_code)); return true; } |