summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-29 17:43:44 +0000
committerdavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-29 17:43:44 +0000
commit276aa6a60396329c7fb4a988bd0be7f7d0895651 (patch)
tree62ed233e5faf34a14cf99fcbe49416b64e506d23
parent57f9caa083ef107001b12ec6e455e23a5f94e420 (diff)
downloadchromium_src-276aa6a60396329c7fb4a988bd0be7f7d0895651.zip
chromium_src-276aa6a60396329c7fb4a988bd0be7f7d0895651.tar.gz
chromium_src-276aa6a60396329c7fb4a988bd0be7f7d0895651.tar.bz2
Lower priorities of background tabs on linux.
BUG=none TEST=none Review URL: http://codereview.chromium.org/345009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30470 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/base.gyp1
-rw-r--r--base/process.h41
-rw-r--r--base/process_linux.cc63
-rw-r--r--base/process_posix.cc22
-rw-r--r--base/process_util_unittest.cc14
-rw-r--r--base/process_win.cc7
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc5
7 files changed, 134 insertions, 19 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 277d2e0..7ead978 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -227,6 +227,7 @@
'profiler.cc',
'profiler.h',
'process.h',
+ 'process_linux.cc',
'process_posix.cc',
'process_util.h',
'process_util_linux.cc',
diff --git a/base/process.h b/base/process.h
index 7a1bfba..53512ce 100644
--- a/base/process.h
+++ b/base/process.h
@@ -29,11 +29,25 @@ typedef pid_t ProcessId;
const ProcessHandle kNullProcessHandle = 0;
#endif
+#if defined(OS_LINUX)
+// saved_priority_ will be set to this to indicate that it's not holding
+// a valid value. -20 to 19 are valid process priorities.
+const int kUnsetProcessPriority = 256;
+#endif
+
class Process {
public:
- Process() : process_(kNullProcessHandle), last_working_set_size_(0) {}
- explicit Process(ProcessHandle handle) :
- process_(handle), last_working_set_size_(0) {}
+ Process() : process_(kNullProcessHandle) {
+#if defined(OS_LINUX)
+ saved_priority_ = kUnsetProcessPriority;
+#endif
+ }
+
+ explicit Process(ProcessHandle handle) : process_(handle) {
+#if defined(OS_LINUX)
+ saved_priority_ = kUnsetProcessPriority;
+#endif
+ }
// A handle to the current process.
static Process Current();
@@ -41,7 +55,12 @@ class Process {
// Get/Set the handle for this process. The handle will be 0 if the process
// is no longer running.
ProcessHandle handle() const { return process_; }
- void set_handle(ProcessHandle handle) { process_ = handle; }
+ void set_handle(ProcessHandle handle) {
+ process_ = handle;
+#if defined(OS_LINUX)
+ saved_priority_ = kUnsetProcessPriority;
+#endif
+ }
// Get the PID for this process.
ProcessId pid() const;
@@ -61,16 +80,24 @@ class Process {
// Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const;
- // Set a prcess as backgrounded. If value is true, the priority
- // of the process will be lowered. If value is false, the priority
+ // Set a process as backgrounded. If value is true, the priority
+ // of the process will be lowered. If value is false, the priority
// of the process will be made "normal" - equivalent to default
// process priority.
// Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value);
+ // Returns an integer representing the priority of a process. The meaning
+ // of this value is OS dependent.
+ int GetPriority() const;
+
private:
ProcessHandle process_;
- size_t last_working_set_size_;
+#if defined(OS_LINUX)
+ // Holds the priority that the process was set to when it was backgrounded.
+ // If the process wasn't backgrounded it will be kUnsetProcessPriority.
+ int saved_priority_;
+#endif
};
} // namespace base
diff --git a/base/process_linux.cc b/base/process_linux.cc
new file mode 100644
index 0000000..30bc1f7
--- /dev/null
+++ b/base/process_linux.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2008 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/logging.h"
+
+namespace base {
+
+bool Process::IsProcessBackgrounded() const {
+ DCHECK(process_);
+ return saved_priority_ == kUnsetProcessPriority;
+}
+
+bool Process::SetProcessBackgrounded(bool background) {
+ DCHECK(process_);
+
+ 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 + 1);
+ if (result == -1) {
+ // Failed to lower priority.
+ 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
diff --git a/base/process_posix.cc b/base/process_posix.cc
index f0e019a..29166b9 100644
--- a/base/process_posix.cc
+++ b/base/process_posix.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <sys/resource.h>
+
#include "base/process.h"
#include "base/process_util.h"
@@ -9,7 +11,7 @@ namespace base {
void Process::Close() {
process_ = 0;
- // if the process wasn't termiated (so we waited) or the state
+ // if the process wasn't terminated (so we waited) or the state
// wasn't already collected w/ a wait from process_utils, we're gonna
// end up w/ a zombie when it does finally exit.
}
@@ -23,18 +25,19 @@ void Process::Terminate(int result_code) {
KillProcess(process_, result_code, false);
}
+#if !defined(OS_LINUX)
bool Process::IsProcessBackgrounded() const {
- // http://code.google.com/p/chromium/issues/detail?id=8083
+ // See SetProcessBackgrounded().
return false;
}
bool Process::SetProcessBackgrounded(bool value) {
- // http://code.google.com/p/chromium/issues/detail?id=8083
- // Just say we did it to keep renderer happy at the moment. Need to finish
- // cleaning this up w/in higher layers since windows is probably the only
- // one that can raise priorities w/o privileges.
- return true;
+ // POSIX only allows lowering the priority of a process, so if we
+ // were to lower it we wouldn't be able to raise it back to its initial
+ // priority.
+ return false;
}
+#endif
ProcessId Process::pid() const {
if (process_ == 0)
@@ -52,4 +55,9 @@ Process Process::Current() {
return Process(GetCurrentProcessHandle());
}
+int Process::GetPriority() const {
+ DCHECK(process_);
+ return getpriority(PRIO_PROCESS, process_);
+}
+
} // namspace base
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index eff8fae..e2fb5bf 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -69,6 +69,20 @@ TEST_F(ProcessUtilTest, KillSlowChild) {
base::CloseProcessHandle(handle);
}
+// Ensure that the priority of a process is restored correctly after
+// backgrounding and restoring.
+// Note: a platform may not be willing or able to lower the priority of
+// a process. The calls to SetProcessBackground should be noops then.
+TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
+ ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess");
+ Process process(handle);
+ int old_priority = process.GetPriority();
+ process.SetProcessBackgrounded(true);
+ process.SetProcessBackgrounded(false);
+ int new_priority = process.GetPriority();
+ EXPECT_EQ(old_priority, new_priority);
+}
+
// TODO(estade): if possible, port these 2 tests.
#if defined(OS_WIN)
TEST_F(ProcessUtilTest, EnableLFH) {
diff --git a/base/process_win.cc b/base/process_win.cc
index 469e7cd..cdb9390 100644
--- a/base/process_win.cc
+++ b/base/process_win.cc
@@ -25,7 +25,7 @@ void Process::Terminate(int result_code) {
bool Process::IsProcessBackgrounded() const {
if (!process_)
return false; // Failure case.
- DWORD priority = GetPriorityClass(process_);
+ DWORD priority = GetPriority();
if (priority == 0)
return false; // Failure case.
return priority == BELOW_NORMAL_PRIORITY_CLASS;
@@ -54,4 +54,9 @@ Process Process::Current() {
return Process(GetCurrentProcess());
}
+int Process::GetPriority() const {
+ DCHECK(process_);
+ return GetPriorityClass(process_);
+}
+
} // namespace base
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 43d1668..dcdea78 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -989,10 +989,7 @@ void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) {
#endif // OS_WIN
if (should_set_backgrounded) {
- bool rv = process_.SetProcessBackgrounded(backgrounded);
- if (!rv) {
- return;
- }
+ process_.SetProcessBackgrounded(backgrounded);
}
}