diff options
Diffstat (limited to 'base/process/process_linux.cc')
-rw-r--r-- | base/process/process_linux.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc new file mode 100644 index 0000000000..faf39afd4b --- /dev/null +++ b/base/process/process_linux.cc @@ -0,0 +1,201 @@ +// Copyright (c) 2011 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.h" + +#include <errno.h> +#include <sys/resource.h> + +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/stringprintf.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_restrictions.h" +#include "build/build_config.h" + +// Not defined on AIX by default. +#if defined(OS_AIX) +#define RLIMIT_NICE 20 +#endif + +namespace base { + +namespace { + +const int kForegroundPriority = 0; + +#if defined(OS_CHROMEOS) +// We are more aggressive in our lowering of background process priority +// for chromeos as we have much more control over other processes running +// on the machine. +// +// TODO(davemoore) Refactor this by adding support for higher levels to set +// the foregrounding / backgrounding process so we don't have to keep +// chrome / chromeos specific logic here. +const int kBackgroundPriority = 19; +const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs"; +const char kForeground[] = "/chrome_renderers/foreground"; +const char kBackground[] = "/chrome_renderers/background"; +const char kProcPath[] = "/proc/%d/cgroup"; + +struct CGroups { + // Check for cgroups files. ChromeOS supports these by default. It creates + // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups, + // one contains at most a single foreground renderer and the other contains + // all background renderers. This allows us to limit the impact of background + // renderers on foreground ones to a greater level than simple renicing. + bool enabled; + base::FilePath foreground_file; + base::FilePath background_file; + + CGroups() { + foreground_file = + base::FilePath(base::StringPrintf(kControlPath, kForeground)); + background_file = + base::FilePath(base::StringPrintf(kControlPath, kBackground)); + base::FileSystemType foreground_type; + base::FileSystemType background_type; + enabled = + base::GetFileSystemType(foreground_file, &foreground_type) && + base::GetFileSystemType(background_file, &background_type) && + foreground_type == FILE_SYSTEM_CGROUP && + background_type == FILE_SYSTEM_CGROUP; + } + + static CGroups& Get() { + static auto& groups = *new CGroups; + return groups; + } +}; +#else +const int kBackgroundPriority = 5; +#endif // defined(OS_CHROMEOS) + +bool CanReraisePriority() { + // We won't be able to raise the priority if we don't have the right rlimit. + // The limit may be adjusted in /etc/security/limits.conf for PAM systems. + struct rlimit rlim; + return (getrlimit(RLIMIT_NICE, &rlim) == 0) && + (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur); +} + +} // namespace + +// static +bool Process::CanBackgroundProcesses() { +#if defined(OS_CHROMEOS) + if (CGroups::Get().enabled) + return true; +#endif // defined(OS_CHROMEOS) + + static const bool can_reraise_priority = CanReraisePriority(); + return can_reraise_priority; +} + +bool Process::IsProcessBackgrounded() const { + DCHECK(IsValid()); + +#if defined(OS_CHROMEOS) + if (CGroups::Get().enabled) { + // Used to allow reading the process priority from proc on thread launch. + base::ThreadRestrictions::ScopedAllowIO allow_io; + std::string proc; + if (base::ReadFileToString( + base::FilePath(StringPrintf(kProcPath, process_)), &proc)) { + return IsProcessBackgroundedCGroup(proc); + } + return false; + } +#endif // defined(OS_CHROMEOS) + + return GetPriority() == kBackgroundPriority; +} + +bool Process::SetProcessBackgrounded(bool background) { + DCHECK(IsValid()); + +#if defined(OS_CHROMEOS) + if (CGroups::Get().enabled) { + std::string pid = IntToString(process_); + 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) + + if (!CanBackgroundProcesses()) + return false; + + int priority = background ? kBackgroundPriority : kForegroundPriority; + int result = setpriority(PRIO_PROCESS, process_, priority); + DPCHECK(result == 0); + return result == 0; +} + +#if defined(OS_CHROMEOS) +bool IsProcessBackgroundedCGroup(const StringPiece& cgroup_contents) { + // The process can be part of multiple control groups, and for each cgroup + // hierarchy there's an entry in the file. We look for a control group + // named "/chrome_renderers/background" to determine if the process is + // backgrounded. crbug.com/548818. + std::vector<StringPiece> lines = SplitStringPiece( + cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + for (const auto& line : lines) { + std::vector<StringPiece> fields = + SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL); + if (fields.size() != 3U) { + NOTREACHED(); + continue; + } + if (fields[2] == kBackground) + return true; + } + + return false; +} +#endif // defined(OS_CHROMEOS) + +#if defined(OS_CHROMEOS) +// Reads /proc/<pid>/status and returns the PID in its PID namespace. +// If the process is not in a PID namespace or /proc/<pid>/status does not +// report NSpid, kNullProcessId is returned. +ProcessId Process::GetPidInNamespace() const { + std::string status; + { + // Synchronously reading files in /proc does not hit the disk. + ThreadRestrictions::ScopedAllowIO allow_io; + FilePath status_file = + FilePath("/proc").Append(IntToString(process_)).Append("status"); + if (!ReadFileToString(status_file, &status)) { + return kNullProcessId; + } + } + + StringPairs pairs; + SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs); + for (const auto& pair : pairs) { + const std::string& key = pair.first; + const std::string& value_str = pair.second; + if (key == "NSpid") { + std::vector<StringPiece> split_value_str = SplitStringPiece( + value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + if (split_value_str.size() <= 1) { + return kNullProcessId; + } + int value; + // The last value in the list is the PID in the namespace. + if (!StringToInt(split_value_str.back(), &value)) { + NOTREACHED(); + return kNullProcessId; + } + return value; + } + } + return kNullProcessId; +} +#endif // defined(OS_CHROMEOS) + +} // namespace base |