summaryrefslogtreecommitdiffstats
path: root/chromium/base/process
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/base/process
parentbb09965444b5bb20b096a291445170876225268d (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')
-rw-r--r--chromium/base/process/launch.h5
-rw-r--r--chromium/base/process/launch_posix.cc8
-rw-r--r--chromium/base/process/launch_win.cc12
-rw-r--r--chromium/base/process/memory_unittest.cc20
-rw-r--r--chromium/base/process/process_info_linux.cc6
-rw-r--r--chromium/base/process/process_info_unittest.cc20
-rw-r--r--chromium/base/process/process_linux.cc22
-rw-r--r--chromium/base/process/process_metrics.cc5
-rw-r--r--chromium/base/process/process_metrics.h142
-rw-r--r--chromium/base/process/process_metrics_freebsd.cc2
-rw-r--r--chromium/base/process/process_metrics_ios.cc44
-rw-r--r--chromium/base/process/process_metrics_linux.cc66
-rw-r--r--chromium/base/process/process_metrics_mac.cc211
-rw-r--r--chromium/base/process/process_metrics_openbsd.cc2
-rw-r--r--chromium/base/process/process_metrics_unittest.cc87
-rw-r--r--chromium/base/process/process_metrics_win.cc55
-rw-r--r--chromium/base/process/process_posix.cc1
-rw-r--r--chromium/base/process/process_unittest.cc80
-rw-r--r--chromium/base/process/process_util_unittest.cc122
-rw-r--r--chromium/base/process/process_win.cc7
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;
}