*/
#include <stdio.h>
-#include <stdbool.h>
#include <fcntl.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <time.h>
#include <limits.h>
-#include <fcntl.h>
#include <dirent.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <sys/sysinfo.h>
#include <Ecore.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include "trace.h"
+#include "cgroup.h"
#include "proc-main.h"
#include "lowmem-handler.h"
#include "proc-process.h"
+#include "swap-common.h"
#include "lowmem-common.h"
#include "resourced.h"
#include "macro.h"
+#include "notifier.h"
#include "config-parser.h"
#include "module.h"
+#include "logging-common.h"
#define MEMINFO_PATH "/proc/meminfo"
#define MEMCG_PATH "/sys/fs/cgroup"
-#define MEMPS_LOG_FILE "/var/log/memps"
+#define MEMPS_LOG_PATH "/var/log/"
+#define MEMPS_LOG_FILE MEMPS_LOG_PATH"memps"
#define MEMPS_EXEC_PATH "usr/bin/memps"
#define MEMCG_MOVE_CHARGE_PATH "memory.move_charge_at_immigrate"
#define MEMCG_OOM_CONTROL_PATH "memory.oom_control"
#define MAX_MEMORY_CGROUP_VICTIMS 10
#define MAX_CGROUP_VICTIMS 1
#define OOM_TIMER_INTERVAL 2
-#define MAX_TIMER_CHECK 10
-#define OOM_MULTIKILL_WAIT (1000*1000)
+#define OOM_MULTIKILL_WAIT (500*1000)
+#define OOM_SIGKILL_WAIT 1
#define OOM_SCORE_POINT_WEIGHT 1500
+#define OOM_KILLER_PRIORITY -20
#define MAX_FD_VICTIMS 10
+#define MAX_SWAP_VICTIMS 5
+#define MAX_MEMPS_LOGS 50
+#define NUM_RM_LOGS 5
+#define THRESHOLD_MARGIN 10 /* MB */
#define MEM_SIZE_64 64 /* MB */
#define MEM_SIZE_256 256 /* MB */
#define MEM_SIZE_2048 2048 /* MB */
/* thresholds for 64M RAM*/
-#define MEMCG_MEMORY_64_THRES_LOW 8 /* MB */
-#define MEMCG_MEMORY_64_THRES_MEDIUM 5 /* MB */
-#define MEMCG_MEMORY_64_THRES_LEAVE 8 /* MB */
+#define DYNAMIC_PROCESS_64_THRES 10 /* MB */
+#define DYNAMIC_PROCESS_64_LEAVE 30 /* MB */
+#define MEMCG_MEMORY_64_THRES_SWAP 15 /* MB */
+#define MEMCG_MEMORY_64_THRES_LOW 8 /* MB */
+#define MEMCG_MEMORY_64_THRES_MEDIUM 5 /* MB */
+#define MEMCG_MEMORY_64_THRES_LEAVE 8 /* MB */
/* thresholds for 256M RAM */
+#define DYNAMIC_PROCESS_256_THRES 50 /* MB */
+#define DYNAMIC_PROCESS_256_LEAVE 80 /* MB */
+#define MEMCG_MEMORY_256_THRES_SWAP 40 /* MB */
#define MEMCG_MEMORY_256_THRES_LOW 20 /* MB */
#define MEMCG_MEMORY_256_THRES_MEDIUM 10 /* MB */
#define MEMCG_MEMORY_256_THRES_LEAVE 20 /* MB */
/* threshold for 512M RAM */
-#define MEMCG_MEMORY_512_THRES_LOW 50 /* MB */
-#define MEMCG_MEMORY_512_THRES_MEDIUM 40 /* MB */
-#define MEMCG_MEMORY_512_THRES_LEAVE 60 /* MB */
+#define DYNAMIC_PROCESS_512_THRES 80 /* MB */
+#define DYNAMIC_PROCESS_512_LEAVE 100 /* MB */
+#define DYNAMIC_PROCESS_512_THRESLAUNCH 60 /* MB */
+#define DYNAMIC_PROCESS_512_LEAVELAUNCH 80 /* MB */
+#define MEMCG_MEMORY_512_THRES_SWAP 100 /* MB */
+#define MEMCG_MEMORY_512_THRES_LOW 50 /* MB */
+#define MEMCG_MEMORY_512_THRES_MEDIUM 40 /* MB */
+#define MEMCG_MEMORY_512_THRES_LEAVE 60 /* MB */
/* threshold for more than 1024M RAM */
+#define DYNAMIC_PROCESS_1024_THRES 150 /* MB */
+#define DYNAMIC_PROCESS_1024_LEAVE 300 /* MB */
+#define MEMCG_MEMORY_1024_THRES_SWAP 300 /* MB */
#define MEMCG_MEMORY_1024_THRES_LOW 200 /* MB */
#define MEMCG_MEMORY_1024_THRES_MEDIUM 100 /* MB */
#define MEMCG_MEMORY_1024_THRES_LEAVE 150 /* MB */
/* threshold for more than 2048M RAM */
+#define DYNAMIC_PROCESS_2048_THRES 200 /* MB */
+#define DYNAMIC_PROCESS_2048_LEAVE 500 /* MB */
+#define MEMCG_MEMORY_2048_THRES_SWAP 300 /* MB */
#define MEMCG_MEMORY_2048_THRES_LOW 200 /* MB */
#define MEMCG_MEMORY_2048_THRES_MEDIUM 160 /* MB */
#define MEMCG_MEMORY_2048_THRES_LEAVE 300 /* MB */
-enum {
- MEMNOTIFY_NORMAL,
- MEMNOTIFY_LOW,
- MEMNOTIFY_MEDIUM,
- MEMNOTIFY_MAX_LEVELS,
-};
-
static int thresholds[MEMNOTIFY_MAX_LEVELS];
+static int dynamic_process_threshold[DYNAMIC_KILL_MAX];
+static int dynamic_process_leave[DYNAMIC_KILL_MAX];
struct task_info {
pid_t pid;
void (*action) (void);
};
-struct mem_info {
- unsigned real_free;
- unsigned reclaimable;
+
+struct victims {
+ int num;
+ pid_t pids[MAX_MEMORY_CGROUP_VICTIMS];
};
/* low memory action function for cgroup */
static int compare_fg_victims(const struct task_info *ta, const struct task_info *tb);
/* low memory action function */
static void normal_act(void);
+static void swap_act(void);
static void low_act(void);
static void medium_act(void);
{ MEMNOTIFY_##c, MEMNOTIFY_##n, act}
static struct lowmem_process_entry lpe[] = {
+ LOWMEM_ENTRY(NORMAL, SWAP, swap_act),
LOWMEM_ENTRY(NORMAL, LOW, low_act),
LOWMEM_ENTRY(NORMAL, MEDIUM, medium_act),
+ LOWMEM_ENTRY(SWAP, NORMAL, normal_act),
+ LOWMEM_ENTRY(SWAP, LOW, low_act),
+ LOWMEM_ENTRY(SWAP, MEDIUM, medium_act),
+ LOWMEM_ENTRY(LOW, SWAP, swap_act),
LOWMEM_ENTRY(LOW, NORMAL, normal_act),
LOWMEM_ENTRY(LOW, MEDIUM, medium_act),
+ LOWMEM_ENTRY(MEDIUM, SWAP, swap_act),
LOWMEM_ENTRY(MEDIUM, NORMAL, normal_act),
LOWMEM_ENTRY(MEDIUM, LOW, low_act),
};
static int evfd[MEMCG_MAX_GROUPS] = {-1, };
static int cur_mem_state = MEMNOTIFY_NORMAL;
static Ecore_Timer *oom_check_timer = NULL;
+static Ecore_Timer *oom_sigkill_timer = NULL;
static pid_t killed_fg_victim;
+static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
+struct victims killed_tasks = {0, {0, }};
static pthread_t oom_thread = 0;
static pthread_mutex_t oom_mutex = PTHREAD_MUTEX_INITIALIZER;
static unsigned long totalram;
static unsigned long ktotalram;
+
+static const struct module_ops memory_modules_ops;
+static const struct module_ops *lowmem_ops;
+
static inline void get_total_memory(void)
{
struct sysinfo si;
}
}
-static void get_mem_info(struct mem_info *mi)
+unsigned int get_available(void)
{
char buf[PATH_MAX];
FILE *fp;
char *idx;
- unsigned int tfree = 0, tactive_file = 0, tinactive_file = 0;
+ unsigned int free = 0, cached = 0;
+ unsigned int available = 0;
fp = fopen(MEMINFO_PATH, "r");
if (!fp) {
_E("%s open failed, %d", buf, fp);
- return;
+ return available;
}
while (fgets(buf, PATH_MAX, fp) != NULL) {
idx += strlen("MemFree:");
while (*idx < '0' || *idx > '9')
idx++;
- tfree = atoi(idx);
- tfree >>= 10;
- } else if((idx = strstr(buf, "Active(file):"))) {
- idx += strlen("Active(file):");
+ free = atoi(idx);
+ } else if ((idx = strstr(buf, "MemAvailable:"))) {
+ idx += strlen("MemAvailable:");
while (*idx < '0' || *idx > '9')
idx++;
- tactive_file = atoi(idx);
- tactive_file >>= 10;
- } else if((idx = strstr(buf, "Inactive(file):"))) {
- idx += strlen("Inactive(file):");
+ available = atoi(idx);
+ break;
+ } else if((idx = strstr(buf, "Cached:"))) {
+ idx += strlen("Cached:");
while (*idx < '0' || *idx > '9')
idx++;
- tinactive_file = atoi(idx);
- tinactive_file >>= 10;
+ cached = atoi(idx);
break;
}
}
- mi->real_free = tfree;
- mi->reclaimable = tactive_file + tinactive_file;
+ if (available == 0)
+ available = free + cached;
+ available >>= 10;
fclose(fp);
+
+ return available;
}
static bool get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
return RESOURCED_ERROR_NONE;
}
-static int remove_shm(void)
+static int memps_file_select(const struct dirent *entry)
{
- int maxid, shmid, id;
- struct shmid_ds shmseg;
- struct shm_info shm_info;
+ return (strstr(entry->d_name, "memps") ? 1 : 0);
+}
- maxid = shmctl(0, SHM_INFO, (struct shmid_ds *)(void *)&shm_info);
- if (maxid < 0) {
- _E("shared mem error\n");
- return RESOURCED_ERROR_FAIL;
+int compare_func(const struct dirent **a, const struct dirent **b)
+{
+ const char *fn_a = (*a)->d_name;
+ const char *fn_b = (*b)->d_name;
+ char *str_at = strrchr(fn_a, '_') + 1;
+ char *str_bt = strrchr(fn_b, '_') + 1;
+
+ return strcmp(str_at, str_bt);
+}
+
+static void clear_logs(char *dir)
+{
+ struct dirent **namelist;
+ int n, i, ret;
+ char fname[BUF_MAX];
+
+ n = scandir(dir, &namelist, memps_file_select, compare_func);
+ _D("num of log files %d", n);
+ if (n < MAX_MEMPS_LOGS) {
+ while (n--)
+ free(namelist[n]);
+ free(namelist);
+ return;
}
- for (id = 0; id <= maxid; id++) {
- shmid = shmctl(id, SHM_STAT, &shmseg);
- if (shmid < 0)
- continue;
- if (shmseg.shm_nattch == 0) {
- _D("shared memory killer ==> %d killed\n",
- shmid);
- shmctl(shmid, IPC_RMID, NULL);
+ for (i = 0; i < n; i++) {
+ if (i < NUM_RM_LOGS) {
+ strcpy(fname, dir);
+ strcat(fname, namelist[i]->d_name);
+ _D("remove log file %s", fname);
+ ret = remove(fname);
+ if (ret < 0)
+ _E("%s file cannot removed", fname);
}
+
+ free(namelist[i]);
}
- return 0;
+ free(namelist);
}
static void make_memps_log(char *file, pid_t pid, char *victim_name)
{
time_t now;
- struct tm *cur_tm;
- char new_log[512];
+ struct tm cur_tm;
+ char new_log[BUF_MAX];
static pid_t old_pid;
if (old_pid == pid)
old_pid = pid;
now = time(NULL);
- cur_tm = (struct tm *)malloc(sizeof(struct tm));
- if (cur_tm == NULL) {
- _E("Fail to memory allocation");
- return;
- }
- if (localtime_r(&now, cur_tm) == NULL) {
+ if (localtime_r(&now, &cur_tm) == NULL) {
_E("Fail to get localtime");
- free(cur_tm);
return;
}
snprintf(new_log, sizeof(new_log),
- "%s_%s_%d_%.4d%.2d%.2d_%.2d%.2d%.2d.log", file, victim_name,
- pid, (1900 + cur_tm->tm_year), 1 + cur_tm->tm_mon,
- cur_tm->tm_mday, cur_tm->tm_hour, cur_tm->tm_min,
- cur_tm->tm_sec);
+ "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, victim_name,
+ pid, (1900 + cur_tm.tm_year), 1 + cur_tm.tm_mon,
+ cur_tm.tm_mday, cur_tm.tm_hour, cur_tm.tm_min,
+ cur_tm.tm_sec);
- free(cur_tm);
if (fork() == 0) {
- execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-f", new_log, (char *)NULL);
+ execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-r", new_log, (char *)NULL);
exit(0);
}
}
}
if (oomleave > usage) {
- _D("%s : usage : %u, oomleave : %u",
+ _D("%s : usage : %u, leave threshold : %u",
__func__, usage, oomleave);
return RESOURCED_ERROR_NONE;
} else {
- _D("%s : usage : %u, oomleave : %u",
+ _D("%s : usage : %u, leave threshold: %u",
__func__, usage, oomleave);
return RESOURCED_ERROR_FAIL;
}
return ((int)(tb->size) - (int)(ta->size));
}
-static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct task_info *selected,
- unsigned *total_size, unsigned
- should_be_freed, int force)
+static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info *selected,
+ unsigned should_be_freed, int flags)
{
FILE *f = NULL;
char buf[LOWMEM_PATH_MAX] = {0, };
int i = 0;
- int sel = nsel;
- unsigned total_victim_size = *total_size;
+ int num_victims = 0;
+ unsigned total_victim_size = 0;
char appname[PATH_MAX] = {0, };
GArray *victim_candidates = NULL;
/* if g_array_new fails, return the current number of victims */
if (victim_candidates == NULL)
- return sel;
+ return num_victims;
if (idx == MEMCG_MEMORY) {
sprintf(buf, "%s/%s/system.slice/cgroup.procs",
* if task read in this cgroup fails,
* return the current number of victims
*/
- return sel;
+ return num_victims;
}
}
continue;
for (i = 0; i < victim_candidates->len; i++) {
- struct task_info tsk = g_array_index(victim_candidates,
+ struct task_info *tsk = &g_array_index(victim_candidates,
struct task_info, i);
- if (getpgid(tpid) == tsk.pgid) {
- tsk.size += tsize;
- if (tsk.oom_score_adj < 0 && toom > 0) {
- tsk.pid = tpid;
- tsk.oom_score_adj = toom;
- g_array_remove_index(victim_candidates, i);
- g_array_append_val(victim_candidates, tsk);
+ if (getpgid(tpid) == tsk->pgid) {
+ tsk->size += tsize;
+ if (tsk->oom_score_adj <= 0 && toom > 0) {
+ tsk->pid = tpid;
+ tsk->oom_score_adj = toom;
}
break;
}
if (victim_candidates->len == 0) {
g_array_free(victim_candidates, true);
fclose(f);
- return sel;
+ return num_victims;
}
g_array_sort(victim_candidates,
for (i = 0; i < victim_candidates->len; i++) {
struct task_info tsk;
- if (sel >= max_victims ||
- (!force && total_victim_size >= should_be_freed)) {
+ if (num_victims >= max_victims ||
+ (!(flags & OOM_NOMEMORY_CHECK) &&
+ total_victim_size >= should_be_freed)) {
break;
}
+
tsk = g_array_index(victim_candidates, struct task_info, i);
- selected[sel].pid = tsk.pid;
- selected[sel].pgid = tsk.pgid;
- selected[sel].oom_score_adj = tsk.oom_score_adj;
- selected[sel].size = tsk.size;
- total_victim_size += tsk.size >> 10;
- sel++;
+ if (tsk.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED) {
+ unsigned int available;
+ if ((flags & OOM_FORCE) || !(flags & OOM_TIMER_CHECK)) {
+ _D("%d is skipped during force kill", tsk.pid);
+ break;
+ }
+ available = get_available();
+ if ((flags & OOM_TIMER_CHECK) &&
+ (available > thresholds[MEMNOTIFY_MEDIUM] +
+ THRESHOLD_MARGIN)) {
+ _D("available: %d MB, larger than threshold margin",
+ available);
+ break;
+ }
+ }
+ selected[num_victims].pid = tsk.pid;
+ selected[num_victims].pgid = tsk.pgid;
+ selected[num_victims].oom_score_adj = tsk.oom_score_adj;
+ selected[num_victims].size = tsk.size;
+ total_victim_size += tsk.size >> 10;
+ num_victims++;
}
g_array_free(victim_candidates, true);
fclose(f);
- *total_size = total_victim_size;
- return sel;
+ return num_victims;
+
+}
+
+static inline int is_dynamic_process_killer(int flags) {
+ return ((flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK));
+}
+
+static int lowmem_swap_cgroup_oom_killer(int flags)
+{
+ int ret;
+ char appname[PATH_MAX];
+ int count = 0;
+ char buf[LOWMEM_PATH_MAX] = {0, };
+ FILE *f;
+ unsigned int tsize = 0;
+ int swap_type;
+
+ swap_type = swap_status(SWAP_GET_TYPE, NULL);
+ if (swap_type <= SWAP_OFF)
+ return count;
+
+ sprintf(buf, "%s/memory/swap/cgroup.procs",
+ MEMCG_PATH);
+
+ f = fopen(buf, "r");
+ if (!f) {
+ _E("%s open failed, %d", buf, f);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ while (fgets(buf, 32, f) != NULL) {
+ pid_t tpid = 0;
+ int toom = 0;
+
+ tpid = atoi(buf);
+
+ if (proc_get_oom_score_adj(tpid, &toom) < 0) {
+ _D("pid(%d) was already terminated", tpid);
+ continue;
+ }
+
+ if (!get_mem_usage_by_pid(tpid, &tsize)) {
+ _D("pid(%d) size is not available\n", tpid);
+ continue;
+ }
+
+ /* To Do: skip by checking pgid? */
+ if (toom < OOMADJ_BACKGRD_UNLOCKED)
+ continue;
+
+ ret = proc_get_cmdline(tpid, appname);
+ if (ret == RESOURCED_ERROR_FAIL)
+ continue;
+
+ /* make memps log for killing application firstly */
+ if (count == 0)
+ make_memps_log(MEMPS_LOG_FILE, tpid, appname);
+
+ count++;
+
+ proc_remove_process_list(tpid);
+ kill(tpid, SIGKILL);
+ _E("we killed, lowmem lv2 = %d (%s) score = %d, size = %u KB\n",
+ tpid, appname, toom, tsize);
+ if (is_dynamic_process_killer(flags) &&
+ count >= MAX_SWAP_VICTIMS)
+ break;
+ }
+
+ fclose(f);
+ _I("number of swap victims = %d\n", count);
+ if (!(flags & OOM_FORCE) && (count >= MAX_SWAP_VICTIMS))
+ usleep(OOM_MULTIKILL_WAIT);
+
+ return count;
}
-/* Find victims: BACKGROUND */
-static int lowmem_get_memory_cgroup_victims(struct task_info *selected, int force)
+/* Find victims: (SWAP -> ) BACKGROUND */
+static int lowmem_get_memory_cgroup_victims(struct task_info *selected,
+ int flags)
{
- int i, count = 0;
- unsigned available, should_be_freed = 0, total_size = 0;
- struct mem_info mi;
+ int i, swap_victims, count = 0;
+ unsigned int available, should_be_freed = 0;
- if (force ) {
- count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND, count,
- MAX_FD_VICTIMS, selected,
- &total_size, 0, force);
+ swap_victims = lowmem_swap_cgroup_oom_killer(flags);
+
+ if ((flags & OOM_FORCE) && swap_victims < MAX_FD_VICTIMS) {
+ count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
+ MAX_FD_VICTIMS - swap_victims, selected,
+ 0, flags);
+ _D("kill %d victims in %s cgroup",
+ count, memcg_class[MEMCG_BACKGROUND].cgroup_name);
return count;
}
- get_mem_info(&mi);
- available = mi.real_free + mi.reclaimable;
+ available = get_available();
if (available < memcg_class[MEMCG_MEMORY].thres_leave)
should_be_freed = memcg_class[MEMCG_MEMORY].thres_leave - available;
_I("should_be_freed = %u MB", should_be_freed);
+ if (should_be_freed == 0 || swap_victims >= num_max_victims)
+ return count;
- if (should_be_freed) {
- for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
- count = lowmem_get_cgroup_victims(i, count,
- MAX_MEMORY_CGROUP_VICTIMS, selected,
- &total_size, should_be_freed,
- force);
- if (count >= MAX_MEMORY_CGROUP_VICTIMS || total_size >= should_be_freed)
- break;
+ for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
+ if ((flags & OOM_TIMER_CHECK) && i < MEMCG_BACKGROUND &&
+ available > thresholds[MEMNOTIFY_MEDIUM]) {
+ _D("in timer, not kill fg app, available %u > threshold %u",
+ available, thresholds[MEMNOTIFY_MEDIUM]);
+ return count;
}
+
+ count = lowmem_get_cgroup_victims(i,
+ num_max_victims - swap_victims,
+ selected, should_be_freed, flags);
+ if (count > 0) {
+ _D("kill %d victims in %s cgroup",
+ count, memcg_class[i].cgroup_name);
+ return count;
+ } else
+ _D("There are no victims to be killed in %s cgroup",
+ memcg_class[i].cgroup_name);
+
}
return count;
}
-static int lowmem_get_victims(int idx, struct task_info *selected, int force)
+static int lowmem_get_victims(int idx, struct task_info *selected,
+ int flags)
{
int count = 0;
- unsigned total_size = 0;
if (idx == MEMCG_MEMORY)
- count = lowmem_get_memory_cgroup_victims(selected, force);
+ count = lowmem_get_memory_cgroup_victims(selected, flags);
else
- count = lowmem_get_cgroup_victims(idx, count,
+ count = lowmem_get_cgroup_victims(idx,
MAX_CGROUP_VICTIMS, selected,
- &total_size,
- memcg_class[idx].thres_leave, force);
+ memcg_class[idx].thres_leave,
+ flags);
return count;
}
-/* To Do: decide the number of victims based on size */
-void lowmem_oom_killer_cb(int memcg_idx, int force)
+static Eina_Bool send_sigkill_cb(void *data)
{
- const pid_t self = getpid();
- int pid, ret, oom_score_adj, i;
- char appname[PATH_MAX];
- unsigned total_size = 0, size;
- struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
- int count = 0;
+ int i = 0;
- /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
- count = lowmem_get_victims(memcg_idx, selected, force);
+ _D("kill by SIGKILL timer tasks num = %d", killed_tasks.num);
- if (count == 0) {
- _D("get %s cgroup victim is failed",
- memcg_class[memcg_idx].cgroup_name);
- return;
+ for (i = 0; i < killed_tasks.num; i++) {
+ kill(killed_tasks.pids[i], SIGKILL);
+ _D("killed %d by SIGKILL", killed_tasks.pids[i]);
}
+ killed_tasks.num = 0;
+ ecore_timer_del(oom_sigkill_timer);
+ oom_sigkill_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+
+}
+
+static int lowmem_kill_victims(int memcg_idx,
+ int count, struct task_info *selected, int flags)
+{
+ const pid_t self = getpid();
+ int pid, ret, oom_score_adj, i;
+ unsigned total_size = 0, size;
+ char appname[PATH_MAX];
+
for (i = 0; i < count; i++) {
/* check current memory status */
- if (memcg_idx != MEMCG_MEMORY && lowmem_check_current_state(memcg_idx) >= 0)
- return;
+ if (!(flags & OOM_FORCE) && memcg_idx != MEMCG_MEMORY &&
+ lowmem_check_current_state(memcg_idx) >= 0)
+ return count;
pid = selected[i].pid;
oom_score_adj = selected[i].oom_score_adj;
total_size += size;
- if (force)
+ proc_remove_process_list(pid);
+ if (flags & OOM_FORCE) {
kill(pid, SIGTERM);
- else
+ if (killed_tasks.num < MAX_MEMORY_CGROUP_VICTIMS)
+ killed_tasks.pids[killed_tasks.num++] = pid;
+ } else
kill(pid, SIGKILL);
- _E("we killed, lowmem lv2 = %d (%s) oom = %d, size = %u KB, victim total size = %u KB\n",
- pid, appname, oom_score_adj, size, total_size);
+ _E("we killed, force(%d), lowmem lv2 = %d (%s) score = %d, size = %u KB, victim total size = %u KB\n",
+ flags & OOM_FORCE, pid, appname, oom_score_adj, size, total_size);
if (memcg_idx >= MEMCG_FOREGROUND &&
memcg_idx < MEMCG_BACKGROUND)
if (i != 0)
make_memps_log(MEMPS_LOG_FILE, pid, appname);
}
+
+ return count;
+}
+
+int lowmem_oom_killer_cb(int memcg_idx, int flags)
+{
+ struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
+ int count = 0;
+
+ /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
+ count = lowmem_get_victims(memcg_idx, selected, flags);
+
+ if (count == 0) {
+ _D("get %s cgroup victim is failed",
+ memcg_class[memcg_idx].cgroup_name);
+ return count;
+ }
+
+ count = lowmem_kill_victims(memcg_idx, count, selected, flags);
+ clear_logs(MEMPS_LOG_PATH);
+ logging_control(LOGGING_UPDATE_STATE, NULL);
+
+ return count;
+}
+
+void lowmem_dynamic_process_killer(int type)
+{
+ struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
+ int count = 0;
+ unsigned available = get_available();
+ unsigned should_be_freed;
+ int flags = OOM_FORCE;
+ int swap_victims;
+
+ if (!dynamic_process_threshold[type])
+ return;
+
+ if (available >= dynamic_process_threshold[type])
+ return;
+
+ change_memory_state(MEMNOTIFY_LOW, 1);
+ swap_victims = lowmem_swap_cgroup_oom_killer(flags);
+ if (swap_victims >= MAX_SWAP_VICTIMS)
+ goto start_timer;
+
+ available = get_available();
+ if (available >= dynamic_process_leave[type])
+ return;
+
+ should_be_freed = dynamic_process_leave[type] - available;
+ _D("run dynamic killer, type=%d, available=%d, should_be_freed = %u", type, available, should_be_freed);
+ count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
+ num_max_victims - swap_victims, selected,
+ should_be_freed, flags);
+
+ if (count == 0) {
+ _D("get victim for dynamic process is failed");
+ return;
+ }
+
+ lowmem_kill_victims(MEMCG_BACKGROUND, count, selected, flags);
+ change_memory_state(MEMNOTIFY_NORMAL, 0);
+
+start_timer:
+ if (oom_sigkill_timer == NULL) {
+ _D("start timer to sigkill tasks");
+ oom_sigkill_timer =
+ ecore_timer_add(OOM_SIGKILL_WAIT, send_sigkill_cb,
+ NULL);
+ } else
+ killed_tasks.num = 0;
}
static void *lowmem_oom_killer_pthread(void *arg)
{
int ret = 0;
+ setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
+
while (1) {
/*
* When signalled by main thread,
break;
}
- _I("oom thread conditional signal received");
- lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+ _I("oom thread conditional signal received and start");
+ lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_NONE);
+ _I("lowmem_oom_killer_cb finished");
ret = pthread_mutex_unlock(&oom_mutex);
if ( ret ) {
case MEMNOTIFY_NORMAL:
tmp = "mem normal";
break;
+ case MEMNOTIFY_SWAP:
+ tmp = "mem swap";
+ break;
case MEMNOTIFY_LOW:
tmp = "mem low";
break;
cur_mem_state = mem_state;
}
+static void lowmem_swap_memory(void)
+{
+ pid_t pid;
+ int swap_type;
+
+ if (cur_mem_state == MEMNOTIFY_NORMAL)
+ return;
+
+ swap_type = swap_status(SWAP_GET_TYPE, NULL);
+
+ if (swap_type == SWAP_ON) {
+ while (1)
+ {
+ pid = (pid_t)swap_status(SWAP_GET_CANDIDATE_PID, NULL);
+ if (!pid)
+ break;
+ _I("swap cgroup entered : pid : %d", (int)pid);
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, (void*)&pid);
+ }
+ if (swap_status(SWAP_GET_STATUS, NULL) == SWAP_OFF)
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_RESTART, NULL);
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_START, NULL);
+ }
+}
+
+
static void normal_act(void)
{
int ret, status;
change_lowmem_state(MEMNOTIFY_NORMAL);
}
+static void swap_act(void)
+{
+ int ret, status;
+
+ ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+ if (ret)
+ _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+ if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL)
+ vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+ VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+ change_lowmem_state(MEMNOTIFY_SWAP);
+}
+
static void low_act(void)
{
int ret, status;
_D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
change_lowmem_state(MEMNOTIFY_LOW);
- remove_shm();
/* Since vconf for soft warning could be set during low memory check,
* we set it only when the current status is not soft warning.
static Eina_Bool medium_cb(void *data)
{
- struct mem_info mi;
- unsigned available;
+ unsigned int available;
+ int count = 0;
- get_mem_info(&mi);
- available = mi.real_free + mi.reclaimable;
+ available = get_available();
_D("available = %u, timer run until reaching leave threshold", available);
if (available >= memcg_class[MEMCG_MEMORY].thres_leave && oom_check_timer != NULL) {
}
_I("cannot reach leave threshold, timer again");
- lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+ count = lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_TIMER_CHECK);
+ /*
+ * After running oom killer in timer, but there is no victim,
+ * stop timer.
+ */
+ if (!count && available >= thresholds[MEMNOTIFY_MEDIUM] &&
+ oom_check_timer != NULL) {
+ ecore_timer_del(oom_check_timer);
+ oom_check_timer = NULL;
+ _D("oom_check_timer deleted, available %u > threshold %u",
+ available, thresholds[MEMNOTIFY_MEDIUM]);
+ normal_act();
+ return ECORE_CALLBACK_CANCEL;
+ }
return ECORE_CALLBACK_RENEW;
}
change_lowmem_state(MEMNOTIFY_MEDIUM);
/* signal to lowmem_oom_killer_pthread to start killer */
- ret = pthread_mutex_lock(&oom_mutex);
- if ( ret ) {
- _E("medium_act::pthread_mutex_lock() failed, %d", ret);
- return;
- }
-
- ret = pthread_cond_signal(&oom_cond);
- if ( ret ) {
- _E("medium_act::pthread_cond_wait() failed, %d", ret);
- pthread_mutex_unlock(&oom_mutex);
- return;
- }
-
- _I("send signal lowmem oom killer");
- ret = pthread_mutex_unlock(&oom_mutex);
- if ( ret ) {
- _E("medium_act::pthread_mutex_unlock() failed, %d", ret);
+ ret = pthread_mutex_trylock(&oom_mutex);
+ if (ret) {
+ _E("medium_act::pthread_mutex_trylock() failed, %d, errno: %d", ret, errno);
return;
}
+ _I("oom mutex trylock success");
+ pthread_cond_signal(&oom_cond);
+ _I("send signal to oom killer thread");
+ pthread_mutex_unlock(&oom_mutex);
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
if ((memcg_idx >= MEMCG_FOREGROUND && memcg_idx < MEMCG_BACKGROUND)
&& is_fg_victim_killed(memcg_idx)) {
show_foreground_procs(memcg_idx);
- lowmem_oom_killer_cb(memcg_idx, 0);
+ lowmem_oom_killer_cb(memcg_idx, OOM_NONE);
}
}
return ret;
}
-static unsigned int check_mem_state(unsigned available)
+static unsigned int check_mem_state(unsigned int available)
{
int mem_state;
for (mem_state = MEMNOTIFY_MAX_LEVELS -1; mem_state > MEMNOTIFY_NORMAL; mem_state--) {
return mem_state;
}
+void change_memory_state(int state, int force)
+{
+ unsigned int available;
+ int mem_state;
+
+ if (force) {
+ mem_state = state;
+ } else {
+ available = get_available();
+ mem_state = check_mem_state(available);
+ _D("available = %u, mem_state = %d", available, mem_state);
+ }
+
+ switch (mem_state) {
+ case MEMNOTIFY_NORMAL:
+ normal_act();
+ break;
+ case MEMNOTIFY_SWAP:
+ swap_act();
+ break;
+ case MEMNOTIFY_LOW:
+ low_act();
+ break;
+ case MEMNOTIFY_MEDIUM:
+ medium_act();
+ break;
+ default:
+ assert(0);
+ }
+}
+
static void lowmem_handler(void)
{
- struct mem_info mi;
- unsigned available;
+ static unsigned int prev_available;
+ unsigned int available;
int mem_state;
- get_mem_info(&mi);
- available = mi.real_free + mi.reclaimable;
+ available = get_available();
- mem_state = check_mem_state(available);
- _D("available = %u, mem_state = %d", available, mem_state);
+ if (prev_available == available)
+ return;
+ mem_state = check_mem_state(available);
lowmem_process(mem_state);
+ prev_available = available;
}
static void lowmem_cgroup_handler(int memcg_idx)
return RESOURCED_ERROR_NONE;
}
-static int set_thresholds(const char * section_name, const struct parse_result *result)
+static int set_memory_config(const char * section_name, const struct parse_result *result)
{
- if (!result || !section_name)
- return -EINVAL;
+ if (!result || !section_name)
+ return -EINVAL;
- if (strcmp(result->section, section_name))
- return RESOURCED_ERROR_NONE;
+ if (strcmp(result->section, section_name))
+ return RESOURCED_ERROR_NONE;
- if (!strcmp(result->name, "ThresholdLow")) {
- int value = atoi(result->value);
- set_threshold(MEMNOTIFY_LOW, value);
- } else if (!strcmp(result->name, "ThresholdMedium")) {
- int value = atoi(result->value);
- set_threshold(MEMNOTIFY_MEDIUM, value);
- } else if (!strcmp(result->name, "ThresholdLeave")) {
- int value = atoi(result->value);
- set_leave_threshold(value);
- } else if (!strcmp(result->name, "ForegroundRatio")) {
- float value = atof(result->value);
- set_foreground_ratio(value);
- }
- return RESOURCED_ERROR_NONE;
+ if (!strcmp(result->name, "ThresholdSwap")) {
+ int value = atoi(result->value);
+ set_threshold(MEMNOTIFY_SWAP, value);
+ } else if (!strcmp(result->name, "ThresholdLow")) {
+ int value = atoi(result->value);
+ set_threshold(MEMNOTIFY_LOW, value);
+ } else if (!strcmp(result->name, "ThresholdMedium")) {
+ int value = atoi(result->value);
+ set_threshold(MEMNOTIFY_MEDIUM, value);
+ } else if (!strcmp(result->name, "ThresholdLeave")) {
+ int value = atoi(result->value);
+ set_leave_threshold(value);
+ } else if (!strcmp(result->name, "ForegroundRatio")) {
+ float value = atof(result->value);
+ set_foreground_ratio(value);
+ } else if (!strcmp(result->name, "NumMaxVictims")) {
+ int value = atoi(result->value);
+ num_max_victims = value;
+ _D("set number of max victims as %d", num_max_victims);
+ } else if (!strcmp(result->name, "DynamicThreshold")) {
+ int value = atoi(result->value);
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = value;
+ _D("set dynamic process threshold as %d",
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
+ } else if (!strcmp(result->name, "DynamicLeave")) {
+ int value = atoi(result->value);
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = value;
+ _D("set dynamic process leave threshold as %d",
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
+ } else if (!strcmp(result->name, "DynamicThresholdLaunch")) {
+ int value = atoi(result->value);
+ dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = value;
+ _D("set dynamic process threshold as %d",
+ dynamic_process_threshold[DYNAMIC_KILL_LUNCH]);
+ } else if (!strcmp(result->name, "DynamicLeaveLaunch")) {
+ int value = atoi(result->value);
+ dynamic_process_leave[DYNAMIC_KILL_LUNCH] = value;
+ _D("set dynamic process leave threshold as %d",
+ dynamic_process_leave[DYNAMIC_KILL_LUNCH]);
+ }
+ return RESOURCED_ERROR_NONE;
}
static int memory_load_64_config(struct parse_result *result, void *user_data)
{
- return set_thresholds("Memory64", result);
+ return set_memory_config("Memory64", result);
}
static int memory_load_256_config(struct parse_result *result, void *user_data)
{
- return set_thresholds("Memory256", result);
+ return set_memory_config("Memory256", result);
}
static int memory_load_512_config(struct parse_result *result, void *user_data)
{
- return set_thresholds("Memory512", result);
+ return set_memory_config("Memory512", result);
}
static int memory_load_1024_config(struct parse_result *result, void *user_data)
{
- return set_thresholds("Memory1024", result);
+ return set_memory_config("Memory1024", result);
}
static int memory_load_2048_config(struct parse_result *result, void *user_data)
{
- return set_thresholds("Memory2048", result);
+ return set_memory_config("Memory2048", result);
}
/* init thresholds depending on total ram size. */
if (total_ramsize <= MEM_SIZE_64) {
/* set thresholds for ram size 64M */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_LEAVE;
+ set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_64_THRES_SWAP);
set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_64_THRES_LOW);
set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_64_THRES_MEDIUM);
set_leave_threshold(MEMCG_MEMORY_64_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_64_config, NULL);
} else if (total_ramsize <= MEM_SIZE_256) {
/* set thresholds for ram size 256M */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_LEAVE;
+ set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_256_THRES_SWAP);
set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_256_THRES_LOW);
set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_256_THRES_MEDIUM);
set_leave_threshold(MEMCG_MEMORY_256_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_256_config, NULL);
} else if (total_ramsize <= MEM_SIZE_512) {
/* set thresholds for ram size 512M */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_LEAVE;
+ dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_THRESLAUNCH;
+ dynamic_process_leave[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_LEAVELAUNCH;
+ set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_512_THRES_SWAP);
set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_512_THRES_LOW);
set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_512_THRES_MEDIUM);
set_leave_threshold(MEMCG_MEMORY_512_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_512_config, NULL);
} else if (total_ramsize <= MEM_SIZE_1024) {
/* set thresholds for ram size more than 1G */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_LEAVE;
+ set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_1024_THRES_SWAP);
set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_1024_THRES_LOW);
set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_1024_THRES_MEDIUM);
set_leave_threshold(MEMCG_MEMORY_1024_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_1024_config, NULL);
} else {
- /* set thresholds for ram size more than 2G */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_LEAVE;
+ set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_2048_THRES_SWAP);
set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_2048_THRES_LOW);
set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_2048_THRES_MEDIUM);
set_leave_threshold(MEMCG_MEMORY_2048_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_2048_config, NULL);
}
- for (i = MEMNOTIFY_NORMAL; i < MEMNOTIFY_MAX_LEVELS; i++)
+ for (i = MEMNOTIFY_SWAP; i < MEMNOTIFY_MAX_LEVELS; i++)
_I("set threshold for %d to %u", i, thresholds[i]);
_I("set thres_leave to %u", memcg_class[MEMCG_MEMORY].thres_leave);
+ _I("set dynamic process threshold to %u", dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
+ _I("set dynamic process leave to %u", dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
}
static int create_foreground_memcg(void)
return ret;
}
+static void lowmem_check(void)
+{
+ unsigned int available;
+
+ available = get_available();
+ _D("available = %u", available);
-static int find_foreground_cgroup(void) {
+ if(cur_mem_state != MEMNOTIFY_SWAP &&
+ (available <= thresholds[MEMNOTIFY_SWAP] &&
+ available > thresholds[MEMNOTIFY_LOW])) {
+ swap_act();
+
+ }
+}
+
+static int find_foreground_cgroup(struct proc_process_info_t *process_info) {
int fg, min_fg = -1;
unsigned int min_usage = UINT_MAX;
+ /*
+ * if this process group is already in one of the foreground cgroup,
+ * put all of the process in this group into the same cgroup.
+ */
+ if (process_info && process_info->memcg_idx >= MEMCG_FOREGROUND &&
+ process_info->memcg_idx < MEMCG_FOREGROUND + NUM_FOREGROUND)
+ return process_info->memcg_idx;
+
+ /*
+ * if any of the process in this group is not in foreground,
+ * find foreground cgroup with minimum usage
+ */
for (fg = MEMCG_FOREGROUND; fg < MEMCG_BACKGROUND; fg++) {
unsigned int usage;
usage = get_mem_usage(fg);
return min_fg;
}
-void lowmem_move_memcgroup(int pid, int oom_score_adj)
+static void lowmem_move_memcgroup(int pid, int oom_score_adj)
{
char buf[LOWMEM_PATH_MAX] = {0,};
FILE *f;
- int size;
+ int size, background = 0;
+ unsigned long swap_args[1] = {0,};
+ struct proc_process_info_t *process_info =
+ find_process_info(NULL, pid, NULL);
if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED) {
sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
+ proc_set_process_info_memcg(process_info, MEMCG_BACKGROUND);
+ background = 1;
} else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED &&
oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
- int ret;
- ret = find_foreground_cgroup();
+ int ret = find_foreground_cgroup(process_info);
if (ret == RESOURCED_ERROR_FAIL) {
_E("cannot find foreground cgroup");
return;
}
sprintf(buf, "%s/memory/foreground%d/cgroup.procs", MEMCG_PATH, ret);
+ proc_set_process_info_memcg(process_info, ret);
} else
return;
-
- _D("buf : %s, pid : %d, oom : %d", buf, pid, oom_score_adj);
+ swap_args[0] = (unsigned long)pid;
+ if (!swap_status(SWAP_CHECK_PID, swap_args) || !background) {
+ _D("buf : %s, pid : %d, score : %d", buf, pid, oom_score_adj);
f = fopen(buf, "w");
if (!f) {
_E("%s open failed", buf);
if (fwrite(buf, size, 1, f) != 1)
_E("fwrite cgroup tasks : %d\n", pid);
fclose(f);
-
+ }
+ if (background) {
+ lowmem_check();
+ lowmem_swap_memory();
+ }
}
-void lowmem_cgroup_foregrd_manage(int currentpid)
+static void lowmem_cgroup_foregrd_manage(int currentpid)
{
- char buf[LOWMEM_PATH_MAX] = {0,};
- int pid, pgid;
- FILE *f;
- sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
- f = fopen(buf, "r");
- if (!f) {
- _E("%s open failed", buf);
+ GSList *iter;
+ struct proc_process_info_t *process_info =
+ find_process_info(NULL, currentpid, NULL);
+
+ if (!process_info)
return;
+
+ gslist_for_each_item(iter, process_info->pids) {
+ struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
+
+ if (pid_info->type == RESOURCED_APP_TYPE_GROUP)
+ lowmem_move_memcgroup(pid_info->pid, OOMADJ_FOREGRD_UNLOCKED);
}
- while (fgets(buf, LOWMEM_PATH_MAX, f) != NULL) {
- pid = atoi(buf);
- if (currentpid == pid)
- continue;
- pgid = getpgid(pid);
- if (currentpid == pgid)
- lowmem_move_memcgroup(pid, OOMADJ_APP_LIMIT);
- }
- fclose(f);
}
static int oom_thread_create(void)
return ret;
}
+static int lowmem_app_launch_cb(void *data)
+{
+ struct proc_status *p_data = (struct proc_status*)data;
+ struct proc_process_info_t *process_info;
+ int ret = 0;
+ ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
+ "Please provide valid argument!");
+ process_info = (struct proc_process_info_t *)p_data->processinfo;
+
+ if (process_info && !(process_info->type & PROC_LARGE_HEAP))
+ lowmem_dynamic_process_killer(DYNAMIC_KILL_LUNCH);
+ return ret;
+}
+
/* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
int lowmem_init(void)
{
}
lowmem_dbus_init();
+ register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
return ret;
}
static int resourced_memory_init(void *data)
{
+ lowmem_ops = &memory_modules_ops;
+
return lowmem_init();
}
static int resourced_memory_finalize(void *data)
{
+ unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
+ return RESOURCED_ERROR_NONE;
+}
+
+int lowmem_control(enum lowmem_control_type type, unsigned long *args)
+{
+ struct lowmem_data_type l_data;
+
+ if (lowmem_ops) {
+ l_data.control_type = type;
+ l_data.args = args;
+ return lowmem_ops->control(&l_data);
+ }
+
return RESOURCED_ERROR_NONE;
}
-static struct module_ops memory_modules_ops = {
+static const struct module_ops memory_modules_ops = {
.priority = MODULE_PRIORITY_NORMAL,
.name = "lowmem",
.init = resourced_memory_init,