2
* Copyright (C) 2014 Canonical, Ltd.
4
* This program is free software: you can redistribute it and/or modify it under
5
* the terms of the GNU Lesser General Public License version 3, as published by
6
* the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10
* SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
#include "processcontroller.h"
23
#include <core/posix/process.h>
24
#include <core/posix/this_process.h>
25
#include <core/posix/linux/proc/process/oom_adj.h>
26
#include <core/posix/linux/proc/process/oom_score_adj.h>
34
* This class manages individual processes during their lifetime. It allows one to pause
35
* and resume processes.
37
* It also has methods to set a score on processes which is used by the Out of Memory (OOM)
38
* process killer to decide what process gets killed in a low memory situation.
41
namespace plpp = core::posix::linux::proc::process;
46
ProcessController::OomController::OomController()
51
* \brief ProcessController::OomController::ensureProcessLikelyToBeKilled
53
* Set the process OOM-killer score so that the process is _more_ likely to be killed
54
* in a low memory situation
58
* Useful information about these OOM-weighting methods
60
* the "Process C++" library wraps some APIs exported by the kernel in the the /proc filesystem.
61
* The OOM score is one of these, but the APIs for it changed from Linux 2.6.36 onward.
63
* === Up to Linux 2.6.36 ===
64
* /proc/[pid]/oom_adj (wrapped by plpp::OomAdj) was used up to 2.6.36 (is deprecated now)
65
* Valid values are in the range -16 to +15, plus the special value -17, which disables
66
* OOM-killing altogether for this process. A positive score increases the likelihood
67
* of this process being killed by the OOM-killer; a negative score decreases the likelihood.
69
* The default value for this file is 0; a new process inherits its parent's oom_adj setting.
71
* === Linux 2.6.36 and later ===
72
* /proc/[pid]/oom_score_adj (wrapped by plpp::OomScoreAdj) is the recommended API. Valid
73
* values are in the range -1000 (never kill) to 1000 (always kill).
75
* For backward compatibility with previous kernels, /proc/[pid]/oom_adj can still be used to
76
* tune the badness score. Its value is scaled linearly with oom_score_adj. So writing to
77
* /proc/[pid]/oom_score_adj or /proc/[pid]/oom_adj will change the other with its scaled value.
79
* === How OOM score changing is implemented ===
80
* To support all available kernels, we thus perform the following for any OOM score change:
81
* 1. Attempt to use the newer kernel API (plpp::OomScoreAdj). Fetch the min & max possible
82
* values and calculate a desired score for the process.
83
* 2. If that fails, fall back to the older kernel API (plpp::OomSAdj), again fetching min
84
* & max possible values and calculating a desired score for the process.
86
void ProcessController::OomController::ensureProcessLikelyToBeKilled(pid_t pid)
88
// We avoid boundary values for oom_score_adj. For that, we
89
// set it to 80% of the total available range.
90
static const float defaultPercentage = 0.8;
92
core::posix::Process process(pid);
95
plpp::OomScoreAdj shellScore;
96
core::posix::this_process::instance() >> shellScore;
98
plpp::OomScoreAdj processScore
100
static_cast<int>((plpp::OomScoreAdj::max_value() - shellScore.value) * defaultPercentage) + shellScore.value
103
process << processScore;
105
// Accessing OomScoreAdj resulted in an exception being thrown.
106
// Trying with the deprecated OomAdj now as a last resort.
109
process << plpp::OomAdj{plpp::OomAdj::max_value()};
112
qDebug() << "ensureProcessIsLikelyToBeKilled failed for pid=" << pid;
118
* \brief ProcessController::OomController::ensureProcessLessLikelyToBeKilled
120
* Set the process OOM-killer score so that, in a low memory situation, the process
121
* is _more_ likely to be killed than the foreground application, but less likely
122
* than the background applications
124
void ProcessController::OomController::ensureProcessLessLikelyToBeKilled(pid_t pid)
126
// Set it to 50% of the total available range.
127
static const float defaultPercentage = 0.5;
129
core::posix::Process process(pid);
132
plpp::OomScoreAdj shellScore;
133
core::posix::this_process::instance() >> shellScore;
135
plpp::OomScoreAdj processScore
137
static_cast<int>((plpp::OomScoreAdj::max_value() - shellScore.value) * defaultPercentage) + shellScore.value
140
process << processScore;
142
// Accessing OomScoreAdj resulted in an exception being thrown.
143
// Trying with the deprecated OomAdj now as a last resort.
146
process << plpp::OomAdj{plpp::OomAdj::max_value()};
149
qDebug() << "ensureProcessIsLessLikelyToBeKilled failed for pid=" << pid;
155
* \brief ProcessController::OomController::ensureProcessUnlikelyToBeKilled
157
* Set the process OOM-killer weighting so that the process is _less_ likely to be killed
158
* in a low memory situation
160
void ProcessController::OomController::ensureProcessUnlikelyToBeKilled(pid_t pid)
162
// By system default, we set the oom_score_adj of Unity8 to -10 (via lightdm).
163
// As we want to avoid that any app's oom_score_adj is <= Unity8's oom_score_adj,
164
// (i.e. Unity8 would be killed before that app is) we choose a default increase of +1.
165
static const int default_increase = 1;
167
core::posix::Process process(pid);
170
plpp::OomScoreAdj shellScore;
171
core::posix::this_process::instance() >> shellScore;
173
plpp::OomScoreAdj processScore
175
shellScore.value + default_increase
178
process << processScore;
180
// Accessing OomScoreAdj resulted in an exception being thrown.
181
// Trying with the deprecated OomAdj now as a last resort.
182
// By system default, we set the oom_score_adj of Unity8 to -10 (via lightdm).
183
// As we want to avoid that any app's oom_score_adj or oom_adj is <= Unity8's oom_score_adj,
184
// we choose a default value of -9 for oom_score_adj and 0 for oom_adj.
185
static const int defaultValue = 0;
189
process << plpp::OomAdj{defaultValue};
192
qDebug() << "ensureProcessIsUnlikelyToBeKilled failed for pid" << pid;
197
ProcessController::ProcessController()
198
: m_oomController(new ProcessController::OomController())
202
ProcessController::~ProcessController()
206
const QSharedPointer<ProcessController::OomController>& ProcessController::oomController() const
208
return m_oomController;
212
* \brief ProcessController::sigStopProcessGroupForPid
214
* \return True if process was stopped successfully, false otherwise
216
bool ProcessController::sigStopProcessGroupForPid(pid_t pid) const
218
return -1 != kill(-pid, SIGSTOP);
222
* \brief ProcessController::sigContinueProcessGroupForPid
224
* \return True of process was resumed successfully, false otherwise
226
bool ProcessController::sigContinueProcessGroupForPid(pid_t pid) const
228
return -1 != kill(-pid, SIGCONT);