summaryrefslogtreecommitdiffstats
path: root/chromium/base/process/process_linux.cc
blob: b12e994848d67e4ef4ff9002fe6faf52fcb56031 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2011 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/process.h"

#include <errno.h>
#include <sys/resource.h>

#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"

namespace {
const int kForegroundPriority = 0;

#if defined(OS_CHROMEOS)
// We are more aggressive in our lowering of background process priority
// for chromeos as we have much more control over other processes running
// on the machine.
//
// TODO(davemoore) Refactor this by adding support for higher levels to set
// the foregrounding / backgrounding process so we don't have to keep
// chrome / chromeos specific logic here.
const int kBackgroundPriority = 19;
const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
const char kForeground[] = "/chrome_renderers/foreground";
const char kBackground[] = "/chrome_renderers/background";
const char kProcPath[] = "/proc/%d/cgroup";

struct CGroups {
  // Check for cgroups files. ChromeOS supports these by default. It creates
  // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
  // one contains at most a single foreground renderer and the other contains
  // all background renderers. This allows us to limit the impact of background
  // renderers on foreground ones to a greater level than simple renicing.
  bool enabled;
  base::FilePath foreground_file;
  base::FilePath background_file;

  CGroups() {
    foreground_file =
        base::FilePath(base::StringPrintf(kControlPath, kForeground));
    background_file =
        base::FilePath(base::StringPrintf(kControlPath, kBackground));
    file_util::FileSystemType foreground_type;
    file_util::FileSystemType background_type;
    enabled =
        file_util::GetFileSystemType(foreground_file, &foreground_type) &&
        file_util::GetFileSystemType(background_file, &background_type) &&
        foreground_type == file_util::FILE_SYSTEM_CGROUP &&
        background_type == file_util::FILE_SYSTEM_CGROUP;
  }
};

base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
#else
const int kBackgroundPriority = 5;
#endif
}

namespace base {

bool Process::IsProcessBackgrounded() const {
  DCHECK(process_);

#if defined(OS_CHROMEOS)
  if (cgroups.Get().enabled) {
    std::string proc;
    if (base::ReadFileToString(
            base::FilePath(StringPrintf(kProcPath, process_)),
            &proc)) {
      std::vector<std::string> proc_parts;
      base::SplitString(proc, ':', &proc_parts);
      DCHECK(proc_parts.size() == 3);
      bool ret = proc_parts[2] == std::string(kBackground);
      return ret;
    } else {
      return false;
    }
  }
#endif
  return GetPriority() == kBackgroundPriority;
}

bool Process::SetProcessBackgrounded(bool background) {
  DCHECK(process_);

#if defined(OS_CHROMEOS)
  if (cgroups.Get().enabled) {
    std::string pid = StringPrintf("%d", process_);
    const base::FilePath file =
        background ?
            cgroups.Get().background_file : cgroups.Get().foreground_file;
    return file_util::WriteFile(file, pid.c_str(), pid.size()) > 0;
  }
#endif // OS_CHROMEOS

  if (!CanBackgroundProcesses())
    return false;

  int priority = background ? kBackgroundPriority : kForegroundPriority;
  int result = setpriority(PRIO_PROCESS, process_, priority);
  DPCHECK(result == 0);
  return result == 0;
}

struct CheckForNicePermission {
  CheckForNicePermission() : can_reraise_priority(false) {
    // 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) &&
        (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur)) {
        can_reraise_priority = true;
    }
  };

  bool can_reraise_priority;
};

// static
bool Process::CanBackgroundProcesses() {
#if defined(OS_CHROMEOS)
  if (cgroups.Get().enabled)
    return true;
#endif

  static LazyInstance<CheckForNicePermission> check_for_nice_permission =
      LAZY_INSTANCE_INITIALIZER;
  return check_for_nice_permission.Get().can_reraise_priority;
}

}  // namespace base