~ubuntu-branches/ubuntu/trusty/unity-mir/trusty-proposed

« back to all changes in this revision

Viewing changes to src/modules/Unity/Application/taskcontroller.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, thomas-voss, Ricardo Mendoza, Ubuntu daily release
  • Date: 2013-10-16 11:01:55 UTC
  • mfrom: (1.1.31)
  • Revision ID: package-import@ubuntu.com-20131016110155-mfvpv1v3uz8369ad
Tags: 0.1+13.10.20131016-0ubuntu1
[ thomas-voss ]
* Slightly refactor the OOM adjustments to be a pure implementation
  detail of the TaskManager. (LP: #1238691)

[ Ricardo Mendoza ]
* Slightly refactor the OOM adjustments to be a pure implementation
  detail of the TaskManager. (LP: #1238691)

[ Ubuntu daily release ]
* Automatic snapshot from revision 127

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#include <signal.h>
33
33
#include <unistd.h>
34
34
 
 
35
// linux specific
 
36
#include <linux/oom.h>
 
37
 
 
38
namespace
 
39
{
 
40
/**
 
41
 * From man proc:
 
42
 *
 
43
 * This file can be used to adjust the score used to select which
 
44
 * process should be killed in an out-of-memory (OOM) situation.  The
 
45
 * kernel uses this value for a bit-shift opera‐ tion of the process's
 
46
 * oom_score value: valid values are in the range -16 to +15, plus the
 
47
 * special value -17, which disables OOM-killing altogether for this
 
48
 * process.  A posi‐ tive score increases the likelihood of this process
 
49
 * being killed by the OOM-killer; a negative score decreases the
 
50
 * likelihood.
 
51
 *
 
52
 * The default value for this file is 0; a new process inherits its
 
53
 * parent's oom_adj setting.  A process must be privileged
 
54
 * (CAP_SYS_RESOURCE) to update this file.
 
55
 
 
56
 * Since Linux 2.6.36, use of this file is deprecated in favor of
 
57
 * /proc/[pid]/oom_score_adj.
 
58
 */
 
59
struct OomAdjuster
 
60
{
 
61
    static int disableOomKillerValue()
 
62
    {
 
63
        return OOM_DISABLE;
 
64
    }
 
65
 
 
66
    static int minValue()
 
67
    {
 
68
        return OOM_ADJUST_MIN;
 
69
    }
 
70
 
 
71
    static int maxValue()
 
72
    {
 
73
        return OOM_ADJUST_MAX;
 
74
    }
 
75
 
 
76
    static OomAdjuster leastLikelyToBeKilled()
 
77
    {
 
78
        return OomAdjuster(minValue());
 
79
    }
 
80
 
 
81
    static OomAdjuster mostLikelyToBeKilled()
 
82
    {
 
83
        return OomAdjuster(maxValue());
 
84
    }
 
85
 
 
86
    OomAdjuster(int value) : value(value)
 
87
    {
 
88
    }
 
89
 
 
90
    bool isValid() const
 
91
    {
 
92
        return !(value < disableOomKillerValue() || value > maxValue());
 
93
    }
 
94
 
 
95
    bool applyForPid(pid_t pid) const
 
96
    {
 
97
        auto fn = QString("/proc/%1/oom_adj").arg(pid);
 
98
        QFile file(fn);
 
99
        
 
100
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
 
101
            return false;
 
102
 
 
103
        QTextStream out(&file);
 
104
        out << value;
 
105
 
 
106
        return true;
 
107
    }
 
108
 
 
109
    int value;
 
110
};
 
111
 
 
112
/**
 
113
 * From man proc:
 
114
 *
 
115
 *  This file can be used to adjust the badness heuristic used to
 
116
 *  select which process gets killed in out-of-memory conditions.
 
117
 *
 
118
 *  The badness heuristic assigns a value to each candidate
 
119
 *  task ranging from 0 (never kill) to 1000 (always kill)
 
120
 *  to determine which process is targeted.  The units are
 
121
 *  roughly a proportion along that range of allowed memory
 
122
 *  the process may allocate from, based on an estimation of
 
123
 *  its current memory and swap use.  For example, if a task
 
124
 *  is using all allowed memory, its badness score will be
 
125
 *  1000.  If it is using half of its allowed memory, its
 
126
 *  score will be 500.
 
127
 *
 
128
 *  There is an additional factor included in the badness score: root
 
129
 *  processes are given 3% extra memory over other tasks.
 
130
 *
 
131
 *  The amount of "allowed" memory depends on the context in
 
132
 *  which the OOM-killer was called.  If it is due to the
 
133
 *  memory assigned to the allocating task's cpuset being
 
134
 *  exhausted, the allowed memory represents the set of mems
 
135
 *  assigned to that cpuset (see cpuset(7)).  If it is due
 
136
 *  to a mempolicy's node(s) being exhausted, the allowed
 
137
 *  memory represents the set of mempolicy nodes.  If it is
 
138
 *  due to a memory limit (or swap limit) being reached, the
 
139
 *  allowed memory is that configured limit.  Finally, if it
 
140
 *  is due to the entire system being out of memory, the
 
141
 *  allowed memory represents all allocatable resources.
 
142
 *
 
143
 *  The value of oom_score_adj is added to the badness score before it
 
144
 *  is used to determine which task to kill.  Acceptable values range
 
145
 *  from -1000 (OOM_SCORE_ADJ_MIN) to +1000 (OOM_SCORE_ADJ_MAX).  This
 
146
 *  allows user space to control the preference for OOM-killing,
 
147
 *  ranging from always preferring a certain task or completely
 
148
 *  disabling it from OOM- killing.  The lowest possible value, -1000,
 
149
 *  is equivalent to disabling OOM-killing entirely for that task,
 
150
 *  since it will always report a badness score of 0.
 
151
 *
 
152
 *  Consequently, it is very simple for user space to define the amount
 
153
 *  of memory to consider for each task.  Setting a oom_score_adj value
 
154
 *  of +500, for example, is roughly equiv‐ alent to allowing the
 
155
 *  remainder of tasks sharing the same system, cpuset, mempolicy, or
 
156
 *  memory controller resources to use at least 50% more memory.  A
 
157
 *  value of -500, on the other hand, would be roughly equivalent to
 
158
 *  discounting 50% of the task's allowed memory from being considered
 
159
 *  as scoring against the task.
 
160
 *
 
161
 *  For backward compatibility with previous kernels,
 
162
 *  /proc/[pid]/oom_adj can still be used to tune the badness score.
 
163
 *  Its value is scaled linearly with oom_score_adj.
 
164
 *
 
165
 *  Writing to /proc/[pid]/oom_score_adj or
 
166
 *  /proc/[pid]/oom_adj will change the other with its
 
167
 *  scaled value.
 
168
 */
 
169
struct OomScoreAdjuster
 
170
{
 
171
    static int disableOomKillerValue()
 
172
    {
 
173
        return OOM_SCORE_ADJ_MIN;
 
174
    }
 
175
 
 
176
    static int minValue()
 
177
    {
 
178
        return OOM_SCORE_ADJ_MIN;
 
179
    }
 
180
 
 
181
    static int maxValue()
 
182
    {
 
183
        return OOM_SCORE_ADJ_MAX;
 
184
    }
 
185
 
 
186
    static OomScoreAdjuster leastLikelyToBeKilled()
 
187
    {
 
188
        // We could be way more clever here if we knew the distribution
 
189
        // of oom_score_adj values of all app processes. However, we just
 
190
        // make sure that the process is not ignored by the oom killer for now.
 
191
        return OomScoreAdjuster(minValue()+200);
 
192
    }
 
193
 
 
194
    static OomScoreAdjuster mostLikelyToBeKilled()
 
195
    {
 
196
        return OomScoreAdjuster(maxValue());
 
197
    }
 
198
 
 
199
    OomScoreAdjuster(int value) : value(value)
 
200
    {
 
201
    }
 
202
 
 
203
    bool isValid() const
 
204
    {
 
205
        return !(value < disableOomKillerValue() || value > maxValue());
 
206
    }
 
207
 
 
208
    bool applyForPid(pid_t pid) const
 
209
    {
 
210
        auto fn = QString("/proc/%1/oom_score_adj").arg(pid);
 
211
        QFile file(fn);
 
212
        
 
213
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
 
214
            return false;
 
215
 
 
216
        QTextStream out(&file);
 
217
        out << value;
 
218
 
 
219
        return true;
 
220
    }
 
221
 
 
222
    int value;
 
223
};
 
224
 
 
225
void ensureProcessIsUnlikelyToBeKilled(pid_t pid)
 
226
{    
 
227
    if (!OomScoreAdjuster::leastLikelyToBeKilled().applyForPid(pid))
 
228
        if (!OomAdjuster::leastLikelyToBeKilled().applyForPid(pid))
 
229
            DLOG("ensureProcessIsUnlikelyToBeKilled failed");
 
230
}
 
231
 
 
232
void ensureProcessIsLikelyToBeKilled(pid_t pid)
 
233
{
 
234
    if (!OomScoreAdjuster::mostLikelyToBeKilled().applyForPid(pid))
 
235
        if (!OomAdjuster::mostLikelyToBeKilled().applyForPid(pid))
 
236
            DLOG("ensureProcessIsLikelyToBeKilled failed");
 
237
}
 
238
}
35
239
 
36
240
TaskController* TaskController::m_theTaskController = nullptr;
37
241
 
48
252
{
49
253
    startCallback = [](const gchar * appId, gpointer userData) {
50
254
        Q_UNUSED(userData)
 
255
        pid_t pid = upstart_app_launch_get_primary_pid(appId);
 
256
        ensureProcessIsUnlikelyToBeKilled(pid);
51
257
        Q_EMIT TaskController::singleton()->processStartReport(QString(appId), false);
52
258
    };
53
259
 
58
264
 
59
265
    focusCallback = [](const gchar * appId, gpointer userData) {
60
266
        Q_UNUSED(userData)
 
267
        pid_t pid = upstart_app_launch_get_primary_pid(appId);
 
268
        ensureProcessIsUnlikelyToBeKilled(pid);
61
269
        Q_EMIT TaskController::singleton()->requestFocus(QString(appId));
62
270
    };
63
271
 
137
345
    DLOG("TaskController::suspend (this=%p, application=%p)", this, qPrintable(appId));
138
346
    pid_t pid = upstart_app_launch_get_primary_pid(appId.toLatin1().constData());
139
347
 
 
348
    ensureProcessIsLikelyToBeKilled(pid);
 
349
 
140
350
    if (pid) {
141
351
        kill(pid, SIGSTOP);
142
352
        return true;
150
360
    DLOG("TaskController::resume (this=%p, application=%p)", this, qPrintable(appId));
151
361
    pid_t pid = upstart_app_launch_get_primary_pid(appId.toLatin1().constData());
152
362
 
 
363
    ensureProcessIsUnlikelyToBeKilled(pid);
 
364
 
153
365
    if (pid) {
154
366
        kill(pid, SIGCONT);
155
367
        return true;