base: Allow renderer thread priorities to be changed.
This provides a mechanism for a renderer to change the priority of
its threads and as a result also the cpuset they are assigned to.
A ChildProcessHost IPC message from the renderer is used to request
a thread priority change and have the browser process identify the
renderer thread that is requesting a priority change by checking all
its threads to find a thread with NSpid field in
/proc/[pid]/task/[thread_id]/status that matches the namespace tid
from the renderer.
This is currently limited to Linux and ChromeOS but follow up work
will investigate the possibility and benefits of doing the same on
other platforms.
Note: Thread priorities in the renderer are already adjusted in a
similar way on Android as the sandbox is not strict enough to
prevent this on Android today.
BUG=chrome-os-partner:56550
TEST=
Review-Url: https://codereview.chromium.org/2334533002
Cr-Commit-Position: refs/heads/master@{#419649}
diff --git a/base/linux_util.cc b/base/linux_util.cc
index 74ac98f..bf50471 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -20,6 +20,8 @@
#include "base/files/file_util.h"
#include "base/memory/singleton.h"
#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
@@ -72,6 +74,28 @@
};
#endif // if defined(OS_LINUX)
+bool GetTasksForProcess(pid_t pid, std::vector<pid_t>* tids) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+
+ DIR* task = opendir(buf);
+ if (!task) {
+ DLOG(WARNING) << "Cannot open " << buf;
+ return false;
+ }
+
+ struct dirent* dent;
+ while ((dent = readdir(task))) {
+ char* endptr;
+ const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
+ if (tid_ul == ULONG_MAX || *endptr)
+ continue;
+ tids->push_back(tid_ul);
+ }
+ closedir(task);
+ return true;
+}
+
} // namespace
namespace base {
@@ -132,34 +156,17 @@
pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
bool* syscall_supported) {
- char buf[256];
- snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
-
if (syscall_supported != NULL)
*syscall_supported = false;
- DIR* task = opendir(buf);
- if (!task) {
- DLOG(WARNING) << "Cannot open " << buf;
- return -1;
- }
-
std::vector<pid_t> tids;
- struct dirent* dent;
- while ((dent = readdir(task))) {
- char* endptr;
- const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
- if (tid_ul == ULONG_MAX || *endptr)
- continue;
- tids.push_back(tid_ul);
- }
- closedir(task);
+ if (!GetTasksForProcess(pid, &tids))
+ return -1;
std::unique_ptr<char[]> syscall_data(new char[expected_data.length()]);
- for (std::vector<pid_t>::const_iterator
- i = tids.begin(); i != tids.end(); ++i) {
- const pid_t current_tid = *i;
- snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid);
+ for (pid_t tid : tids) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, tid);
int fd = open(buf, O_RDONLY);
if (fd < 0)
continue;
@@ -172,7 +179,45 @@
if (0 == strncmp(expected_data.c_str(), syscall_data.get(),
expected_data.length())) {
- return current_tid;
+ return tid;
+ }
+ }
+ return -1;
+}
+
+pid_t FindThreadID(pid_t pid, pid_t ns_tid, bool* ns_pid_supported) {
+ if (ns_pid_supported)
+ *ns_pid_supported = false;
+
+ std::vector<pid_t> tids;
+ if (!GetTasksForProcess(pid, &tids))
+ return -1;
+
+ for (pid_t tid : tids) {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "/proc/%d/task/%d/status", pid, tid);
+ std::string status;
+ if (!ReadFileToString(FilePath(buf), &status))
+ return -1;
+ StringPairs pairs;
+ SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
+ for (const auto& pair : pairs) {
+ const std::string& key = pair.first;
+ const std::string& value_str = pair.second;
+ if (key == "NSpid") {
+ if (ns_pid_supported)
+ *ns_pid_supported = true;
+ std::vector<StringPiece> split_value_str = SplitStringPiece(
+ value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ DCHECK_NE(split_value_str.size(), 0u);
+ int value;
+ // The last value in the list is the PID in the namespace.
+ if (StringToInt(split_value_str.back(), &value) && value == ns_tid) {
+ // The first value in the list is the real PID.
+ if (StringToInt(split_value_str.front(), &value))
+ return value;
+ }
+ }
}
}
return -1;