This patch restructures code for better readability and easier maintenance. Also introduces lowmemorykiller.h header file. Signed-off-by: Stratos Karafotis <stratosk@xxxxxxxxxxxx> --- drivers/staging/android/lowmemorykiller.c | 162 ++++++++++++++++++------------ drivers/staging/android/lowmemorykiller.h | 42 ++++++++ 2 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 drivers/staging/android/lowmemorykiller.h diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 3b91b0f..ade8584 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -38,50 +38,44 @@ #include <linux/rcupdate.h> #include <linux/profile.h> #include <linux/notifier.h> +#include "lowmemorykiller.h" -static uint32_t lowmem_debug_level = 2; -static short lowmem_adj[6] = { +static short lowmem_adj[LOWMEM_ARRAY_SIZE] = { 0, 1, 6, 12, }; -static int lowmem_adj_size = 4; -static int lowmem_minfree[6] = { +static int lowmem_minfree[LOWMEM_ARRAY_SIZE] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ }; -static int lowmem_minfree_size = 4; -static unsigned long lowmem_deathpending_timeout; +static int lowmem_adj_size = DEF_LOWMEM_SIZE; +static int lowmem_minfree_size = DEF_LOWMEM_SIZE; +static uint32_t lowmem_debug_level = DEF_DEBUG_LEVEL; -#define lowmem_print(level, x...) \ - do { \ - if (lowmem_debug_level >= (level)) \ - printk(x); \ - } while (0) +static unsigned long lowmem_deathpending_timeout; +static short min_score_adj; +static struct selected_struct selected; -static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) +static void set_min_score_adj(struct shrink_control *sc) { - struct task_struct *tsk; - struct task_struct *selected = NULL; - int rem = 0; - int tasksize; int i; - short min_score_adj = OOM_SCORE_ADJ_MAX + 1; - int selected_tasksize = 0; - short selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); + min_score_adj = OOM_SCORE_ADJ_MAX + 1; + if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; + for (i = 0; i < array_size; i++) { if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) { @@ -89,10 +83,82 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) break; } } + if (sc->nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %hd\n", sc->nr_to_scan, sc->gfp_mask, other_free, other_file, min_score_adj); + return; +} + +static enum lowmem_scan_t scan_process(struct task_struct *tsk) +{ + struct task_struct *p; + short oom_score_adj; + int tasksize; + + if (tsk->flags & PF_KTHREAD) + return LMK_SCAN_CONTINUE; + + p = find_lock_task_mm(tsk); + if (!p) + return LMK_SCAN_CONTINUE; + + if (test_tsk_thread_flag(p, TIF_MEMDIE) && + time_before_eq(jiffies, lowmem_deathpending_timeout)) { + task_unlock(p); + rcu_read_unlock(); + return LMK_SCAN_ABORT; + } + + oom_score_adj = p->signal->oom_score_adj; + if (oom_score_adj < min_score_adj) { + task_unlock(p); + return LMK_SCAN_CONTINUE; + } + + tasksize = get_mm_rss(p->mm); + task_unlock(p); + if (tasksize <= 0) + return LMK_SCAN_CONTINUE; + + if (selected.task) { + if (oom_score_adj < selected.oom_score_adj) + return LMK_SCAN_CONTINUE; + + if (oom_score_adj == selected.oom_score_adj && + tasksize <= selected.tasksize) + return LMK_SCAN_CONTINUE; + } + + selected.task = p; + selected.tasksize = tasksize; + selected.oom_score_adj = oom_score_adj; + lowmem_print(2, "select %d (%s), adj %hd, size %d, to kill\n", + p->pid, p->comm, oom_score_adj, tasksize); + + return LMK_SCAN_OK; +} + +static inline void kill_selected(void) +{ + lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n", + selected.task->pid, selected.task->comm, + selected.oom_score_adj, selected.tasksize); + + lowmem_deathpending_timeout = jiffies + HZ; + + send_sig(SIGKILL, selected.task, 0); + set_tsk_thread_flag(selected.task, TIF_MEMDIE); +} + +static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) +{ + struct task_struct *tsk; + int rem = 0; + + set_min_score_adj(sc); + rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + @@ -102,60 +168,27 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) sc->nr_to_scan, sc->gfp_mask, rem); return rem; } - selected_oom_score_adj = min_score_adj; - rcu_read_lock(); - for_each_process(tsk) { - struct task_struct *p; - short oom_score_adj; + selected.task = NULL; + selected.tasksize = 0; + selected.oom_score_adj = min_score_adj; - if (tsk->flags & PF_KTHREAD) - continue; - - p = find_lock_task_mm(tsk); - if (!p) - continue; + rcu_read_lock(); - if (test_tsk_thread_flag(p, TIF_MEMDIE) && - time_before_eq(jiffies, lowmem_deathpending_timeout)) { - task_unlock(p); - rcu_read_unlock(); + for_each_process(tsk) { + if (scan_process(tsk) == LMK_SCAN_ABORT) return 0; - } - oom_score_adj = p->signal->oom_score_adj; - if (oom_score_adj < min_score_adj) { - task_unlock(p); - continue; - } - tasksize = get_mm_rss(p->mm); - task_unlock(p); - if (tasksize <= 0) - continue; - if (selected) { - if (oom_score_adj < selected_oom_score_adj) - continue; - if (oom_score_adj == selected_oom_score_adj && - tasksize <= selected_tasksize) - continue; - } - selected = p; - selected_tasksize = tasksize; - selected_oom_score_adj = oom_score_adj; - lowmem_print(2, "select %d (%s), adj %hd, size %d, to kill\n", - p->pid, p->comm, oom_score_adj, tasksize); } - if (selected) { - lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n", - selected->pid, selected->comm, - selected_oom_score_adj, selected_tasksize); - lowmem_deathpending_timeout = jiffies + HZ; - send_sig(SIGKILL, selected, 0); - set_tsk_thread_flag(selected, TIF_MEMDIE); - rem -= selected_tasksize; + + if (selected.task) { + kill_selected(); + rem -= selected.tasksize; } + lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", sc->nr_to_scan, sc->gfp_mask, rem); rcu_read_unlock(); + return rem; } @@ -186,4 +219,3 @@ module_init(lowmem_init); module_exit(lowmem_exit); MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/android/lowmemorykiller.h b/drivers/staging/android/lowmemorykiller.h new file mode 100644 index 0000000..923ccf7 --- /dev/null +++ b/drivers/staging/android/lowmemorykiller.h @@ -0,0 +1,42 @@ +/* include/linux/lowmemorykiller.h + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_LOWMEMORYKILLER_H +#define _LINUX_LOWMEMORYKILLER_H + +#define DEF_DEBUG_LEVEL (2) +#define DEF_LOWMEM_SIZE (4) +#define LOWMEM_ARRAY_SIZE (6) + +#define lowmem_print(level, x...) \ + do { \ + if (lowmem_debug_level >= (level)) \ + printk(x); \ + } while (0) + +enum lowmem_scan_t { + LMK_SCAN_OK, + LMK_SCAN_CONTINUE, + LMK_SCAN_ABORT, +}; + +/* Selected task struct */ +struct selected_struct { + struct task_struct *task; + int tasksize; + short oom_score_adj; +}; + +#endif /* _LINUX_LOWMEMORYKILLER_H */ -- 1.8.1 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel