| // 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.h" |
| |
| #include <errno.h> |
| #include <sys/resource.h> |
| |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/stringprintf.h" |
| |
| #if defined(OS_CHROMEOS) |
| static bool use_cgroups = false; |
| static bool cgroups_inited = false; |
| static const char kForegroundTasks[] = |
| "/tmp/cgroup/cpu/chrome_renderers/foreground/tasks"; |
| static const char kBackgroundTasks[] = |
| "/tmp/cgroup/cpu/chrome_renderers/background/tasks"; |
| static FilePath foreground_tasks; |
| static FilePath background_tasks; |
| #endif |
| |
| namespace base { |
| |
| #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. |
| const int kPriorityAdjustment = 19; |
| #else |
| const int kPriorityAdjustment = 5; |
| #endif |
| |
| bool Process::IsProcessBackgrounded() const { |
| DCHECK(process_); |
| return saved_priority_ == kUnsetProcessPriority; |
| } |
| |
| bool Process::SetProcessBackgrounded(bool background) { |
| DCHECK(process_); |
| |
| #if defined(OS_CHROMEOS) |
| // Check for cgroups files. ChromeOS supports these by default. It creates |
| // a cgroup mount in /tmp/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. |
| if (!cgroups_inited) { |
| cgroups_inited = true; |
| foreground_tasks = FilePath(kForegroundTasks); |
| background_tasks = FilePath(kBackgroundTasks); |
| file_util::FileSystemType foreground_type; |
| file_util::FileSystemType background_type; |
| use_cgroups = |
| file_util::GetFileSystemType(foreground_tasks, &foreground_type) && |
| file_util::GetFileSystemType(background_tasks, &background_type) && |
| foreground_type == file_util::FILE_SYSTEM_CGROUP && |
| background_type == file_util::FILE_SYSTEM_CGROUP; |
| } |
| |
| if (use_cgroups) { |
| if (background) { |
| std::string pid = StringPrintf("%d", process_); |
| if (file_util::WriteFile(background_tasks, pid.c_str(), pid.size()) > 0) { |
| // With cgroups there's no real notion of priority as an int, but this |
| // will ensure we only move renderers back to the foreground group |
| // if we've ever put them in the background one. |
| saved_priority_ = 0; |
| return true; |
| } else { |
| return false; |
| } |
| } else { |
| if (saved_priority_ == kUnsetProcessPriority) { |
| // Can't restore if we were never backgrounded. |
| return false; |
| } |
| std::string pid = StringPrintf("%d", process_); |
| if (file_util::WriteFile(foreground_tasks, pid.c_str(), pid.size()) > 0) { |
| saved_priority_ = kUnsetProcessPriority; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| } |
| #endif // OS_CHROMEOS |
| |
| if (background) { |
| // 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; |
| if (getrlimit(RLIMIT_NICE, &rlim) != 0) { |
| // Call to getrlimit failed, don't background. |
| return false; |
| } |
| errno = 0; |
| int current_priority = GetPriority(); |
| if (errno) { |
| // Couldn't get priority. |
| return false; |
| } |
| // {set,get}priority values are in the range -20 to 19, where -1 is higher |
| // priority than 0. But rlimit's are in the range from 0 to 39 where |
| // 1 is higher than 0. |
| if ((20 - current_priority) > static_cast<int>(rlim.rlim_cur)) { |
| // User is not allowed to raise the priority back to where it is now. |
| return false; |
| } |
| int result = |
| setpriority( |
| PRIO_PROCESS, process_, current_priority + kPriorityAdjustment); |
| if (result == -1) { |
| LOG(ERROR) << "Failed to lower priority, errno: " << errno; |
| return false; |
| } |
| saved_priority_ = current_priority; |
| return true; |
| } else { |
| if (saved_priority_ == kUnsetProcessPriority) { |
| // Can't restore if we were never backgrounded. |
| return false; |
| } |
| int result = setpriority(PRIO_PROCESS, process_, saved_priority_); |
| // If we can't restore something has gone terribly wrong. |
| DPCHECK(result == 0); |
| saved_priority_ = kUnsetProcessPriority; |
| return true; |
| } |
| } |
| |
| } // namespace base |