Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(580)

Side by Side Diff: base/process_linux.cc

Issue 8506036: Fix tab backgrounding on Linux / ChromeOS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated license Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/process.h ('k') | base/process_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/process.h" 5 #include "base/process.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <sys/resource.h> 8 #include <sys/resource.h>
9 9
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/lazy_instance.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/stringprintf.h" 13 #include "base/stringprintf.h"
14 #include "base/string_split.h"
15 #include "base/synchronization/lock.h"
13 16
14 namespace base { 17 namespace {
18 const int kForegroundPriority = 0;
15 19
16 #if defined(OS_CHROMEOS) 20 #if defined(OS_CHROMEOS)
17 // We are more aggressive in our lowering of background process priority 21 // We are more aggressive in our lowering of background process priority
18 // for chromeos as we have much more control over other processes running 22 // for chromeos as we have much more control over other processes running
19 // on the machine. 23 // on the machine.
20 const int kPriorityAdjustment = 19; 24 //
25 // TODO(davemoore) Refactor this by adding support for higher levels to set
26 // the foregrounding / backgrounding process so we don't have to keep
27 // chrome / chromeos specific logic here.
28 const int kBackgroundPriority = 19;
29 const char kControlPath[] = "/tmp/cgroup/cpu%s/cgroup.procs";
30 const char kForeground[] = "/chrome_renderers/foreground";
31 const char kBackground[] = "/chrome_renderers/background";
32 const char kProcPath[] = "/proc/%d/cgroup";
33
34 struct CGroups {
35 // Check for cgroups files. ChromeOS supports these by default. It creates
36 // a cgroup mount in /tmp/cgroup and then configures two cpu task groups,
37 // one contains at most a single foreground renderer and the other contains
38 // all background renderers. This allows us to limit the impact of background
39 // renderers on foreground ones to a greater level than simple renicing.
40 bool enabled;
41 FilePath foreground_file;
42 FilePath background_file;
43
44 CGroups() {
45 foreground_file = FilePath(StringPrintf(kControlPath, kForeground));
46 background_file = FilePath(StringPrintf(kControlPath, kBackground));
47 file_util::FileSystemType foreground_type;
48 file_util::FileSystemType background_type;
49 enabled =
50 file_util::GetFileSystemType(foreground_file, &foreground_type) &&
51 file_util::GetFileSystemType(background_file, &background_type) &&
52 foreground_type == file_util::FILE_SYSTEM_CGROUP &&
53 background_type == file_util::FILE_SYSTEM_CGROUP;
54 }
55 };
56
57 base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
21 #else 58 #else
22 const int kPriorityAdjustment = 5; 59 const int kBackgroundPriority = 5;
23 #endif 60 #endif
61 }
62
63 namespace base {
24 64
25 bool Process::IsProcessBackgrounded() const { 65 bool Process::IsProcessBackgrounded() const {
26 DCHECK(process_); 66 DCHECK(process_);
27 return saved_priority_ == kUnsetProcessPriority; 67
68 #if defined(OS_CHROMEOS)
69 if (cgroups.Get().enabled) {
70 std::string proc;
71 if (file_util::ReadFileToString(
72 FilePath(StringPrintf(kProcPath, process_)),
73 &proc)) {
74 std::vector<std::string> proc_parts;
75 base::SplitString(proc, ':', &proc_parts);
76 DCHECK(proc_parts.size() == 3);
77 bool ret = proc_parts[2] == std::string(kBackground);
78 return ret;
79 } else {
80 return false;
81 }
82 }
83 #endif
84 return GetPriority() == kBackgroundPriority;
28 } 85 }
29 86
30 bool Process::SetProcessBackgrounded(bool background) { 87 bool Process::SetProcessBackgrounded(bool background) {
31 DCHECK(process_); 88 DCHECK(process_);
32 89
33 #if defined(OS_CHROMEOS) 90 #if defined(OS_CHROMEOS)
34 static bool cgroups_inited = false; 91 if (cgroups.Get().enabled) {
35 static bool use_cgroups = false; 92 std::string pid = StringPrintf("%d", process_);
36 93 const FilePath file =
37 // Check for cgroups files. ChromeOS supports these by default. It creates 94 background ?
38 // a cgroup mount in /tmp/cgroup and then configures two cpu task groups, 95 cgroups.Get().background_file : cgroups.Get().foreground_file;
39 // one contains at most a single foreground renderer and the other contains 96 return file_util::WriteFile(file, pid.c_str(), pid.size()) > 0;
40 // all background renderers. This allows us to limit the impact of background
41 // renderers on foreground ones to a greater level than simple renicing.
42 FilePath foreground_tasks(
43 "/tmp/cgroup/cpu/chrome_renderers/foreground/tasks");
44 FilePath background_tasks(
45 "/tmp/cgroup/cpu/chrome_renderers/background/tasks");
46 if (!cgroups_inited) {
47 cgroups_inited = true;
48 file_util::FileSystemType foreground_type;
49 file_util::FileSystemType background_type;
50 use_cgroups =
51 file_util::GetFileSystemType(foreground_tasks, &foreground_type) &&
52 file_util::GetFileSystemType(background_tasks, &background_type) &&
53 foreground_type == file_util::FILE_SYSTEM_CGROUP &&
54 background_type == file_util::FILE_SYSTEM_CGROUP;
55 }
56
57 if (use_cgroups) {
58 if (background) {
59 std::string pid = StringPrintf("%d", process_);
60 if (file_util::WriteFile(background_tasks, pid.c_str(), pid.size()) > 0) {
61 // With cgroups there's no real notion of priority as an int, but this
62 // will ensure we only move renderers back to the foreground group
63 // if we've ever put them in the background one.
64 saved_priority_ = 0;
65 return true;
66 } else {
67 return false;
68 }
69 } else {
70 if (saved_priority_ == kUnsetProcessPriority) {
71 // Can't restore if we were never backgrounded.
72 return false;
73 }
74 std::string pid = StringPrintf("%d", process_);
75 if (file_util::WriteFile(foreground_tasks, pid.c_str(), pid.size()) > 0) {
76 saved_priority_ = kUnsetProcessPriority;
77 return true;
78 } else {
79 return false;
80 }
81 }
82 } 97 }
83 #endif // OS_CHROMEOS 98 #endif // OS_CHROMEOS
84 99
85 if (background) { 100 if (!CanBackgroundProcesses())
101 return false;
102
103 int priority = background ? kBackgroundPriority : kForegroundPriority;
104 int result = setpriority(PRIO_PROCESS, process_, priority);
105 DPCHECK(result == 0);
106 return result == 0;
107 }
108
109 struct CheckForNicePermission {
110 bool can_reraise_priority;
111
112 CheckForNicePermission() {
86 // We won't be able to raise the priority if we don't have the right rlimit. 113 // We won't be able to raise the priority if we don't have the right rlimit.
87 // The limit may be adjusted in /etc/security/limits.conf for PAM systems. 114 // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
88 struct rlimit rlim; 115 struct rlimit rlim;
89 if (getrlimit(RLIMIT_NICE, &rlim) != 0) { 116 if ((getrlimit(RLIMIT_NICE, &rlim) == 0) &&
90 // Call to getrlimit failed, don't background. 117 (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur)) {
91 return false; 118 can_reraise_priority = true;
92 } 119 }
93 errno = 0; 120 };
94 int current_priority = GetPriority(); 121 };
95 if (errno) { 122
96 // Couldn't get priority. 123 // static
97 return false; 124 bool Process::CanBackgroundProcesses() {
98 } 125 #if defined(OS_CHROMEOS)
99 // {set,get}priority values are in the range -20 to 19, where -1 is higher 126 if (cgroups.Get().enabled)
100 // priority than 0. But rlimit's are in the range from 0 to 39 where
101 // 1 is higher than 0.
102 if ((20 - current_priority) > static_cast<int>(rlim.rlim_cur)) {
103 // User is not allowed to raise the priority back to where it is now.
104 return false;
105 }
106 int result =
107 setpriority(
108 PRIO_PROCESS, process_, current_priority + kPriorityAdjustment);
109 if (result == -1) {
110 DLOG(ERROR) << "Failed to lower priority, errno: " << errno;
111 return false;
112 }
113 saved_priority_ = current_priority;
114 return true; 127 return true;
115 } else { 128 #endif
116 if (saved_priority_ == kUnsetProcessPriority) { 129
117 // Can't restore if we were never backgrounded. 130 static LazyInstance<CheckForNicePermission> check_for_nice_permission =
118 return false; 131 LAZY_INSTANCE_INITIALIZER;
119 } 132 return check_for_nice_permission.Get().can_reraise_priority;
120 int result = setpriority(PRIO_PROCESS, process_, saved_priority_);
121 // If we can't restore something has gone terribly wrong.
122 DPCHECK(result == 0);
123 saved_priority_ = kUnsetProcessPriority;
124 return true;
125 }
126 } 133 }
127 134
128 } // namespace base 135 } // namespace base
OLDNEW
« no previous file with comments | « base/process.h ('k') | base/process_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698