diff options
author | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-29 17:43:44 +0000 |
---|---|---|
committer | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-29 17:43:44 +0000 |
commit | 276aa6a60396329c7fb4a988bd0be7f7d0895651 (patch) | |
tree | 62ed233e5faf34a14cf99fcbe49416b64e506d23 | |
parent | 57f9caa083ef107001b12ec6e455e23a5f94e420 (diff) | |
download | chromium_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.gyp | 1 | ||||
-rw-r--r-- | base/process.h | 41 | ||||
-rw-r--r-- | base/process_linux.cc | 63 | ||||
-rw-r--r-- | base/process_posix.cc | 22 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 14 | ||||
-rw-r--r-- | base/process_win.cc | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 5 |
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); } } |