diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-04 14:17:57 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-05 10:05:06 +0000 |
commit | 39d357e3248f80abea0159765ff39554affb40db (patch) | |
tree | aba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/base/process | |
parent | 87778abf5a1f89266f37d1321b92a21851d8244d (diff) |
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2
Change-Id: I20d43c737f82764d857ada9a55586901b18b9243
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/base/process')
28 files changed, 322 insertions, 442 deletions
diff --git a/chromium/base/process/internal_linux.cc b/chromium/base/process/internal_linux.cc index d286f4e7539..e9ed641dc02 100644 --- a/chromium/base/process/internal_linux.cc +++ b/chromium/base/process/internal_linux.cc @@ -170,6 +170,32 @@ Time GetBootTime() { return Time::FromTimeT(btime); } +TimeDelta GetUserCpuTimeSinceBoot() { + FilePath path("/proc/stat"); + std::string contents; + if (!ReadProcFile(path, &contents)) + return TimeDelta(); + + ProcStatMap proc_stat; + ParseProcStat(contents, &proc_stat); + ProcStatMap::const_iterator cpu_it = proc_stat.find("cpu"); + if (cpu_it == proc_stat.end()) + return TimeDelta(); + + std::vector<std::string> cpu = SplitString( + cpu_it->second, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + + if (cpu.size() < 2 || cpu[0] != "cpu") + return TimeDelta(); + + uint64_t user; + uint64_t nice; + if (!StringToUint64(cpu[0], &user) || !StringToUint64(cpu[1], &nice)) + return TimeDelta(); + + return ClockTicksToTimeDelta(user + nice); +} + TimeDelta ClockTicksToTimeDelta(int clock_ticks) { // This queries the /proc-specific scaling factor which is // conceptually the system hertz. To dump this value on another diff --git a/chromium/base/process/internal_linux.h b/chromium/base/process/internal_linux.h index ba793f7cc7c..b36f75a90af 100644 --- a/chromium/base/process/internal_linux.h +++ b/chromium/base/process/internal_linux.h @@ -83,6 +83,9 @@ size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, // Returns the time that the OS started. Clock ticks are relative to this. Time GetBootTime(); +// Returns the amount of time spent in user space since boot across all CPUs. +TimeDelta GetUserCpuTimeSinceBoot(); + // Converts Linux clock ticks to a wall time delta. TimeDelta ClockTicksToTimeDelta(int clock_ticks); diff --git a/chromium/base/process/kill.h b/chromium/base/process/kill.h index c664f33262f..6d410e02a0d 100644 --- a/chromium/base/process/kill.h +++ b/chromium/base/process/kill.h @@ -18,6 +18,16 @@ namespace base { class ProcessFilter; +#if defined(OS_WIN) +namespace win { + +// See definition in sandbox/win/src/sandbox_types.h +const DWORD kSandboxFatalMemoryExceeded = 7012; + +} // namespace win + +#endif // OS_WIN + // Return status values from GetTerminationStatus. Don't use these as // exit code arguments to KillProcess*(), use platform/application // specific values instead. @@ -39,6 +49,7 @@ enum TerminationStatus { TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill #endif TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched + TERMINATION_STATUS_OOM, // Process died due to oom TERMINATION_STATUS_MAX_ENUM }; diff --git a/chromium/base/process/kill_posix.cc b/chromium/base/process/kill_posix.cc index 85470e05f97..4dc60ef2a24 100644 --- a/chromium/base/process/kill_posix.cc +++ b/chromium/base/process/kill_posix.cc @@ -52,6 +52,8 @@ TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, case SIGFPE: case SIGILL: case SIGSEGV: + case SIGTRAP: + case SIGSYS: return TERMINATION_STATUS_PROCESS_CRASHED; case SIGKILL: #if defined(OS_CHROMEOS) diff --git a/chromium/base/process/kill_win.cc b/chromium/base/process/kill_win.cc index 358590e7a38..ecb08421cfa 100644 --- a/chromium/base/process/kill_win.cc +++ b/chromium/base/process/kill_win.cc @@ -8,12 +8,14 @@ #include <io.h> #include <stdint.h> +#include <algorithm> #include <utility> #include "base/bind.h" #include "base/bind_helpers.h" #include "base/logging.h" #include "base/macros.h" +#include "base/process/memory.h" #include "base/process/process_iterator.h" #include "base/threading/thread_task_runner_handle.h" #include "base/win/object_watcher.h" @@ -146,6 +148,11 @@ TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { case kDebuggerTerminatedExitCode: // Debugger terminated process. case kProcessKilledExitCode: // Task manager kill. return TERMINATION_STATUS_PROCESS_WAS_KILLED; + case base::win::kSandboxFatalMemoryExceeded: // Terminated process due to + // exceeding the sandbox job + // object memory limits. + case base::win::kOomExceptionCode: // Ran out of memory. + return TERMINATION_STATUS_OOM; default: // All other exit codes indicate crashes. return TERMINATION_STATUS_PROCESS_CRASHED; diff --git a/chromium/base/process/launch.cc b/chromium/base/process/launch.cc index 3ca5155a122..c03e1a75db1 100644 --- a/chromium/base/process/launch.cc +++ b/chromium/base/process/launch.cc @@ -7,43 +7,11 @@ namespace base { -LaunchOptions::LaunchOptions() - : wait(false), -#if defined(OS_WIN) - start_hidden(false), - handles_to_inherit(NULL), - inherit_handles(false), - as_user(NULL), - empty_desktop_name(false), - job_handle(NULL), - stdin_handle(NULL), - stdout_handle(NULL), - stderr_handle(NULL), - force_breakaway_from_job_(false) -#else - clear_environ(false), - fds_to_remap(NULL), - maximize_rlimits(NULL), - new_process_group(false) -#if defined(OS_LINUX) - , clone_flags(0) - , allow_new_privs(false) - , kill_on_parent_death(false) -#endif // OS_LINUX -#if defined(OS_POSIX) - , pre_exec_delegate(NULL) -#endif // OS_POSIX -#if defined(OS_CHROMEOS) - , ctrl_terminal_fd(-1) -#endif // OS_CHROMEOS -#endif // !defined(OS_WIN) - { -} +LaunchOptions::LaunchOptions() = default; LaunchOptions::LaunchOptions(const LaunchOptions& other) = default; -LaunchOptions::~LaunchOptions() { -} +LaunchOptions::~LaunchOptions() = default; LaunchOptions LaunchOptionsForTest() { LaunchOptions options; diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h index 28cea7b931c..2b2040c7d42 100644 --- a/chromium/base/process/launch.h +++ b/chromium/base/process/launch.h @@ -63,17 +63,17 @@ struct BASE_EXPORT LaunchOptions { ~LaunchOptions(); // If true, wait for the process to complete. - bool wait; + bool wait = false; // If not empty, change to this directory before executing the new process. base::FilePath current_directory; #if defined(OS_WIN) - bool start_hidden; + bool start_hidden = false; // If non-null, inherit exactly the list of handles in this vector (these // handles must be inheritable). - HandlesToInheritVector* handles_to_inherit; + HandlesToInheritVector* handles_to_inherit = nullptr; // If true, the new process inherits handles from the parent. In production // code this flag should be used only when running short-lived, trusted @@ -81,7 +81,7 @@ struct BASE_EXPORT LaunchOptions { // leak to the child process, causing errors such as open socket hangs. // Note: If |handles_to_inherit| is non-null, this flag is ignored and only // those handles will be inherited. - bool inherit_handles; + bool inherit_handles = false; // If non-null, runs as if the user represented by the token had launched it. // Whether the application is visible on the interactive desktop depends on @@ -90,29 +90,29 @@ struct BASE_EXPORT LaunchOptions { // To avoid hard to diagnose problems, when specified this loads the // environment variables associated with the user and if this operation fails // the entire call fails as well. - UserTokenHandle as_user; + UserTokenHandle as_user = nullptr; // If true, use an empty string for the desktop name. - bool empty_desktop_name; + bool empty_desktop_name = false; // If non-null, launches the application in that job object. The process will // be terminated immediately and LaunchProcess() will fail if assignment to // the job object fails. - HANDLE job_handle; + HANDLE job_handle = nullptr; // Handles for the redirection of stdin, stdout and stderr. The handles must // be inheritable. Caller should either set all three of them or none (i.e. // there is no way to redirect stderr without redirecting stdin). The // |inherit_handles| flag must be set to true when redirecting stdio stream. - HANDLE stdin_handle; - HANDLE stdout_handle; - HANDLE stderr_handle; + HANDLE stdin_handle = nullptr; + HANDLE stdout_handle = nullptr; + HANDLE stderr_handle = nullptr; // If set to true, ensures that the child process is launched with the // CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent // job if any. - bool force_breakaway_from_job_; -#else + bool force_breakaway_from_job_ = false; +#else // !defined(OS_WIN) // Set/unset environment variables. These are applied on top of the parent // process environment. Empty (the default) means to inherit the same // environment. See AlterEnvironment(). @@ -120,53 +120,58 @@ struct BASE_EXPORT LaunchOptions { // Clear the environment for the new process before processing changes from // |environ|. - bool clear_environ; + bool clear_environ = false; // If non-null, remap file descriptors according to the mapping of // src fd->dest fd to propagate FDs into the child process. // This pointer is owned by the caller and must live through the // call to LaunchProcess(). - const FileHandleMappingVector* fds_to_remap; + const FileHandleMappingVector* fds_to_remap = nullptr; // Each element is an RLIMIT_* constant that should be raised to its // rlim_max. This pointer is owned by the caller and must live through // the call to LaunchProcess(). - const std::vector<int>* maximize_rlimits; + const std::vector<int>* maximize_rlimits = nullptr; // If true, start the process in a new process group, instead of // inheriting the parent's process group. The pgid of the child process // will be the same as its pid. - bool new_process_group; + bool new_process_group = false; #if defined(OS_LINUX) // If non-zero, start the process using clone(), using flags as provided. // Unlike in clone, clone_flags may not contain a custom termination signal // that is sent to the parent when the child dies. The termination signal will // always be set to SIGCHLD. - int clone_flags; + int clone_flags = 0; // By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If // true, then this bit will not be set in the new child process. - bool allow_new_privs; + bool allow_new_privs = false; // Sets parent process death signal to SIGKILL. - bool kill_on_parent_death; + bool kill_on_parent_death = false; #endif // defined(OS_LINUX) #if defined(OS_POSIX) + // If not empty, launch the specified executable instead of + // cmdline.GetProgram(). This is useful when it is necessary to pass a custom + // argv[0]. + base::FilePath real_path; + // If non-null, a delegate to be run immediately prior to executing the new // program in the child process. // // WARNING: If LaunchProcess is called in the presence of multiple threads, // code running in this delegate essentially needs to be async-signal safe // (see man 7 signal for a list of allowed functions). - PreExecDelegate* pre_exec_delegate; + PreExecDelegate* pre_exec_delegate = nullptr; #endif // defined(OS_POSIX) #if defined(OS_CHROMEOS) // If non-negative, the specified file descriptor will be set as the launched // process' controlling terminal. - int ctrl_terminal_fd; + int ctrl_terminal_fd = -1; #endif // defined(OS_CHROMEOS) #endif // !defined(OS_WIN) }; @@ -257,12 +262,6 @@ BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output); BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv, std::string* output); -// A restricted version of |GetAppOutput()| which (a) clears the environment, -// and (b) stores at most |max_output| bytes; also, it doesn't search the path -// for the command. -BASE_EXPORT bool GetAppOutputRestricted(const CommandLine& cl, - std::string* output, size_t max_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 99582f59cfc..e4560436251 100644 --- a/chromium/base/process/launch_posix.cc +++ b/chromium/base/process/launch_posix.cc @@ -152,12 +152,12 @@ int sys_rt_sigaction(int sig, const struct kernel_sigaction* act, // This function is intended to be used in between fork() and execve() and will // reset all signal handlers to the default. // The motivation for going through all of them is that sa_restorer can leak -// from parents and help defeat ASLR on buggy kernels. We reset it to NULL. +// from parents and help defeat ASLR on buggy kernels. We reset it to null. // See crbug.com/177956. void ResetChildSignalHandlersToDefaults(void) { for (int signum = 1; ; ++signum) { struct kernel_sigaction act = {0}; - int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act); + int sigaction_get_ret = sys_rt_sigaction(signum, nullptr, &act); if (sigaction_get_ret && errno == EINVAL) { #if !defined(NDEBUG) // Linux supports 32 real-time signals from 33 to 64. @@ -176,14 +176,14 @@ void ResetChildSignalHandlersToDefaults(void) { // The kernel won't allow to re-set SIGKILL or SIGSTOP. if (signum != SIGSTOP && signum != SIGKILL) { act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL); - act.k_sa_restorer = NULL; - if (sys_rt_sigaction(signum, &act, NULL)) { + act.k_sa_restorer = nullptr; + if (sys_rt_sigaction(signum, &act, nullptr)) { RAW_LOG(FATAL, "sigaction (set) failed."); } } #if !defined(NDEBUG) // Now ask the kernel again and check that no restorer will leak. - if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) { + if (sys_rt_sigaction(signum, nullptr, &act) || act.k_sa_restorer) { RAW_LOG(FATAL, "Cound not fix sa_restorer."); } #endif // !defined(NDEBUG) @@ -305,10 +305,10 @@ Process LaunchProcess(const std::vector<std::string>& argv, for (size_t i = 0; i < argv.size(); i++) { argv_cstr[i] = const_cast<char*>(argv[i].c_str()); } - argv_cstr[argv.size()] = NULL; + argv_cstr[argv.size()] = nullptr; std::unique_ptr<char* []> new_environ; - char* const empty_environ = NULL; + char* const empty_environ = nullptr; char* const* old_environ = GetEnvironment(); if (options.clear_environ) old_environ = &empty_environ; @@ -430,7 +430,7 @@ Process LaunchProcess(const std::vector<std::string>& argv, // Set process' controlling terminal. if (HANDLE_EINTR(setsid()) != -1) { if (HANDLE_EINTR( - ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { + ioctl(options.ctrl_terminal_fd, TIOCSCTTY, nullptr)) == -1) { RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); } } else { @@ -487,7 +487,10 @@ Process LaunchProcess(const std::vector<std::string>& argv, options.pre_exec_delegate->RunAsyncSafe(); } - execvp(argv_cstr[0], argv_cstr.get()); + const char* executable_path = !options.real_path.empty() ? + options.real_path.value().c_str() : argv_cstr[0]; + + execvp(executable_path, argv_cstr.get()); RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); RAW_LOG(ERROR, argv_cstr[0]); @@ -511,14 +514,6 @@ void RaiseProcessToHighPriority() { // setpriority() or sched_getscheduler, but these all require extra rights. } -// Return value used by GetAppOutputInternal to encapsulate the various exit -// scenarios from the function. -enum GetAppOutputInternalResult { - EXECUTE_FAILURE, - EXECUTE_SUCCESS, - GOT_MAX_OUTPUT, -}; - // Executes the application specified by |argv| and wait for it to exit. Stores // the output (stdout) in |output|. If |do_search_path| is set, it searches the // path for the application; in that case, |envp| must be null, and it will use @@ -526,21 +521,14 @@ enum GetAppOutputInternalResult { // specify the path of the application, and |envp| will be used as the // environment. If |include_stderr| is true, includes stderr otherwise redirects // it to /dev/null. -// If we successfully start the application and get all requested output, we -// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting -// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS. -// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited -// output can treat this as a success, despite having an exit code of SIG_PIPE -// due to us closing the output pipe. -// In the case of EXECUTE_SUCCESS, the application exit code will be returned -// in |*exit_code|, which should be checked to determine if the application -// ran successfully. -static GetAppOutputInternalResult GetAppOutputInternal( +// The return value of the function indicates success or failure. In the case of +// success, the application exit code will be returned in |*exit_code|, which +// should be checked to determine if the application ran successfully. +static bool GetAppOutputInternal( const std::vector<std::string>& argv, char* const envp[], bool include_stderr, std::string* output, - size_t max_output, bool do_search_path, int* exit_code) { // Doing a blocking wait for another command to finish counts as IO. @@ -562,13 +550,13 @@ static GetAppOutputInternalResult GetAppOutputInternal( DCHECK(!do_search_path ^ !envp); if (pipe(pipe_fd) < 0) - return EXECUTE_FAILURE; + return false; switch (pid = fork()) { case -1: // error close(pipe_fd[0]); close(pipe_fd[1]); - return EXECUTE_FAILURE; + return false; case 0: // child { // DANGER: no calls to malloc or locks are allowed from now on: @@ -605,7 +593,7 @@ static GetAppOutputInternalResult GetAppOutputInternal( for (size_t i = 0; i < argv.size(); i++) argv_cstr[i] = const_cast<char*>(argv[i].c_str()); - argv_cstr[argv.size()] = NULL; + argv_cstr[argv.size()] = nullptr; if (do_search_path) execvp(argv_cstr[0], argv_cstr.get()); else @@ -620,33 +608,21 @@ static GetAppOutputInternalResult GetAppOutputInternal( close(pipe_fd[1]); output->clear(); - char buffer[256]; - size_t output_buf_left = max_output; - ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| - // case in the logic below. - - while (output_buf_left > 0) { - bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, - std::min(output_buf_left, sizeof(buffer)))); + + while (true) { + char buffer[256]; + ssize_t bytes_read = + HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); if (bytes_read <= 0) break; output->append(buffer, bytes_read); - output_buf_left -= static_cast<size_t>(bytes_read); } close(pipe_fd[0]); // Always wait for exit code (even if we know we'll declare // GOT_MAX_OUTPUT). Process process(pid); - bool success = process.WaitForExit(exit_code); - - // If we stopped because we read as much as we wanted, we return - // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|). - if (!output_buf_left && bytes_read > 0) - return GOT_MAX_OUTPUT; - else if (success) - return EXECUTE_SUCCESS; - return EXECUTE_FAILURE; + return process.WaitForExit(exit_code); } } } @@ -656,44 +632,27 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) { } bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { - // Run |execve()| with the current environment and store "unlimited" data. + // Run |execve()| with the current environment. int exit_code; - GetAppOutputInternalResult result = GetAppOutputInternal( - argv, NULL, false, output, std::numeric_limits<std::size_t>::max(), true, - &exit_code); - return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; + bool result = + GetAppOutputInternal(argv, nullptr, false, output, true, &exit_code); + return result && exit_code == EXIT_SUCCESS; } bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { - // Run |execve()| with the current environment and store "unlimited" data. - int exit_code; - GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), NULL, true, output, std::numeric_limits<std::size_t>::max(), - true, &exit_code); - return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; -} - -// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we -// don't hang if what we're calling hangs. -bool GetAppOutputRestricted(const CommandLine& cl, - std::string* output, size_t max_output) { - // Run |execve()| with the empty environment. - char* const empty_environ = NULL; + // Run |execve()| with the current environment. int exit_code; - GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), &empty_environ, false, output, max_output, false, &exit_code); - return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS && - exit_code == EXIT_SUCCESS); + bool result = + GetAppOutputInternal(cl.argv(), nullptr, true, output, true, &exit_code); + return result && exit_code == EXIT_SUCCESS; } bool GetAppOutputWithExitCode(const CommandLine& cl, std::string* output, int* exit_code) { - // Run |execve()| with the current environment and store "unlimited" data. - GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), NULL, false, output, std::numeric_limits<std::size_t>::max(), - true, exit_code); - return result == EXECUTE_SUCCESS; + // Run |execve()| with the current environment. + return GetAppOutputInternal(cl.argv(), nullptr, false, output, true, + exit_code); } #endif // !defined(OS_NACL_NONSFI) diff --git a/chromium/base/process/launch_win.cc b/chromium/base/process/launch_win.cc index 97b59a5bfe4..1349b3e4af3 100644 --- a/chromium/base/process/launch_win.cc +++ b/chromium/base/process/launch_win.cc @@ -142,14 +142,7 @@ void RouteStdioToConsole(bool create_console_if_not_found) { // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was // invalid. if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) { - // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013. - // http://crbug.com/358267. Confirm that the underlying HANDLE is valid - // before aborting. - - intptr_t stdout_handle = _get_osfhandle(_fileno(stdout)); - intptr_t stderr_handle = _get_osfhandle(_fileno(stderr)); - if (stdout_handle >= 0 || stderr_handle >= 0) - return; + return; } if (!AttachConsole(ATTACH_PARENT_PROCESS)) { diff --git a/chromium/base/process/memory.cc b/chromium/base/process/memory.cc index 75d45303eba..6349c08ca0a 100644 --- a/chromium/base/process/memory.cc +++ b/chromium/base/process/memory.cc @@ -9,6 +9,9 @@ namespace base { +// Defined in memory_win.cc for Windows. +#if !defined(OS_WIN) + namespace { // Breakpad server classifies base::`anonymous namespace'::OnNoMemory as @@ -25,6 +28,8 @@ void TerminateBecauseOutOfMemory(size_t size) { OnNoMemory(size); } +#endif + // Defined in memory_mac.mm for Mac. #if !defined(OS_MACOSX) diff --git a/chromium/base/process/memory.h b/chromium/base/process/memory.h index be669dd8476..77911cfc350 100644 --- a/chromium/base/process/memory.h +++ b/chromium/base/process/memory.h @@ -48,6 +48,20 @@ const int kMaxOomScore = 1000; BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score); #endif +#if defined(OS_WIN) +namespace win { + +// Custom Windows exception code chosen to indicate an out of memory error. +// See https://msdn.microsoft.com/en-us/library/het71c37.aspx. +// "To make sure that you do not define a code that conflicts with an existing +// exception code" ... "The resulting error code should therefore have the +// highest four bits set to hexadecimal E." +// 0xe0000008 was chosen arbitrarily, as 0x00000008 is ERROR_NOT_ENOUGH_MEMORY. +const DWORD kOomExceptionCode = 0xe0000008; + +} // namespace win +#endif + // Special allocator functions for callers that want to check for OOM. // These will not abort if the allocation fails even if // EnableTerminationOnOutOfMemory has been called. diff --git a/chromium/base/process/memory_mac.mm b/chromium/base/process/memory_mac.mm index 32fdd38821d..bac75aeab15 100644 --- a/chromium/base/process/memory_mac.mm +++ b/chromium/base/process/memory_mac.mm @@ -248,7 +248,7 @@ void oom_killer_new() { // === Core Foundation CFAllocators === bool CanGetContextForCFAllocator() { - return !base::mac::IsOSLaterThanSierra_DontCallThis(); + return !base::mac::IsOSLaterThan10_12_DontCallThis(); } CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { diff --git a/chromium/base/process/memory_stubs.cc b/chromium/base/process/memory_stubs.cc index 7ed012d8803..787d9aef217 100644 --- a/chromium/base/process/memory_stubs.cc +++ b/chromium/base/process/memory_stubs.cc @@ -19,6 +19,10 @@ bool AdjustOOMScore(ProcessId process, int score) { return false; } +void TerminateBecauseOutOfMemory(size_t size) { + abort(); +} + // UncheckedMalloc and Calloc exist so that platforms making use of // EnableTerminationOnOutOfMemory have a way to allocate memory without // crashing. This _stubs.cc file is for platforms that do not support diff --git a/chromium/base/process/memory_unittest.cc b/chromium/base/process/memory_unittest.cc index ec2ed9f1869..0be2d440063 100644 --- a/chromium/base/process/memory_unittest.cc +++ b/chromium/base/process/memory_unittest.cc @@ -11,6 +11,7 @@ #include <limits> #include "base/allocator/allocator_check.h" +#include "base/allocator/features.h" #include "base/compiler_specific.h" #include "base/debug/alias.h" #include "base/memory/aligned_memory.h" @@ -26,7 +27,6 @@ #endif #if defined(OS_MACOSX) #include <malloc/malloc.h> -#include "base/mac/mac_util.h" #include "base/process/memory_unittest_mac.h" #endif #if defined(OS_LINUX) @@ -82,17 +82,23 @@ TEST(MemoryTest, AllocatorShimWorking) { ASSERT_TRUE(base::allocator::IsAllocatorInitialized()); } -// Android doesn't implement set_new_handler, so we can't use the -// OutOfMemoryTest cases. OpenBSD does not support these tests either. -// Don't test these on ASan/TSan/MSan configurations: only test the real -// allocator. +// OpenBSD does not support these tests. Don't test these on ASan/TSan/MSan +// configurations: only test the real allocator. // Windows only supports these tests with the allocator shim in place. -#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \ - !(defined(OS_WIN) && !defined(ALLOCATOR_SHIM)) && \ +#if !defined(OS_OPENBSD) && \ + BUILDFLAG(ENABLE_WIN_ALLOCATOR_SHIM_TESTS) && \ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) namespace { -const char *kOomRegex = "Out of memory"; +#if defined(OS_WIN) +// Windows raises an exception rather than using LOG(FATAL) in order to make the +// exit code unique to OOM. +const char* kOomRegex = ""; +const int kExitCode = base::win::kOomExceptionCode; +#else +const char* kOomRegex = "Out of memory"; +const int kExitCode = 1; +#endif } // namespace class OutOfMemoryTest : public testing::Test { @@ -128,112 +134,112 @@ class OutOfMemoryDeathTest : public OutOfMemoryTest { }; TEST_F(OutOfMemoryDeathTest, New) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = operator new(test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, NewArray) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = new char[test_size_]; - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, Malloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = malloc(test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, Realloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = realloc(NULL, test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, Calloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = calloc(1024, test_size_ / 1024L); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, AlignedAlloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = base::AlignedAlloc(test_size_, 8); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } // POSIX does not define an aligned realloc function. #if defined(OS_WIN) TEST_F(OutOfMemoryDeathTest, AlignedRealloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = _aligned_realloc(NULL, test_size_, 8); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } #endif // defined(OS_WIN) -// OS X has no 2Gb allocation limit. +// OS X and Android have no 2Gb allocation limit. // See https://crbug.com/169327. -#if !defined(OS_MACOSX) +#if !defined(OS_MACOSX) && !defined(OS_ANDROID) TEST_F(OutOfMemoryDeathTest, SecurityNew) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = operator new(insecure_test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, SecurityNewArray) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = new char[insecure_test_size_]; - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, SecurityMalloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = malloc(insecure_test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, SecurityRealloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = realloc(NULL, insecure_test_size_); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, SecurityCalloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = calloc(1024, insecure_test_size_ / 1024L); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } TEST_F(OutOfMemoryDeathTest, SecurityAlignedAlloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = base::AlignedAlloc(insecure_test_size_, 8); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } // POSIX does not define an aligned realloc function. #if defined(OS_WIN) TEST_F(OutOfMemoryDeathTest, SecurityAlignedRealloc) { - ASSERT_DEATH({ + ASSERT_EXIT({ SetUpInDeathAssert(); value_ = _aligned_realloc(NULL, insecure_test_size_, 8); - }, kOomRegex); + }, testing::ExitedWithCode(kExitCode), kOomRegex); } #endif // defined(OS_WIN) -#endif // !defined(OS_MACOSX) +#endif // !defined(OS_MACOSX) && !defined(OS_ANDROID) #if defined(OS_LINUX) @@ -405,17 +411,7 @@ class OutOfMemoryHandledTest : public OutOfMemoryTest { // TODO(b.kelemen): make UncheckedMalloc and UncheckedCalloc work // on Windows as well. -// UncheckedMalloc() and UncheckedCalloc() work as regular malloc()/calloc() -// under sanitizer tools. -#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) { -#if defined(OS_MACOSX) && ARCH_CPU_32_BITS - // The Mavericks malloc library changed in a way which breaks the tricks used - // to implement EnableTerminationOnOutOfMemory() with UncheckedMalloc() under - // 32-bit. The 64-bit malloc library works as desired without tricks. - if (base::mac::IsOSMavericksOrLater()) - return; -#endif EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_)); EXPECT_TRUE(value_ != NULL); free(value_); @@ -425,13 +421,6 @@ TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) { } TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) { -#if defined(OS_MACOSX) && ARCH_CPU_32_BITS - // The Mavericks malloc library changed in a way which breaks the tricks used - // to implement EnableTerminationOnOutOfMemory() with UncheckedCalloc() under - // 32-bit. The 64-bit malloc library works as desired without tricks. - if (base::mac::IsOSMavericksOrLater()) - return; -#endif EXPECT_TRUE(base::UncheckedCalloc(1, kSafeMallocSize, &value_)); EXPECT_TRUE(value_ != NULL); const char* bytes = static_cast<const char*>(value_); @@ -450,6 +439,5 @@ TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) { EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_)); EXPECT_TRUE(value_ == NULL); } -#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) -#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !(defined(OS_WIN) && - // !defined(ALLOCATOR_SHIM)) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) +#endif // !defined(OS_OPENBSD) && BUILDFLAG(ENABLE_WIN_ALLOCATOR_SHIM_TESTS) && + // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) diff --git a/chromium/base/process/memory_win.cc b/chromium/base/process/memory_win.cc index 17d588aab73..d433020debb 100644 --- a/chromium/base/process/memory_win.cc +++ b/chromium/base/process/memory_win.cc @@ -7,8 +7,7 @@ #include <new.h> #include <psapi.h> #include <stddef.h> - -#include "base/logging.h" +#include <windows.h> // malloc_unchecked is required to implement UncheckedMalloc properly. // It's provided by allocator_shim_win.cc but since that's not always present, @@ -30,25 +29,27 @@ namespace base { namespace { #pragma warning(push) -#pragma warning(disable: 4702) +#pragma warning(disable: 4702) // Unreachable code after the _exit. -int OnNoMemory(size_t size) { +NOINLINE int OnNoMemory(size_t size) { // Kill the process. This is important for security since most of code // does not check the result of memory allocation. - LOG(FATAL) << "Out of memory, size = " << size; - + // https://msdn.microsoft.com/en-us/library/het71c37.aspx + ::RaiseException(win::kOomExceptionCode, EXCEPTION_NONCONTINUABLE, 0, + nullptr); // Safety check, make sure process exits here. - _exit(1); + _exit(win::kOomExceptionCode); return 0; } #pragma warning(pop) -// HeapSetInformation function pointer. -typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); - } // namespace +void TerminateBecauseOutOfMemory(size_t size) { + OnNoMemory(size); +} + void EnableTerminationOnHeapCorruption() { // Ignore the result code. Supported on XP SP3 and Vista. HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); diff --git a/chromium/base/process/process_metrics.cc b/chromium/base/process/process_metrics.cc index 0b387264315..cc6532c8dca 100644 --- a/chromium/base/process/process_metrics.cc +++ b/chromium/base/process/process_metrics.cc @@ -46,7 +46,7 @@ std::unique_ptr<Value> SystemMetrics::ToValue() const { return std::move(res); } -ProcessMetrics* ProcessMetrics::CreateCurrentProcessMetrics() { +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateCurrentProcessMetrics() { #if !defined(OS_MACOSX) || defined(OS_IOS) return CreateProcessMetrics(base::GetCurrentProcessHandle()); #else diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h index 57cb3abec0d..d9c9952201b 100644 --- a/chromium/base/process/process_metrics.h +++ b/chromium/base/process/process_metrics.h @@ -11,6 +11,7 @@ #include <stddef.h> #include <stdint.h> +#include <memory> #include <string> #include "base/base_export.h" @@ -103,22 +104,22 @@ class BASE_EXPORT ProcessMetrics { ~ProcessMetrics(); // Creates a ProcessMetrics for the specified process. - // The caller owns the returned object. #if !defined(OS_MACOSX) || defined(OS_IOS) - static ProcessMetrics* CreateProcessMetrics(ProcessHandle process); + static std::unique_ptr<ProcessMetrics> CreateProcessMetrics( + ProcessHandle process); #else // The port provider needs to outlive the ProcessMetrics object returned by // this function. If NULL is passed as provider, the returned object // only returns valid metrics if |process| is the current process. - static ProcessMetrics* CreateProcessMetrics(ProcessHandle process, - PortProvider* port_provider); + static std::unique_ptr<ProcessMetrics> CreateProcessMetrics( + ProcessHandle process, + PortProvider* port_provider); #endif // !defined(OS_MACOSX) || defined(OS_IOS) // Creates a ProcessMetrics for the current process. This a cross-platform // convenience wrapper for CreateProcessMetrics(). - // The caller owns the returned object. - static ProcessMetrics* CreateCurrentProcessMetrics(); + static std::unique_ptr<ProcessMetrics> CreateCurrentProcessMetrics(); // Returns the current space allocated for the pagefile, in bytes (these pages // may or may not be in memory). On Linux, this returns the total virtual @@ -295,9 +296,9 @@ struct BASE_EXPORT SystemMemoryInfoKB { int dirty; // vmstats data. - int pswpin; - int pswpout; - int pgmajfault; + unsigned long pswpin; + unsigned long pswpout; + unsigned long pgmajfault; #endif // defined(OS_ANDROID) || defined(OS_LINUX) #if defined(OS_CHROMEOS) @@ -374,6 +375,9 @@ BASE_EXPORT bool IsValidDiskName(const std::string& candidate); // Retrieves data from /proc/diskstats about system-wide disk I/O. // Fills in the provided |diskinfo| structure. Returns true on success. BASE_EXPORT bool GetSystemDiskInfo(SystemDiskInfo* diskinfo); + +// Returns the amount of time spent in user space since boot across all CPUs. +BASE_EXPORT TimeDelta GetUserCpuTimeSinceBoot(); #endif // defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_CHROMEOS) diff --git a/chromium/base/process/process_metrics_freebsd.cc b/chromium/base/process/process_metrics_freebsd.cc index 5fd93cbe1c9..686f6338724 100644 --- a/chromium/base/process/process_metrics_freebsd.cc +++ b/chromium/base/process/process_metrics_freebsd.cc @@ -10,20 +10,21 @@ #include <unistd.h> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/sys_info.h" namespace base { ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), + processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0), - last_cpu_(0) { - processor_count_ = base::SysInfo::NumberOfProcessors(); -} + last_cpu_(0) {} // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( + ProcessHandle process) { + return WrapUnique(new ProcessMetrics(process)); } size_t ProcessMetrics::GetPagefileUsage() const { diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc index 8f9806e132a..e6b01192b59 100644 --- a/chromium/base/process/process_metrics_ios.cc +++ b/chromium/base/process/process_metrics_ios.cc @@ -9,6 +9,7 @@ #include <stddef.h> #include "base/logging.h" +#include "base/memory/ptr_util.h" namespace base { @@ -25,10 +26,7 @@ bool GetTaskInfo(task_basic_info_64* task_info_data) { } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() { - total = 0; - free = 0; -} +SystemMemoryInfoKB::SystemMemoryInfoKB() : total(0), free(0) {} SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = default; @@ -38,8 +36,9 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process) {} ProcessMetrics::~ProcessMetrics() {} // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( + ProcessHandle process) { + return WrapUnique(new ProcessMetrics(process)); } double ProcessMetrics::GetCPUUsage() { diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc index 3d27656d6ac..b14aa210bd5 100644 --- a/chromium/base/process/process_metrics_linux.cc +++ b/chromium/base/process/process_metrics_linux.cc @@ -17,6 +17,7 @@ #include "base/files/dir_reader_posix.h" #include "base/files/file_util.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/process/internal_linux.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -72,8 +73,8 @@ size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { const std::string& key = pairs[i].first; const std::string& value_str = pairs[i].second; if (key == field) { - std::vector<StringPiece> split_value_str = SplitStringPiece( - value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector<StringPiece> split_value_str = + SplitStringPiece(value_str, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL); if (split_value_str.size() != 2 || split_value_str[1] != "kB") { NOTREACHED(); return 0; @@ -163,8 +164,9 @@ int GetProcessCPU(pid_t pid) { } // namespace // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( + ProcessHandle process) { + return WrapUnique(new ProcessMetrics(process)); } // On linux, we return vsize. @@ -354,8 +356,7 @@ bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) } std::vector<std::string> totmaps_fields = SplitString( - totmaps_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); + totmaps_data, kWhitespaceASCII, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]); DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]); @@ -406,8 +407,8 @@ bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) return false; } - std::vector<StringPiece> statm_vec = SplitStringPiece( - statm, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector<StringPiece> statm_vec = + SplitStringPiece(statm, " ", TRIM_WHITESPACE, SPLIT_WANT_ALL); if (statm_vec.size() != 7) return false; // Not the format we expect. @@ -686,12 +687,16 @@ bool ParseProcVmstat(const std::string& vmstat_data, if (tokens.size() != 2) continue; + uint64_t val; + if (!StringToUint64(tokens[1], &val)) + continue; + if (tokens[0] == "pswpin") { - StringToInt(tokens[1], &meminfo->pswpin); + meminfo->pswpin = val; } else if (tokens[0] == "pswpout") { - StringToInt(tokens[1], &meminfo->pswpout); + meminfo->pswpout = val; } else if (tokens[0] == "pgmajfault") { - StringToInt(tokens[1], &meminfo->pgmajfault); + meminfo->pgmajfault = val; } } @@ -907,6 +912,10 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) { return true; } +TimeDelta GetUserCpuTimeSinceBoot() { + return internal::GetUserCpuTimeSinceBoot(); +} + #if defined(OS_CHROMEOS) std::unique_ptr<Value> SwapInfo::ToValue() const { std::unique_ptr<DictionaryValue> res(new DictionaryValue()); diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc index b3e87178ab4..7fc931748ae 100644 --- a/chromium/base/process/process_metrics_mac.cc +++ b/chromium/base/process/process_metrics_mac.cc @@ -15,6 +15,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" +#include "base/memory/ptr_util.h" #include "base/sys_info.h" #if !defined(TASK_POWER_INFO) @@ -79,10 +80,7 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() { - total = 0; - free = 0; -} +SystemMemoryInfoKB::SystemMemoryInfoKB() : total(0), free(0) {} SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = default; @@ -94,10 +92,10 @@ SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = // otherwise return 0. // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics( +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( ProcessHandle process, PortProvider* port_provider) { - return new ProcessMetrics(process, port_provider); + return WrapUnique(new ProcessMetrics(process, port_provider)); } size_t ProcessMetrics::GetPagefileUsage() const { @@ -145,7 +143,7 @@ bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, // The same region can be referenced multiple times. To avoid double counting // we need to keep track of which regions we've already counted. - base::hash_set<int> seen_objects; + hash_set<int> seen_objects; // We iterate through each VM region in the task's address map. For shared // memory we add up all the pages that are marked as shared. Like libtop we diff --git a/chromium/base/process/process_metrics_openbsd.cc b/chromium/base/process/process_metrics_openbsd.cc index 3f76cc222d9..58033aef62e 100644 --- a/chromium/base/process/process_metrics_openbsd.cc +++ b/chromium/base/process/process_metrics_openbsd.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/macros.h" #include "base/process/process_metrics.h" #include <stddef.h> @@ -10,11 +9,16 @@ #include <sys/param.h> #include <sys/sysctl.h> +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/sys_info.h" + namespace base { // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( + ProcessHandle process) { + return WrapUnique(new ProcessMetrics(process)); } size_t ProcessMetrics::GetPagefileUsage() const { @@ -136,11 +140,9 @@ double ProcessMetrics::GetCPUUsage() { ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), + processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0), - last_cpu_(0) { - - processor_count_ = base::SysInfo::NumberOfProcessors(); -} + last_cpu_(0) {} size_t GetSystemCommitCharge() { int mib[] = { CTL_VM, VM_METER }; diff --git a/chromium/base/process/process_metrics_posix.cc b/chromium/base/process/process_metrics_posix.cc index fad581eece7..13acf2ea34f 100644 --- a/chromium/base/process/process_metrics_posix.cc +++ b/chromium/base/process/process_metrics_posix.cc @@ -33,6 +33,8 @@ static const rlim_t kSystemDefaultMaxFds = 256; static const rlim_t kSystemDefaultMaxFds = 8192; #elif defined(OS_FREEBSD) static const rlim_t kSystemDefaultMaxFds = 8192; +#elif defined(OS_NETBSD) +static const rlim_t kSystemDefaultMaxFds = 1024; #elif defined(OS_OPENBSD) static const rlim_t kSystemDefaultMaxFds = 256; #elif defined(OS_ANDROID) diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc index 4c5b71d0bd5..3e059b48a45 100644 --- a/chromium/base/process/process_metrics_unittest.cc +++ b/chromium/base/process/process_metrics_unittest.cc @@ -286,13 +286,13 @@ TEST_F(SystemMetricsTest, ParseVmstat) { "pgrefill_high 0\n" "pgrefill_movable 0\n"; EXPECT_TRUE(ParseProcVmstat(valid_input1, &meminfo)); - EXPECT_EQ(meminfo.pswpin, 179); - EXPECT_EQ(meminfo.pswpout, 406); - EXPECT_EQ(meminfo.pgmajfault, 487192); + EXPECT_EQ(179LU, meminfo.pswpin); + EXPECT_EQ(406LU, meminfo.pswpout); + EXPECT_EQ(487192LU, meminfo.pgmajfault); EXPECT_TRUE(ParseProcVmstat(valid_input2, &meminfo)); - EXPECT_EQ(meminfo.pswpin, 12); - EXPECT_EQ(meminfo.pswpout, 901); - EXPECT_EQ(meminfo.pgmajfault, 2023); + EXPECT_EQ(12LU, meminfo.pswpin); + EXPECT_EQ(901LU, meminfo.pswpout); + EXPECT_EQ(2023LU, meminfo.pgmajfault); } #endif // defined(OS_LINUX) || defined(OS_ANDROID) @@ -488,7 +488,7 @@ MULTIPROCESS_TEST_MAIN(ChildMain) { TEST(ProcessMetricsTest, GetOpenFdCount) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - const FilePath temp_path = temp_dir.path(); + const FilePath temp_path = temp_dir.GetPath(); CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine()); child_command_line.AppendSwitchPath(kTempDirFlag, temp_path); Process child = SpawnMultiProcessTestChild( diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc index 46e4b8d8494..5b2777bb364 100644 --- a/chromium/base/process/process_metrics_win.cc +++ b/chromium/base/process/process_metrics_win.cc @@ -13,6 +13,8 @@ #include <algorithm> #include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/process/memory.h" #include "base/sys_info.h" namespace base { @@ -29,12 +31,8 @@ typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( } // namespace -SystemMemoryInfoKB::SystemMemoryInfoKB() { - total = 0; - free = 0; - swap_total = 0; - swap_free = 0; -} +SystemMemoryInfoKB::SystemMemoryInfoKB() + : total(0), free(0), swap_total(0), swap_free(0) {} SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = default; @@ -42,8 +40,9 @@ SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) = ProcessMetrics::~ProcessMetrics() { } // static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); +std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( + ProcessHandle process) { + return WrapUnique(new ProcessMetrics(process)); } size_t ProcessMetrics::GetPagefileUsage() const { @@ -142,6 +141,36 @@ void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { usage->priv = committed_private / 1024; } +namespace { + +class WorkingSetInformationBuffer { + public: + WorkingSetInformationBuffer() {} + ~WorkingSetInformationBuffer() { Clear(); } + + bool Reserve(size_t size) { + Clear(); + // Use UncheckedMalloc here because this can be called from the code + // that handles low memory condition. + return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); + } + + PSAPI_WORKING_SET_INFORMATION* get() { return buffer_; } + const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } + + private: + void Clear() { + free(buffer_); + buffer_ = nullptr; + } + + PSAPI_WORKING_SET_INFORMATION* buffer_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(WorkingSetInformationBuffer); +}; + +} // namespace + bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { size_t ws_private = 0; size_t ws_shareable = 0; @@ -151,40 +180,33 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { memset(ws_usage, 0, sizeof(*ws_usage)); DWORD number_of_entries = 4096; // Just a guess. - PSAPI_WORKING_SET_INFORMATION* buffer = NULL; + WorkingSetInformationBuffer buffer; int retries = 5; for (;;) { DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); - // if we can't expand the buffer, don't leak the previous - // contents or pass a NULL pointer to QueryWorkingSet - PSAPI_WORKING_SET_INFORMATION* new_buffer = - reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>( - realloc(buffer, buffer_size)); - if (!new_buffer) { - free(buffer); + if (!buffer.Reserve(buffer_size)) return false; - } - buffer = new_buffer; // Call the function once to get number of items - if (QueryWorkingSet(process_, buffer, buffer_size)) + if (QueryWorkingSet(process_, buffer.get(), buffer_size)) break; // Success - if (GetLastError() != ERROR_BAD_LENGTH) { - free(buffer); + if (GetLastError() != ERROR_BAD_LENGTH) return false; - } number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries); // Maybe some entries are being added right now. Increase the buffer to - // take that into account. - number_of_entries = static_cast<DWORD>(number_of_entries * 1.25); + // take that into account. Increasing by 10% should generally be enough, + // especially considering the potentially low memory condition during the + // call (when called from OomMemoryDetails) and the potentially high + // number of entries (300K was observed in crash dumps). + number_of_entries = static_cast<DWORD>(number_of_entries * 1.1); if (--retries == 0) { - free(buffer); // If we're looping, eventually fail. + // If we're looping, eventually fail. return false; } } @@ -207,7 +229,6 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { ws_usage->priv = ws_private * PAGESIZE_KB; ws_usage->shareable = ws_shareable * PAGESIZE_KB; ws_usage->shared = ws_shared * PAGESIZE_KB; - free(buffer); return true; } @@ -263,35 +284,8 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), - processor_count_(base::SysInfo::NumberOfProcessors()), - last_system_time_(0) { -} - -// GetPerformanceInfo is not available on WIN2K. So we'll -// load it on-the-fly. -const wchar_t kPsapiDllName[] = L"psapi.dll"; -typedef BOOL (WINAPI *GetPerformanceInfoFunction) ( - PPERFORMANCE_INFORMATION pPerformanceInformation, - DWORD cb); - -// Beware of races if called concurrently from multiple threads. -static BOOL InternalGetPerformanceInfo( - PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) { - static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL; - if (!GetPerformanceInfo_func) { - HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName); - if (psapi_dll) - GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>( - GetProcAddress(psapi_dll, "GetPerformanceInfo")); - - if (!GetPerformanceInfo_func) { - // The function could not be loaded! - memset(pPerformanceInformation, 0, cb); - return FALSE; - } - } - return GetPerformanceInfo_func(pPerformanceInformation, cb); -} + processor_count_(SysInfo::NumberOfProcessors()), + last_system_time_(0) {} size_t GetSystemCommitCharge() { // Get the System Page Size. @@ -299,7 +293,7 @@ size_t GetSystemCommitCharge() { GetSystemInfo(&system_info); PERFORMANCE_INFORMATION info; - if (!InternalGetPerformanceInfo(&info, sizeof(info))) { + if (!GetPerformanceInfo(&info, sizeof(info))) { DLOG(ERROR) << "Failed to fetch internal performance info."; return 0; } diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc index ade82e5ce66..a9d745eeead 100644 --- a/chromium/base/process/process_posix.cc +++ b/chromium/base/process/process_posix.cc @@ -9,6 +9,7 @@ #include <sys/resource.h> #include <sys/wait.h> +#include "base/debug/activity_tracker.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" @@ -354,6 +355,9 @@ bool Process::WaitForExit(int* exit_code) { } bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { + // Record the event that this thread is blocking upon (for hang diagnosis). + base::debug::ScopedProcessWaitActivity process_activity(this); + return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout); } diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc index c162fb20366..87fdd012309 100644 --- a/chromium/base/process/process_util_unittest.cc +++ b/chromium/base/process/process_util_unittest.cc @@ -60,7 +60,6 @@ #if defined(OS_MACOSX) #include <mach/vm_param.h> #include <malloc/malloc.h> -#include "base/mac/mac_util.h" #endif #if defined(OS_ANDROID) #include "third_party/lss/linux_syscall_support.h" @@ -572,10 +571,6 @@ int change_fdguard_np(int fd, // <http://crbug.com/338157>. This function allows querying whether the file // descriptor is guarded before attempting to close it. bool CanGuardFd(int fd) { - // The syscall is first provided in 10.9/Mavericks. - if (!base::mac::IsOSMavericksOrLater()) - return true; - // Saves the original flags to reset later. int original_fdflags = 0; @@ -844,118 +839,6 @@ TEST_F(ProcessUtilTest, GetAppOutput) { #endif // defined(OS_ANDROID) } -// Flakes on Android, crbug.com/375840 -#if defined(OS_ANDROID) -#define MAYBE_GetAppOutputRestricted DISABLED_GetAppOutputRestricted -#else -#define MAYBE_GetAppOutputRestricted GetAppOutputRestricted -#endif -TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestricted) { - // Unfortunately, since we can't rely on the path, we need to know where - // everything is. So let's use /bin/sh, which is on every POSIX system, and - // its built-ins. - std::vector<std::string> argv; - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); // argv[1] - - // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of - // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we - // need absolute paths). - argv.push_back("exit 0"); // argv[2]; equivalent to "true" - std::string output = "abc"; - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 100)); - EXPECT_STREQ("", output.c_str()); - - argv[2] = "exit 1"; // equivalent to "false" - output = "before"; - EXPECT_FALSE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 100)); - EXPECT_STREQ("", output.c_str()); - - // Amount of output exactly equal to space allowed. - argv[2] = "echo 123456789"; // (the sh built-in doesn't take "-n") - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 10)); - EXPECT_STREQ("123456789\n", output.c_str()); - - // Amount of output greater than space allowed. - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 5)); - EXPECT_STREQ("12345", output.c_str()); - - // Amount of output less than space allowed. - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 15)); - EXPECT_STREQ("123456789\n", output.c_str()); - - // Zero space allowed. - output = "abc"; - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 0)); - EXPECT_STREQ("", output.c_str()); -} - -#if !defined(OS_MACOSX) && !defined(OS_OPENBSD) -// TODO(benwells): GetAppOutputRestricted should terminate applications -// with SIGPIPE when we have enough output. http://crbug.com/88502 -TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) { - std::vector<std::string> argv; - std::string output; - - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); -#if defined(OS_ANDROID) - argv.push_back("while echo 12345678901234567890; do :; done"); - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 10)); - EXPECT_STREQ("1234567890", output.c_str()); -#else // defined(OS_ANDROID) - argv.push_back("yes"); - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 10)); - EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str()); -#endif // !defined(OS_ANDROID) -} -#endif // !defined(OS_MACOSX) && !defined(OS_OPENBSD) - -#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX) && \ - defined(ARCH_CPU_64_BITS) -// Times out under AddressSanitizer on 64-bit OS X, see -// http://crbug.com/298197. -#define MAYBE_GetAppOutputRestrictedNoZombies \ - DISABLED_GetAppOutputRestrictedNoZombies -#else -#define MAYBE_GetAppOutputRestrictedNoZombies GetAppOutputRestrictedNoZombies -#endif -TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestrictedNoZombies) { - std::vector<std::string> argv; - - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); // argv[1] - argv.push_back("echo 123456789012345678901234567890"); // argv[2] - - // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS - // 10.5) times with an output buffer big enough to capture all output. - for (int i = 0; i < 300; i++) { - std::string output; - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 100)); - EXPECT_STREQ("123456789012345678901234567890\n", output.c_str()); - } - - // Ditto, but with an output buffer too small to capture all output. - for (int i = 0; i < 300; i++) { - std::string output; - EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output, - 10)); - EXPECT_STREQ("1234567890", output.c_str()); - } -} - TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) { // Test getting output from a successful application. std::vector<std::string> argv; diff --git a/chromium/base/process/process_win.cc b/chromium/base/process/process_win.cc index 8e508a1b1fb..6629f4565a7 100644 --- a/chromium/base/process/process_win.cc +++ b/chromium/base/process/process_win.cc @@ -4,6 +4,7 @@ #include "base/process/process.h" +#include "base/debug/activity_tracker.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/process/kill.h" @@ -142,6 +143,9 @@ bool Process::WaitForExit(int* exit_code) { } bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { + // Record the event that this thread is blocking upon (for hang diagnosis). + base::debug::ScopedProcessWaitActivity process_activity(this); + // Limit timeout to INFINITE. DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds()); if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0) |