1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/process.h" 6 7 #include <errno.h> 8 #include <sys/resource.h> 9 10 #include "base/file_util.h" 11 #include "base/logging.h" 12 #include "base/stringprintf.h" 13 14 #if defined(OS_CHROMEOS) 15 static bool use_cgroups = false; 16 static bool cgroups_inited = false; 17 static const char kForegroundTasks[] = 18 "/tmp/cgroup/cpu/chrome_renderers/foreground/tasks"; 19 static const char kBackgroundTasks[] = 20 "/tmp/cgroup/cpu/chrome_renderers/background/tasks"; 21 static FilePath foreground_tasks; 22 static FilePath background_tasks; 23 #endif 24 25 namespace base { 26 27 #if defined(OS_CHROMEOS) 28 // We are more aggressive in our lowering of background process priority 29 // for chromeos as we have much more control over other processes running 30 // on the machine. 31 const int kPriorityAdjustment = 19; 32 #else 33 const int kPriorityAdjustment = 5; 34 #endif 35 36 bool Process::IsProcessBackgrounded() const { 37 DCHECK(process_); 38 return saved_priority_ == kUnsetProcessPriority; 39 } 40 41 bool Process::SetProcessBackgrounded(bool background) { 42 DCHECK(process_); 43 44 #if defined(OS_CHROMEOS) 45 // Check for cgroups files. ChromeOS supports these by default. It creates 46 // a cgroup mount in /tmp/cgroup and then configures two cpu task groups, 47 // one contains at most a single foreground renderer and the other contains 48 // all background renderers. This allows us to limit the impact of background 49 // renderers on foreground ones to a greater level than simple renicing. 50 if (!cgroups_inited) { 51 cgroups_inited = true; 52 foreground_tasks = FilePath(kForegroundTasks); 53 background_tasks = FilePath(kBackgroundTasks); 54 file_util::FileSystemType foreground_type; 55 file_util::FileSystemType background_type; 56 use_cgroups = 57 file_util::GetFileSystemType(foreground_tasks, &foreground_type) && 58 file_util::GetFileSystemType(background_tasks, &background_type) && 59 foreground_type == file_util::FILE_SYSTEM_CGROUP && 60 background_type == file_util::FILE_SYSTEM_CGROUP; 61 } 62 63 if (use_cgroups) { 64 if (background) { 65 std::string pid = StringPrintf("%d", process_); 66 if (file_util::WriteFile(background_tasks, pid.c_str(), pid.size()) > 0) { 67 // With cgroups there's no real notion of priority as an int, but this 68 // will ensure we only move renderers back to the foreground group 69 // if we've ever put them in the background one. 70 saved_priority_ = 0; 71 return true; 72 } else { 73 return false; 74 } 75 } else { 76 if (saved_priority_ == kUnsetProcessPriority) { 77 // Can't restore if we were never backgrounded. 78 return false; 79 } 80 std::string pid = StringPrintf("%d", process_); 81 if (file_util::WriteFile(foreground_tasks, pid.c_str(), pid.size()) > 0) { 82 saved_priority_ = kUnsetProcessPriority; 83 return true; 84 } else { 85 return false; 86 } 87 } 88 } 89 #endif // OS_CHROMEOS 90 91 if (background) { 92 // We won't be able to raise the priority if we don't have the right rlimit. 93 // The limit may be adjusted in /etc/security/limits.conf for PAM systems. 94 struct rlimit rlim; 95 if (getrlimit(RLIMIT_NICE, &rlim) != 0) { 96 // Call to getrlimit failed, don't background. 97 return false; 98 } 99 errno = 0; 100 int current_priority = GetPriority(); 101 if (errno) { 102 // Couldn't get priority. 103 return false; 104 } 105 // {set,get}priority values are in the range -20 to 19, where -1 is higher 106 // priority than 0. But rlimit's are in the range from 0 to 39 where 107 // 1 is higher than 0. 108 if ((20 - current_priority) > static_cast<int>(rlim.rlim_cur)) { 109 // User is not allowed to raise the priority back to where it is now. 110 return false; 111 } 112 int result = 113 setpriority( 114 PRIO_PROCESS, process_, current_priority + kPriorityAdjustment); 115 if (result == -1) { 116 LOG(ERROR) << "Failed to lower priority, errno: " << errno; 117 return false; 118 } 119 saved_priority_ = current_priority; 120 return true; 121 } else { 122 if (saved_priority_ == kUnsetProcessPriority) { 123 // Can't restore if we were never backgrounded. 124 return false; 125 } 126 int result = setpriority(PRIO_PROCESS, process_, saved_priority_); 127 // If we can't restore something has gone terribly wrong. 128 DPCHECK(result == 0); 129 saved_priority_ = kUnsetProcessPriority; 130 return true; 131 } 132 } 133 134 } // namespace base 135