summaryrefslogtreecommitdiffstats
path: root/lmkd
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2014-07-14 12:39:56 -0700
committerColin Cross <ccross@android.com>2014-07-14 17:41:17 -0700
commit16b0946da1745877311562b8cbce08584c6a1b37 (patch)
tree91e380d2fbc77615c3f0d514587660abef09c178 /lmkd
parentce85d955a3ce73abffbdde1f5fdb41580d70cffc (diff)
downloadsystem_core-16b0946da1745877311562b8cbce08584c6a1b37.zip
system_core-16b0946da1745877311562b8cbce08584c6a1b37.tar.gz
system_core-16b0946da1745877311562b8cbce08584c6a1b37.tar.bz2
lmkd: kill multiple tasks
The task selected to die may be small, add its approximate size to other_free and other_file and keep killing until all thresholds are met. Bug: 16236289 Change-Id: Iceeca4c63fec98cae2bf53e258f7707cea408b07
Diffstat (limited to 'lmkd')
-rw-r--r--lmkd/lmkd.c141
1 files changed, 88 insertions, 53 deletions
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index b276f0a..2362cbf 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -560,29 +560,57 @@ static struct proc *proc_adj_lru(int oomadj) {
return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
}
-static void mp_event(uint32_t events __unused) {
- int i;
- int ret;
- unsigned long long evcount;
- struct sysmeminfo mi;
- int other_free;
- int other_file;
- int minfree = 0;
- int min_score_adj = OOM_ADJUST_MAX + 1;
+/* Kill one process specified by procp. Returns the size of the process killed */
+static int kill_one_process(struct proc *procp, int other_free, int other_file,
+ int minfree, int min_score_adj, bool first)
+{
+ int pid = procp->pid;
+ uid_t uid = procp->uid;
+ char *taskname;
+ int tasksize;
+ int r;
+
+ taskname = proc_get_name(pid);
+ if (!taskname) {
+ pid_remove(pid);
+ return -1;
+ }
- ret = read(mpevfd, &evcount, sizeof(evcount));
- if (ret < 0)
- ALOGE("Error reading memory pressure event fd; errno=%d",
- errno);
+ tasksize = proc_get_size(pid);
+ if (tasksize <= 0) {
+ pid_remove(pid);
+ return -1;
+ }
- if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
- return;
+ ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
+ " to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
+ " Free memory is %s%ldkB %s reserved",
+ taskname, pid, uid, procp->oomadj, tasksize * page_k,
+ first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
+ first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
+ r = kill(pid, SIGKILL);
+ killProcessGroup(uid, pid, SIGKILL);
+ pid_remove(pid);
- if (zoneinfo_parse(&mi) < 0)
- return;
+ if (r) {
+ ALOGE("kill(%d): errno=%d", procp->pid, errno);
+ return -1;
+ } else {
+ return tasksize;
+ }
+}
- other_free = mi.nr_free_pages - mi.totalreserve_pages;
- other_file = mi.nr_file_pages - mi.nr_shmem;
+/*
+ * Find a process to kill based on the current (possibly estimated) free memory
+ * and cached memory sizes. Returns the size of the killed processes.
+ */
+static int find_and_kill_process(int other_free, int other_file, bool first)
+{
+ int i;
+ int r;
+ int min_score_adj = OOM_ADJUST_MAX + 1;
+ int minfree = 0;
+ int killed_size = 0;
for (i = 0; i < lowmem_targets_size; i++) {
minfree = lowmem_minfree[i];
@@ -593,52 +621,59 @@ static void mp_event(uint32_t events __unused) {
}
if (min_score_adj == OOM_ADJUST_MAX + 1)
- return;
+ return 0;
for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
struct proc *procp;
- retry:
+retry:
procp = proc_adj_lru(i);
if (procp) {
- int pid = procp->pid;
- uid_t uid = procp->uid;
- char *taskname;
- int tasksize;
- int r;
-
- taskname = proc_get_name(pid);
- if (!taskname) {
- pid_remove(pid);
- goto retry;
- }
-
- tasksize = proc_get_size(pid);
- if (tasksize < 0) {
- pid_remove(pid);
- goto retry;
- }
-
- ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
- " to free %ldkB because cache %ldkB is below limit %ldkB for oom_adj %d\n"
- " Free memory is %ldkB %s reserved",
- taskname, pid, uid, procp->oomadj, tasksize * page_k,
- other_file * page_k, minfree * page_k, min_score_adj,
- other_free * page_k, other_free >= 0 ? "above" : "below");
- r = kill(pid, SIGKILL);
- killProcessGroup(uid, pid, SIGKILL);
- pid_remove(pid);
-
- if (r) {
- ALOGE("kill(%d): errno=%d", procp->pid, errno);
+ killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
+ if (killed_size < 0) {
goto retry;
} else {
- time(&kill_lasttime);
- break;
+ return killed_size;
}
}
}
+
+ return 0;
+}
+
+static void mp_event(uint32_t events __unused) {
+ int i;
+ int ret;
+ unsigned long long evcount;
+ struct sysmeminfo mi;
+ int other_free;
+ int other_file;
+ int killed_size;
+ bool first = true;
+
+ ret = read(mpevfd, &evcount, sizeof(evcount));
+ if (ret < 0)
+ ALOGE("Error reading memory pressure event fd; errno=%d",
+ errno);
+
+ if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
+ return;
+
+ if (zoneinfo_parse(&mi) < 0)
+ return;
+
+ other_free = mi.nr_free_pages - mi.totalreserve_pages;
+ other_file = mi.nr_file_pages - mi.nr_shmem;
+
+ do {
+ killed_size = find_and_kill_process(other_free, other_file, first);
+ if (killed_size > 0) {
+ first = false;
+ other_free += killed_size;
+ other_file += killed_size;
+ }
+ } while (killed_size > 0);
}
static int init_mp(char *levelstr, void *event_handler)