memory : LMK refactoring. 38/99838/16
authorKichan Kwon <k_c.kwon@samsung.com>
Mon, 21 Nov 2016 09:19:23 +0000 (18:19 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Mon, 3 Apr 2017 00:50:04 +0000 (09:50 +0900)
- Find victims not in the memory cgroup but proc_app_list
- Make LMK worker in thread and resourced requests reclaim with enqueue
- Unify (eng/user) conf files
- Restore memcg when resourced is restarted
- Apply new cgroup hierarchy
  "/"             : root cgroup
  "/Apps"         : all apps and services managed by Tizen
  "/MemLimit"     : apps with set memory limit
  "/Swap"         : swapped and reclaimed (if swap module is enabled)
  "/system.slice" : services managed by systemd

Change-Id: I7ef459ad98ad9c765897fd2e4d8593e006c43a32
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
15 files changed:
src/CMakeLists.txt
src/common/cgroup.c
src/common/memory-common.h
src/common/notifier.h
src/common/proc-common.h
src/common/procfs.c
src/memory/lowmem-dbus.c
src/memory/lowmem-handler.h
src/memory/memcontrol.c
src/memory/memory.conf [new file with mode: 0644]
src/memory/memory_eng.conf [deleted file]
src/memory/memory_user.conf [deleted file]
src/memory/vmpressure-lowmem-handler.c
src/proc-stat/proc-main.c
src/proc-stat/proc-monitor.c

index b4ea75582b3a465299ac290de67d8d897584cb9c..09b59d15bbadf041d12faa316cb39b8c7947fc08 100644 (file)
@@ -187,13 +187,8 @@ INSTALL(TARGETS ${RD_BINARY_NAME}
        DESTINATION ${MAKE_INSTALL_PREFIX}/usr/bin RENAME ${RD_BINARY_NAME}
   PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE WORLD_EXECUTE)
 
-IF("${MEMORY_ENG}" STREQUAL "ON")
-  INSTALL(FILES ${MEMORY_SOURCE_DIR}/memory_eng.conf
-         DESTINATION ${RD_CONFIG_PATH} RENAME memory.conf)
-ELSE()
-  INSTALL(FILES ${MEMORY_SOURCE_DIR}/memory_user.conf
-    DESTINATION ${RD_CONFIG_PATH} RENAME memory.conf)
-ENDIF()
+INSTALL(FILES ${MEMORY_SOURCE_DIR}/memory.conf
+  DESTINATION /etc/resourced RENAME memory.conf)
 
 IF("${SWAP_MODULE}" STREQUAL "ON")
        INSTALL(FILES ${SWAP_SOURCE_DIR}/swap.conf DESTINATION ${RD_CONFIG_PATH})
index 890b8f40f61fa5cf4b1a213397887824be86cc23..cb7279d85c321e42c74c05a20cb69560b18ca8c9 100644 (file)
@@ -185,6 +185,7 @@ int cgroup_make_subdir(const char* parentdir, const char* cgroup_name, bool *alr
 {
        char buf[MAX_PATH_LENGTH];
        bool cgroup_exists;
+       bool cgroup_remount = false;
        int ret = 0;
 
        if (!parentdir || !cgroup_name) {
@@ -206,13 +207,14 @@ int cgroup_make_subdir(const char* parentdir, const char* cgroup_name, bool *alr
                                _E("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name);
                                return RESOURCED_ERROR_FAIL;
                        }
+                       cgroup_remount = true;
                }
 
                ret = cgroup_create(buf);
                ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
                        "Fail to create cgroup %s : err %d", cgroup_name, errno);
 
-               if (!strncmp(parentdir, DEFAULT_CGROUP, sizeof(DEFAULT_CGROUP))) {
+               if (cgroup_remount) {
                        ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",
                                        MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
                        if (ret < 0)
index 543ebd4756ed746e68f53f91cf7aca9e1af4a7db..1fbf90f0ee8cd36066265aa00a9aa2f6048d3cf9 100644 (file)
 #define __MEMORY_COMMONL_H__
 
 #include <glib.h>
+#include <stdbool.h>
 #include "const.h"
 
 /*
  * [memory cgroup information]
  * MEMCG_MEMORY : root cgroup for system daemons
- * MEMCG_PLATFORM : platform cgroup for swapping desired platform daemons
- * MEMCG_FOREGROUND : foreground cgroup (oom : 150 ~ 200)
- * MEMCG_PREVIOUS : previous cgroup including service and perciptible (oom : 230 ~ 300)
- * MEMCG_FAVORITE : recently used application (oom : 270)
- * MEMCG_BACKGROUND : background cgroup (oom : 330 ~ )
- * MEMCG_SWAP : swap cgroup (select victims from background applications)
+ * MEMCG_APPS : apps cgroup including foreground apps, service apps and background active (oom : 150 ~ 250), all processes that were not yet moved to swap
+ * MEMCG_LIMIT : cgroups for each app with memory limit set if conguration is enabled.
+ * MEMCG_SWAP : swap cgroup (select victims from background applications), and Favorite apps
+ *
+ * [memory cgroup hierarchy]
+       /sys/fs/cgroup/memory (root memcg)
+        - Apps
+        - Swap
+        - System.slice (not controlled by resourced)
+               - systemd service AA
+               - systemd service BB
  */
 enum memcg_type {
+       MEMCG_ROOT = -1,
        MEMCG_MEMORY,
-       MEMCG_PLATFORM,
-       MEMCG_FOREGROUND,
-       MEMCG_PREVIOUS,
-       MEMCG_FAVORITE,
-       MEMCG_BACKGROUND,
+       MEMCG_APPS,
+       MEMCG_LIMIT,
        MEMCG_SWAP,
        MEMCG_MAX,
 };
@@ -64,18 +68,34 @@ enum lowmem_control_type {
 
 /* number of memory cgroups */
 #define MEMCG_DEFAULT_NUM_SUBCGROUP            0
-#define MEMCG_DEFAULT_EVENT_LEVEL              "medium"
+#define MEMCG_DEFAULT_EVENT_LEVEL              "low"
 #define MEMCG_DEFAULT_USE_HIERARCHY            0
 
 #define MEMCG_LOW_RATIO                        0.8
 #define MEMCG_MEDIUM_RATIO             0.96
 #define MEMCG_FOREGROUND_LEAVE_RATIO   0.25
 
+#define LOWMEM_ROOT_CGROUP                     "/sys/fs/cgroup/memory"
+#define LOWMEM_APPS_CGROUP                     LOWMEM_ROOT_CGROUP"/Apps"
+#define LOWMEM_MEMLIMIT_CGROUP LOWMEM_ROOT_CGROUP"/MemLimit"
+#define LOWMEM_SWAP_CGROUP                     LOWMEM_ROOT_CGROUP"/Swap"
+#define LOWMEM_SYSTEMD_CGROUP          LOWMEM_ROOT_CGROUP"/system.slice"
+
+#define MEMCG_OOM_CONTROL_PATH         "memory.oom_control"
+#define MEMCG_EVENTFD_CONTROL          "cgroup.event_control"
+#define MEMCG_EVENTFD_MEMORY_PRESSURE  "memory.pressure_level"
+#define MEMCG_USAGE                    "memory.usage_in_bytes"
+#define MEMCG_SWAP_USAGE               "memory.memsw.usage_in_bytes"
+#define MEMCG_LIMIT_PATH               "memory.limit_in_bytes"
+#define MEMCG_SWAP_LIMIT_PATH  "memory.memsw.limit_in_bytes"
+
 struct memcg_info {
        /* name of memory cgroup */
        char name[MAX_PATH_LENGTH];
-       /* id for sub cgroup. 0 if no hierarchy, 0 ~ MAX if use hierarchy */
-       int id;
+       /* hashname of memory cgroup for restoring memcg info*/
+       char hashname[MAX_NAME_LENGTH];
+       /* parent id */
+       int parent_memcg;
        /* limit ratio, if don't want to set limit, use NO_LIMIT*/
        float limit_ratio;
        unsigned int limit;
@@ -84,39 +104,33 @@ struct memcg_info {
        /* thresholds, normal, swap, low, medium, and leave */
        unsigned int threshold[LOWMEM_MAX_LEVEL];
        unsigned int threshold_leave;
-       /* vmpressure event string. If don't want to register event, use null */
-       char event_level[MAX_NAME_LENGTH];
        int evfd;
 };
 
 struct memcg {
-       /* number of sub cgroups */
-       int num_subcgroup;
        /* parent cgroup */
        struct memcg_info *info;
        /* set when using multiple sub cgroups */
-       int use_hierarchy;
+       bool use_hierarchy;
        /* list of child cgroups when using multi groups */
        GSList *cgroups;
 };
 
-struct lowmem_data_type {
+struct lowmem_control_data {
        enum lowmem_control_type control_type;
        int args[2];
 };
 
 void memcg_info_set_limit(struct memcg_info *memcg_info, float ratio,
        unsigned int totalram);
-void memcg_info_init(struct memcg_info *memcg_info, const char *name);
 void memcg_init(struct memcg *memcg);
 void memcg_show(struct memcg *memcg);
-int memcg_add_cgroups(struct memcg *memcg, int num);
 
 /**
  * @desc get anon memory usage of cgroup mi based on memory.stat
  * @return 0 if the value was correctly read
  */
-int memcg_get_anon_usage(struct memcg_info *mi, unsigned long long *anon_usage);
+int memcg_get_anon_usage(struct memcg_info *mi, unsigned int *anon_usage);
 
 /**
  * @desc get memory.get usage_in_bytes from cgroup mi (this is value without swap)
@@ -125,9 +139,9 @@ int memcg_get_anon_usage(struct memcg_info *mi, unsigned long long *anon_usage);
 int memcg_get_usage(struct memcg_info *mi, unsigned int *usage_in_bytes);
 
 /**
- * @desc get PIDs of processes in mi cgroup, an allocated array must be provided
- * @return 0 if pids were read and array filled
+ * @desc register eventfd to the memory cgroup with desired value
+ * @return eventfd if it was registered successfully or -1 on failure
  */
-int memcg_get_pids(struct memcg_info *mi, GArray *pids);
+int memcg_set_eventfd(const char *memcg, const char *event, char *value);
 
 #endif /*__MEMORY_COMMONL_H__*/
index 3b55b5f8f2d0b016fa67df68e78bd3da0938fe5b..fd050710d5b6a0f287cd32f615910a6fb5481308 100644 (file)
@@ -81,6 +81,8 @@ enum notifier_type {
        RESOURCED_NOTIFIER_DATA_RESET,
        RESOURCED_NOTIFIER_SYSTEM_SERVICE,
        RESOURCED_NOTIFIER_CONTROL_EXCLUDE,
+       RESOURCED_NOTIFIER_MEM_STATE_CHANGED,
+       RESOURCED_NOTIFIER_MEM_CONTROL,
 
        /*
         * receive external event
index f121390945d457ef867032f326a9b04c6bed875f..9554b35fcb6dffd19e85ee9a7b10b8cef5c48829 100644 (file)
@@ -158,6 +158,7 @@ struct proc_memory_state {
        struct memcg_info *memcg_info;
        int memcg_idx;
        int oom_score_adj;
+       bool oom_killed;
 };
 
 struct proc_app_info {
index f3a12094b03e7be1f83704021507e7a0f23364b1..7b6a8258ac2a0d07b52f63fc196bce1cb3bee5ec 100644 (file)
@@ -49,6 +49,7 @@
 #include "file-helper.h"
 #include "swap-common.h"
 #include "smaps.h"
+#include "notifier.h"
 
 #define PAGE_SIZE_KB 4
 
@@ -146,8 +147,7 @@ int proc_get_oom_score_adj(int pid, int *oom_score_adj)
 int proc_set_oom_score_adj(int pid, int oom_score_adj)
 {
        FILE *fp;
-       struct lowmem_data_type lowmem_data;
-       static const struct module_ops *lowmem;
+       struct lowmem_control_data lowmem_data;
        char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
 
        snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
@@ -161,16 +161,11 @@ int proc_set_oom_score_adj(int pid, int oom_score_adj)
        fprintf(fp, "%d", oom_score_adj);
        fclose(fp);
 
-       if (!lowmem) {
-               lowmem = find_module("lowmem");
-               if (!lowmem)
-                       return RESOURCED_ERROR_FAIL;
-       }
-       if (lowmem && (oom_score_adj >= OOMADJ_SU)) {
+       if (oom_score_adj >= OOMADJ_SU) {
                lowmem_data.control_type = LOWMEM_MOVE_CGROUP;
                lowmem_data.args[0] = (int)pid;
                lowmem_data.args[1] = (int)oom_score_adj;
-               lowmem->control(&lowmem_data);
+               resourced_notify(RESOURCED_NOTIFIER_MEM_CONTROL, &lowmem_data);
        }
 
        return RESOURCED_ERROR_NONE;
index f60a2cb97a896f24f043299239f91a409f1615fc..8a73ff998318f56e4a0bb12308a5b1ed4d8497a0 100644 (file)
@@ -103,7 +103,7 @@ static void lowmem_dbus_oom_trigger(void *data, DBusMessage *msg)
        }
 
        lowmem_change_memory_state(LOWMEM_LOW, 1);
-       lowmem_memory_oom_killer(OOM_FORCE | OOM_NOMEMORY_CHECK);
+       lowmem_trigger_reclaim(OOM_FORCE | OOM_NOMEMORY_CHECK);
        lowmem_change_memory_state(LOWMEM_NORMAL, 0);
 }
 
@@ -152,7 +152,7 @@ static void lowmem_dbus_set_platform(void *data, DBusMessage *msg)
                        _D("there is no message");
                return;
        }
-       lowmem_trigger_swap(pid, MEMCG_PLATFORM);
+       lowmem_trigger_swap(pid, MEMCG_SWAP);
 }
 
 static const struct edbus_signal edbus_signals[] = {
index 9d48dc31fbf8c4016a3021db5afbdd32932710a1..6bb6a5ddd911461e69372c6c28c71f538a2e3fd6 100644 (file)
 #ifndef __LOWMEM_HANDLER_H__
 #define __LOWMEM_HANDLER_H__
 
+#include <proc-common.h>
 #include <memory-common.h>
 
+struct task_info {
+       /*
+        * Mostly, there are not multiple processes with the same pgid.
+        * So, for the frequent case, we use pid variable to avoid
+        * allocating arrays.
+        */
+       pid_t pid;
+       GArray *pids;
+       pid_t pgid;
+       /* oom_score_adj is smae as /proc/<pid>/oom_score_adj */
+       int oom_score_adj;
+       /*
+        * oom_score_lru is same as oom_score_adj or adjusted by
+        * proc_app_info lru_state for apps that are marked as favourite.
+        *
+        * oom_score_lru is the main value used in comparison for LMK.
+        */
+       int oom_score_lru;
+       int size;
+};
+
 void lowmem_dbus_init(void);
-int lowmem_memory_oom_killer(int flags);
-int lowmem_proactive_oom_killer(int flags, char *appid);
+int lowmem_trigger_reclaim(int flags);
 void lowmem_change_memory_state(int state, int force);
 void lowmem_memcg_set_threshold(int idx, int level, int value);
 void lowmem_memcg_set_leave_threshold(int idx, int value);
 unsigned long lowmem_get_ktotalram(void);
 void lowmem_trigger_swap(pid_t pid, int memcg_idx);
+/**
+ * @desc restore memory cgroup from pid when resourced is restarted
+ */
+void lowmem_restore_memcg(struct proc_app_info *pai);
 
 /*
  * Return memcg pointer to selected cgroup.
@@ -43,10 +68,35 @@ void lowmem_trigger_swap(pid_t pid, int memcg_idx);
 int lowmem_get_memcg(enum memcg_type type, struct memcg **memcg_ptr);
 
 enum oom_killer_cb_flags {
-       OOM_NONE                = 0x00000000,   /* for main oom killer thread */
-       OOM_FORCE               = 0x00000001,   /* for forced kill */
-       OOM_TIMER_CHECK         = 0x00000002,   /* for timer oom killer cb */
-       OOM_NOMEMORY_CHECK      = 0x00000004,   /* check victims' memory */
+       OOM_NONE                = 0x0,          /* for main oom killer thread */
+       OOM_FORCE               = (0x1 << 0),   /* for forced kill */
+       OOM_NOMEMORY_CHECK      = (0x1 << 1),   /* check victims' memory */
+       /*------------------------------------------------------------------*/
+       OOM_IN_DEPTH            = (0x1 << 2),   /* consider all possible cgroups */
+       OOM_SINGLE_SHOT         = (0x1 << 3),   /* do not retry if failed to reclaim memory */
+       OOM_REVISE              = (0x1 << 4),   /* Run another attemp case failed for the first time*/
+       OOM_DROP                = (0x1 << 5),   /* deactivate the worker */
+};
+
+/**
+ * @brief  Low memory killer status
+ *
+ * LOWMEM_RECLAIM_NONE: no potential candidates for memory reclaim
+ * LOWMEM_RECLAIM_DONE: requested size of memory has been successfully
+ *                     reclaimed through terminating number of processes
+ * LOWMEM_RECLAIM_DROP: the whole reclaim procedure should be dropped
+ * LOWMEM_RECLAIM_CONT: selected process might be considered as a potential
+ *                     memory reclaim source - green light for terminating
+ *                     the process
+ * LOWMEM_RECLAIM_WAIT : check again after some seconds
+ *                     because killing processes will take some time.
+ */
+enum {
+       LOWMEM_RECLAIM_NONE,
+       LOWMEM_RECLAIM_DONE,
+       LOWMEM_RECLAIM_DROP,
+       LOWMEM_RECLAIM_CONT,
+       LOWMEM_RECLAIM_WAIT,
 };
 
 #endif /*__LOWMEM_HANDLER_H__*/
index 28d982c5f359b7cdcb19d3b6906481b0edd8a759..f972af77ef449534db0a8ad091ec6c0356e7394f 100644 (file)
 
 #include <string.h>
 #include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/eventfd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "resourced.h"
 #include "trace.h"
 #include "macro.h"
 #include "memory-common.h"
 #include "cgroup.h"
+#include "module.h"
+#include "util.h"
 
 #include <stdlib.h>
 
@@ -52,55 +59,6 @@ void memcg_info_set_limit(struct memcg_info *mi, float ratio,
        mi->oomleave = mi->limit - mi->threshold_leave;
 }
 
-static struct memcg_info *memcg_info_alloc_subcgroup(struct memcg *memcg)
-{
-       struct memcg_info *pmi, *mi;
-       int i;
-       if (!memcg)
-               return NULL;
-       mi = (struct memcg_info *)malloc(sizeof(struct memcg_info));
-       if (!mi)
-               return NULL;
-       mi->id = memcg->num_subcgroup;
-       pmi = memcg->info;
-       snprintf(mi->name, MAX_PATH_LENGTH, "%s/%d",
-               pmi->name, memcg->num_subcgroup++);
-       mi->limit_ratio = pmi->limit_ratio;
-       mi->limit = pmi->limit;
-       mi->oomleave = pmi->oomleave;
-       for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
-               mi->threshold[i] = pmi->threshold[i];
-       mi->threshold_leave = pmi->threshold_leave;
-       strncpy(mi->event_level, pmi->event_level,
-               sizeof(mi->event_level)-1);
-       mi->event_level[sizeof(mi->event_level)-1] = 0;
-       mi->evfd = pmi->evfd;
-       return mi;
-}
-
-static int memcg_add_cgroup(struct memcg *memcg)
-{
-       struct memcg_info *mi = NULL;
-       if (!memcg)
-               return RESOURCED_ERROR_FAIL;
-       mi = memcg_info_alloc_subcgroup(memcg);
-       if (!mi)
-               return RESOURCED_ERROR_FAIL;
-       memcg->cgroups = g_slist_prepend(memcg->cgroups, mi);
-       return RESOURCED_ERROR_NONE;
-}
-
-int memcg_add_cgroups(struct memcg *memcg, int num)
-{
-       int i, ret = RESOURCED_ERROR_NONE;
-       for (i = 0; i < num; i++) {
-               ret = memcg_add_cgroup(memcg);
-               if (ret == RESOURCED_ERROR_FAIL)
-                       return ret;
-       }
-       return ret;
-}
-
 static void memcg_info_show(struct memcg_info *mi)
 {
        int i;
@@ -112,7 +70,6 @@ static void memcg_info_show(struct memcg_info *mi)
        for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
                _D("memcg_info->threshold = %u", mi->threshold[i]);
        _D("memcg_info->threshold_leave = %u", mi->threshold_leave);
-       _D("memcg_info->event_level = %s", mi->event_level);
        _D("memcg_info->evfd = %d", mi->evfd);
 }
 
@@ -127,39 +84,20 @@ void memcg_show(struct memcg *memcg)
        }
 }
 
-void memcg_info_init(struct memcg_info *mi, const char *name)
-{
-       int i;
-       mi->id = 0;
-       mi->limit_ratio = 0;
-       mi->limit = 0;
-       mi->oomleave = 0;
-       for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
-               mi->threshold[i] = 0;
-       mi->threshold_leave = 0;
-       mi->evfd = -1;
-       strncpy(mi->event_level, MEMCG_DEFAULT_EVENT_LEVEL,
-                       sizeof(mi->event_level)-1);
-       mi->event_level[sizeof(mi->event_level)-1] = 0;
-       strncpy(mi->name, name, sizeof(mi->name)-1);
-       mi->name[sizeof(mi->name)-1] = 0;
-}
-
 void memcg_init(struct memcg *memcg)
 {
-       memcg->num_subcgroup = MEMCG_DEFAULT_NUM_SUBCGROUP;
        memcg->use_hierarchy = MEMCG_DEFAULT_USE_HIERARCHY;
        memcg->info = NULL;
        memcg->cgroups = NULL;
 }
 
-int memcg_get_anon_usage(struct memcg_info *mi, unsigned long long *anon_usage)
+int memcg_get_anon_usage(struct memcg_info *mi, unsigned int *anon_usage)
 {
        FILE *f;
        char buf[BUF_MAX] = {0,};
        char line[BUF_MAX] = {0, };
        char name[BUF_MAX] = {0, };
-       unsigned long long tmp, active_anon = 0, inactive_anon = 0;
+       unsigned int tmp, active_anon = 0, inactive_anon = 0;
 
        snprintf(buf, sizeof(buf), "%s/memory.stat", mi->name);
        _I("get mem usage anon from %s", buf);
@@ -170,7 +108,7 @@ int memcg_get_anon_usage(struct memcg_info *mi, unsigned long long *anon_usage)
                return RESOURCED_ERROR_FAIL;
        }
        while (fgets(line, BUF_MAX, f) != NULL) {
-               if (sscanf(line, "%s %llu", name, &tmp)) {
+               if (sscanf(line, "%s %d", name, &tmp)) {
                        if (!strncmp(name, "inactive_anon", strlen("inactive_anon")+1)) {
                                inactive_anon = tmp;
                        } else if (!strncmp(name, "active_anon", strlen("active_anon")+1)) {
@@ -188,7 +126,7 @@ int memcg_get_anon_usage(struct memcg_info *mi, unsigned long long *anon_usage)
 
 int memcg_get_usage(struct memcg_info *mi, unsigned int *usage_bytes)
 {
-       return cgroup_read_node_uint32(mi->name, "memory.usage_in_bytes", usage_bytes);
+       return cgroup_read_node_uint32(mi->name, MEMCG_USAGE, usage_bytes);
 }
 
 /*
@@ -204,7 +142,7 @@ int memcg_get_usage(struct memcg_info *mi, unsigned int *usage_bytes)
  *     g_array_free(pids_array, TRUE);
  *
  */
-int memcg_get_pids(struct memcg_info *mi, GArray *pids)
+int memcg_get_pids(const char *name, GArray *pids)
 {
        FILE *f;
        pid_t tpid;
@@ -213,7 +151,7 @@ int memcg_get_pids(struct memcg_info *mi, GArray *pids)
        if (pids == NULL)
                return RESOURCED_ERROR_FAIL;
 
-       snprintf(buf, sizeof(buf), "%s/cgroup.procs", mi->name);
+       snprintf(buf, sizeof(buf), "%s/cgroup.procs", name);
 
        f = fopen(buf, "r");
        if (!f) {
@@ -229,3 +167,53 @@ int memcg_get_pids(struct memcg_info *mi, GArray *pids)
 
        return RESOURCED_ERROR_NONE;
 }
+
+/*
+ * From memory.txt kernel document,
+ * To register a event for memcg, an application must:
+ *  - create an eventfd using eventfd(2);
+ * - open a node of memory cgroup
+ * - write string like "<event_fd> <opened fd> <value>" to cgroup.event_control
+ *
+ * Current memory cgroup supports eventfd about only
+ * usage_in_byte, oom_control and pressure_level.
+ */
+int memcg_set_eventfd(const char *memcg, const char *event, char *value)
+{
+       _cleanup_close_ int mcgfd = -1;
+       _cleanup_close_ int cgfd = -1;
+       int evfd, res = 0, sz, ret = -1;
+       char buf[PATH_MAX] = {0,};
+
+       /* create an eventfd using eventfd(2)*/
+       evfd = eventfd(0, 0);
+       ret = fcntl(evfd, F_SETFL, O_NONBLOCK);
+       if (ret < 0)
+               return RESOURCED_ERROR_FAIL;
+
+       /* open a node of memory cgroup */
+       sprintf(buf, "%s/%s", memcg, MEMCG_EVENTFD_CONTROL);
+       cgfd = open(buf, O_WRONLY);
+       if (cgfd < 0) {
+               _E("open event_control failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       sprintf(buf, "%s/%s", memcg, event);
+       mcgfd = open(buf, O_RDONLY);
+       if (mcgfd < 0) {
+               _E("open memory control failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       _D("%s %s %s registerd", memcg, event, value);
+       /* write string like "<event_fd> <opened fd> <value>" to cgroup.event_control */
+       sz = sprintf(buf, "%d %d %s", evfd, mcgfd, value);
+       sz += 1;
+       res = write(cgfd, buf, sz);
+       if (res != sz) {
+               _E("write cgfd failed : %d", res);
+               return RESOURCED_ERROR_FAIL;
+       }
+       return evfd;
+}
\ No newline at end of file
diff --git a/src/memory/memory.conf b/src/memory/memory.conf
new file mode 100644 (file)
index 0000000..62143a1
--- /dev/null
@@ -0,0 +1,159 @@
+[VIP_PROCESS]
+# predefined process list
+PREDEFINE=Xorg
+PREDEFINE=enlightenment
+PREDEFINE=dbus-daemon
+PREDEFINE=amd
+PREDEFINE=launchpad_preloading_preinitializing_daemon
+PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
+
+[Memory64]
+# Threshold to start swap
+ThresholdSwap=15               # MB
+
+# Threshold to start reclaim
+ThresholdLow=8                 # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=5              # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=8               # MB
+
+# Number of max victims
+NumMaxVictims=1
+
+[Memory256]
+# Threshold to start swap
+ThresholdSwap=40               # MB
+
+# Threshold to start reclaim
+ThresholdLow=20                        # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=10             # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=20              # MB
+
+# Number of max victims
+NumMaxVictims=2
+
+[Memory448]
+# Threshold to start swap
+ThresholdSwap=100              # MB
+
+# Threshold to start reclaim
+ThresholdLow=60                        # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=50             # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=70              # MB
+
+# Threshold for proactive memory killer
+ProactiveThreshold=80          # MB
+
+# Leave Threshold for proactive memory killer
+ProactiveLeave=100             # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=30            # MB
+
+# Number of max victims
+NumMaxVictims=5
+
+[Memory512]
+# Threshold to start swap
+ThresholdSwap=100              # MB
+
+# Threshold to start reclaim
+ThresholdLow=70                        # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=60             # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=80              # MB
+
+# Threshold for proactive memory killer
+ProactiveThreshold=80          # MB
+
+# Leave Threshold for proactive memory killer
+ProactiveLeave=100             # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=30            # MB
+
+# Number of max victims
+NumMaxVictims=5
+
+[Memory768]
+# Threshold to start swap
+ThresholdSwap=150              # MB
+
+# Threshold to start reclaim
+ThresholdLow=90                # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=80             # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=100             # MB
+
+# Threshold for proactive memory killer
+ProactiveThreshold=100         # MB
+
+# Leave Threshold for proactive memory killer
+ProactiveLeave=130             # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=40            # MB
+
+# Number of max victims
+NumMaxVictims=5
+
+[Memory1024]
+# Threshold to start swap
+ThresholdSwap=300              # MB
+
+# Threshold to start reclaim
+ThresholdLow=120               # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=100            # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=150             # MB
+
+# Threshold for proactive memory killer
+ProactiveThreshold=150         # MB
+
+# Leave Threshold for proactive memory killer
+ProactiveLeave=230             # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=50            # MB
+
+# Number of max victims
+NumMaxVictims=5
+
+[Memory2048]
+# Threshold to start swap
+ThresholdSwap=300              # MB
+
+# Threshold to start reclaim
+ThresholdLow=200               # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=160            # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=300             # MB
+
+# Number of max victims
+NumMaxVictims=10
+
+[POPUP]
+oom_popup=no
diff --git a/src/memory/memory_eng.conf b/src/memory/memory_eng.conf
deleted file mode 100644 (file)
index e2a3fe2..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-[VIP_PROCESS]
-# predefined process list
-PREDEFINE=Xorg
-PREDEFINE=enlightenment
-PREDEFINE=dbus-daemon
-PREDEFINE=amd
-PREDEFINE=launchpad_preloading_preinitializing_daemon
-PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
-
-[Memory64]
-# Threshold to start swap
-ThresholdSwap=15               # MB
-
-# Threshold to start reclaim
-ThresholdLow=8                 # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=5              # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=8               # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=1
-
-[Memory256]
-# Threshold to start swap
-ThresholdSwap=40               # MB
-
-# Threshold to start reclaim
-ThresholdLow=20                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=10             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=20              # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=2
-
-[Memory448]
-# Threshold to start swap
-ThresholdSwap=100              # MB
-
-# Threshold to start reclaim
-ThresholdLow=60                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=50             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=70              # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=80          # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=100             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=30            # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory512]
-# Threshold to start swap
-ThresholdSwap=100              # MB
-
-# Threshold to start reclaim
-ThresholdLow=70                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=60             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=80              # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=80          # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=100             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=30            # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory768]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=100            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=150             # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=150         # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=230             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=50            # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Foreground use hierarchy
-# ForegroundUseHierarchy=1
-
-# Foreground # of cgroups
-# ForegroundNumCgroups=3
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory1024]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=100            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=150             # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory2048]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=160            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=300             # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=10
-
-[POPUP]
-oom_popup=no
diff --git a/src/memory/memory_user.conf b/src/memory/memory_user.conf
deleted file mode 100644 (file)
index 17f20ee..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-[VIP_PROCESS]
-# predefined process list
-PREDEFINE=Xorg
-PREDEFINE=enlightenment
-PREDEFINE=dbus-daemon
-PREDEFINE=amd
-PREDEFINE=launchpad_preloading_preinitializing_daemon
-PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
-
-[Memory64]
-# Threshold to start swap
-ThresholdSwap=15               # MB
-
-# Threshold to start reclaim
-ThresholdLow=8                 # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=5              # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=8               # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-[Memory256]
-# Threshold to start swap
-ThresholdSwap=40               # MB
-
-# Threshold to start reclaim
-ThresholdLow=20                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=10             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=20              # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-# Number of max victims
-NumMaxVictims=2
-
-[Memory448]
-# Threshold to start swap
-ThresholdSwap=100              # MB
-
-# Threshold to start reclaim
-ThresholdLow=60                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=50             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=70              # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=80          # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=100             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=30            # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory512]
-# Threshold to start swap
-ThresholdSwap=100              # MB
-
-# Threshold to start reclaim
-ThresholdLow=70                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=60             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=80              # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=80          # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=100             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=30            # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory768]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=100            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=150             # MB
-
-# Threshold for proactive memory killer
-ProactiveThreshold=150         # MB
-
-# Leave Threshold for proactive memory killer
-ProactiveLeave=230             # MB
-
-# Threshold for dynamic memory killer
-DynamicThreshold=50            # MB
-
-# Foreground limit ratio
-ForegroundRatio=0.6
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory1024]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=100            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=150             # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-# Number of max victims
-NumMaxVictims=5
-
-[Memory2048]
-# Threshold to start swap
-ThresholdSwap=300              # MB
-
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=160            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=300             # MB
-
-# Foreground limit ratio
-ForegroundRatio=1
-
-# Number of max victims
-NumMaxVictims=10
-
-[POPUP]
-oom_popup=no
index 61986b48913e3552e5ad174eb12e23f615a69b4d..229678b6acda8627376a79b97c57fdb555ab0ca2 100644 (file)
@@ -38,7 +38,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/shm.h>
-#include <sys/eventfd.h>
 #include <sys/sysinfo.h>
 #include <Ecore.h>
 #include <sys/time.h>
 #include <bundle.h>
 #include <eventsystem.h>
 
-#include "freezer.h"
 #include "trace.h"
 #include "cgroup.h"
 #include "lowmem-handler.h"
 #include "proc-common.h"
 #include "procfs.h"
+#include "freezer.h"
 #include "resourced.h"
 #include "macro.h"
 #include "notifier.h"
 #include "heart-common.h"
 #include "proc-main.h"
 #include "edbus-handler.h"
+#include "util.h"
 
-#define LOWMEM_DEFAULT_CGROUP          "/sys/fs/cgroup/memory"
 #define LOWMEM_NO_LIMIT                        0
 #define LOWMEM_THRES_INIT              0
 
 #define MEMCG_MOVE_CHARGE_PATH         "memory.move_charge_at_immigrate"
-#define MEMCG_OOM_CONTROL_PATH         "memory.oom_control"
-#define MEMCG_LIMIT_PATH               "memory.limit_in_bytes"
-#define MEMCG_EVENTFD_CONTROL          "cgroup.event_control"
 #define MEMCG_EVENTFD_MEMORY_PRESSURE  "memory.pressure_level"
 #define MEM_CONF_FILE                   RD_CONFIG_FILE(memory)
 #define MEM_VIP_SECTION                        "VIP_PROCESS"
 #define MEM_POPUP_SECTION              "POPUP"
 #define MEM_POPUP_STRING               "oom_popup"
 
-#define BtoMB(x)                       ((x) >> 20)
-#define BtoKB(x)                       ((x) >> 10)
-#define KBtoMB(x)                      ((x) >> 10)
-#define BtoPAGE(x)                     ((x) >> 12)
-#define MBtoKB(x)                      ((x) << 10)
-
 #define BUF_MAX                                1024
 #define MAX_MEMORY_CGROUP_VICTIMS      10
-#define MAX_CGROUP_VICTIMS             1
+#define MAX_VICTIMS_BETWEEN_CHECK      3
 #define OOM_TIMER_INTERVAL             2
 #define OOM_KILLER_PRIORITY            -20
 #define MAX_FD_VICTIMS                 10
-#define MAX_FGRD_KILL                  3
+#define NUM_RM_LOGS                    5
 #define THRESHOLD_MARGIN               10 /* MB */
 
 #define MEM_SIZE_64                    64  /* MB */
@@ -172,76 +162,136 @@ static unsigned dynamic_threshold_min;
 static unsigned dynamic_threshold_adj_gap;
 static unsigned dynamic_oom_threshold;
 
-struct task_info {
-       pid_t pid;
-       pid_t pgid;
-       int oom_score_adj;
-       int size;
+static char *event_level = MEMCG_DEFAULT_EVENT_LEVEL;
+
+/**
+ * Resourced Low Memory Killer
+ * NOTE: planned to be moved to a separate file.
+ */
+/*-------------------------------------------------*/
+#define OOM_TIMER_INTERVAL_SEC 2
+#define LMW_LOOP_WAIT_TIMEOUT_MSEC     OOM_TIMER_INTERVAL_SEC*(G_USEC_PER_SEC)
+#define LMW_RETRY_WAIT_TIMEOUT_MSEC    (G_USEC_PER_SEC)
+
+enum lmk_type {
+       LMK_MEMORY,     /* Kill all range of apps OOMADJ_INIT ~ OOMADJ_APP_MAX */
+       LMK_ACTIVE,     /* Kill active apps OOMADJ_BACKGRD_PERCEPTIBLE ~ OOMADJ_BACKGRD_LOCKED */
+       LMK_INACTIVE,   /* Kill only inactive processes OOMADJ_FAVORITE ~ OOMADJ_APP_MAX */
+};
+
+struct lowmem_control {
+       /*
+        * For each queued request the following properties
+        * are required with two exceptions:
+        *  - status is being set by LMK
+        *  - callback is optional
+        */
+       /* Processing flags*/
+       unsigned int flags;
+       /* Indictator for OOM score of targeted processes */
+       enum lmk_type type;
+       /* Desired size to be restored - level to be reached (MB)*/
+       unsigned int size;
+       /* Max number of processes to be considered */
+       unsigned int count;
+       /* Memory reclaim status */
+       int status;
+       /*
+        * Optional - if set, will be triggered by LMK once the request
+        * is handled.
+        */
+       void (*callback) (struct lowmem_control *);
 };
 
-struct lowmem_process_entry {
-       int cur_mem_state;
-       int new_mem_state;
-       void (*action) (void);
+struct lowmem_worker {
+       pthread_t       worker_thread;
+       GAsyncQueue     *queue;
+       int             active;
+       int             running;
 };
 
+static struct lowmem_worker lmw;
+
+#define LOWMEM_WORKER_IS_ACTIVE(_lmw)  g_atomic_int_get(&(_lmw)->active)
+#define LOWMEM_WORKER_ACTIVATE(_lmw)   g_atomic_int_set(&(_lmw)->active, 1)
+#define LOWMEM_WORKER_DEACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 0)
+
+#define LOWMEM_WORKER_IS_RUNNING(_lmw) g_atomic_int_get(&(_lmw)->running)
+#define LOWMEM_WORKER_RUN(_lmw)        g_atomic_int_set(&(_lmw)->running, 1)
+#define LOWMEM_WORKER_IDLE(_lmw)       g_atomic_int_set(&(_lmw)->running, 0)
+
+#define LOWMEM_NEW_REQUEST() g_slice_new0(struct lowmem_control)
+
+#define LOWMEM_DESTROY_REQUEST(_ctl)           \
+       g_slice_free(typeof(*(_ctl)), _ctl);    \
+
+#define LOWMEM_SET_REQUEST(c, __flags, __type, __size, __count, __cb)  \
+{                                                                      \
+       (c)->flags      = __flags; (c)->type    = __type;               \
+       (c)->size       = __size;  (c)->count   = __count;              \
+       (c)->callback   = __cb;                                         \
+}
+
+static void lowmem_queue_request(struct lowmem_worker *lmw,
+                               struct lowmem_control *ctl)
+{
+       if (LOWMEM_WORKER_IS_ACTIVE(lmw))
+               g_async_queue_push(lmw->queue, ctl);
+}
+
+/* internal */
+static void lowmem_drain_queue(struct lowmem_worker *lmw)
+{
+       struct lowmem_control *ctl;
+
+       g_async_queue_lock(lmw->queue);
+       while ((ctl = g_async_queue_try_pop_unlocked(lmw->queue))) {
+               if (ctl->callback)
+                       ctl->callback(ctl);
+               LOWMEM_DESTROY_REQUEST(ctl);
+       }
+       g_async_queue_unlock(lmw->queue);
+}
+
+static void lowmem_request_destroy(gpointer data)
+{
+       struct lowmem_control *ctl = (struct lowmem_control*) data;
+
+       if (ctl->callback)
+               ctl->callback(ctl);
+       LOWMEM_DESTROY_REQUEST(ctl);
+}
+
+/*-------------------------------------------------*/
+
 /* low memory action function for cgroup */
-static void memory_cgroup_medium_act(int type, struct memcg_info *mi);
+static void memory_cgroup_medium_act(enum lmk_type type, struct memcg_info *mi);
 /* low memory action function */
 static void normal_act(void);
 static void swap_act(void);
 static void low_act(void);
 static void medium_act(void);
 
-static Eina_Bool medium_cb(void *data);
-
-#define LOWMEM_ENTRY(c, n, act)                \
-       { LOWMEM_##c, LOWMEM_##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 cur_mem_state = LOWMEM_NORMAL;
-static Ecore_Timer *oom_check_timer;
 static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
-
-static pthread_t       oom_thread;
-static pthread_mutex_t oom_mutex       = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t  oom_cond        = PTHREAD_COND_INITIALIZER;
+static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
 
 static unsigned long totalram;
 static unsigned long ktotalram;
-static int fg_killed;
 
-static struct module_ops memory_modules_ops;
-static struct module_ops *lowmem_ops;
+static const struct module_ops memory_modules_ops;
+static const struct module_ops *lowmem_ops;
 static bool oom_popup_enable;
 static bool oom_popup;
 
-static const char *memcg_name[MEMCG_MAX] = {
-       NULL,
-       "platform",
-       "foreground",
-       "previous",
-       "favorite",
-       "background",
-       "swap",
+static struct memcg_info gmi[MEMCG_MAX] = {
+       {LOWMEM_ROOT_CGROUP,            "/",            MEMCG_ROOT,},
+       {LOWMEM_APPS_CGROUP,            "Apps",         MEMCG_MEMORY,},
+       {LOWMEM_MEMLIMIT_CGROUP,        "MemLimit",     MEMCG_MEMORY,},
+       {LOWMEM_SWAP_CGROUP,            "Swap",         MEMCG_MEMORY,},
 };
 
-static bool memcg_swap_status[MEMCG_MAX] = {false, };
-
 enum memory_level {
        MEMORY_LEVEL_NORMAL,
        MEMORY_LEVEL_LOW,
@@ -262,29 +312,16 @@ static struct memcg_info *memcg_root;
 
 static GPtrArray *vip_apps;
 
-static char *convert_memstate_to_str(int mem_state)
+static const char *convert_memstate_to_str(int mem_state)
 {
-       char *tmp = NULL;
-       switch (mem_state) {
-       case LOWMEM_NORMAL:
-               tmp = "mem normal";
-               break;
-       case LOWMEM_SWAP:
-               tmp = "mem swap";
-               break;
-       case LOWMEM_LOW:
-               tmp = "mem low";
-               break;
-       case LOWMEM_MEDIUM:
-               tmp = "mem medium";
-               break;
-       default:
-               assert(0);
-       }
-       return tmp;
+       static const char *state_table[] = {"mem normal", "mem swap", "mem low",
+                       "mem medium"};
+       if (mem_state >= 0 && mem_state < LOWMEM_MAX_LEVEL)
+               return state_table[mem_state];
+       return "";
 }
 
-static void adjust_dynamic_threshold(int victim_memcg)
+static void adjust_dynamic_threshold(enum lmk_type lmk_type)
 {
        unsigned prev_dynamic_threshold = dynamic_oom_threshold;
        unsigned available;
@@ -297,7 +334,7 @@ static void adjust_dynamic_threshold(int victim_memcg)
                break;
        case LOWMEM_SWAP:
        case LOWMEM_LOW:
-               if (victim_memcg <= MEMCG_FAVORITE) {
+               if (lmk_type < LMK_INACTIVE) {
                        dynamic_oom_threshold -= dynamic_threshold_adj_gap;
                        break;
                }
@@ -309,7 +346,7 @@ static void adjust_dynamic_threshold(int victim_memcg)
                        dynamic_oom_threshold = memcg_root->threshold[LOWMEM_MEDIUM];
                break;
        case LOWMEM_MEDIUM:
-               if (victim_memcg <= MEMCG_FAVORITE)
+               if (lmk_type < LMK_INACTIVE)
                        dynamic_oom_threshold -= dynamic_threshold_adj_gap;
 
                if (dynamic_oom_threshold < dynamic_threshold_min)
@@ -319,10 +356,10 @@ static void adjust_dynamic_threshold(int victim_memcg)
                break;
        }
 
-       _I("dynamic_threshold is changed from %u to %u, cur_mem_state = %s, victim_memcg = %d",
+       _I("dynamic_threshold is changed from %u to %u, cur_mem_state = %s, lmk_type = %d",
                prev_dynamic_threshold, dynamic_oom_threshold,
                convert_memstate_to_str(cur_mem_state),
-               victim_memcg);
+               lmk_type);
 }
 
 static int lowmem_launch_oompopup(void)
@@ -340,11 +377,11 @@ static inline void get_total_memory(void)
 
        if (!sysinfo(&si)) {
                totalram = si.totalram;
-               ktotalram = BtoKB(totalram);
+               ktotalram = BYTE_TO_KBYTE(totalram);
        }
 }
 
-static int get_proc_mem_usage(pid_t pid, unsigned int *usage)
+static int lowmem_mem_usage_uss(pid_t pid, unsigned int *usage)
 {
        unsigned int uss, zram = 0;
        int ret;
@@ -373,159 +410,167 @@ static int get_proc_mem_usage(pid_t pid, unsigned int *usage)
        return RESOURCED_ERROR_NONE;
 }
 
-static int lowmem_check_current_state(struct memcg_info *mi)
+static int lowmem_mem_usage_rss(pid_t pid, unsigned int *usage)
 {
-       unsigned long long usage, oomleave;
+       unsigned int rss, swap;
        int ret;
 
-       oomleave = (unsigned long long)(mi->oomleave);
-       ret = memcg_get_anon_usage(mi, &usage);
+       *usage = 0;
 
-       if (ret) {
-               _D("getting anonymous usage fails");
+       ret = proc_get_mem_usage(pid, &swap, &rss);
+       if (ret != RESOURCED_ERROR_NONE)
                return ret;
-       }
 
-       if (oomleave > usage) {
-               _D("%s : usage : %llu, leave threshold : %llu",
-                               __func__, usage, oomleave);
-               return RESOURCED_ERROR_NONE;
-       } else {
-               _D("%s : usage : %llu, leave threshold: %llu",
-                               __func__, usage, oomleave);
-               return RESOURCED_ERROR_FAIL;
-       }
+       *usage = rss + swap;
+
+       return RESOURCED_ERROR_NONE;
 }
 
-static int lowmem_get_task_info_array_for_memcg(struct memcg_info *mi, GArray *tasks_array)
+unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
 {
-       int pid_idx, tsk_idx;
-       char appname[BUF_MAX] = {0, };
+       unsigned int size = 0, total_size = 0;
+       int index, ret;
+       pid_t pid;
 
-       GArray *pids_array = g_array_new(false, false, sizeof(pid_t));
-       memcg_get_pids(mi, pids_array);
+       /*
+        * If pids are allocated only when there are multiple processes with
+        * the same pgid e.g., browser and web process. Mostly, single process
+        * is used.
+        */
+       if (tsk->pids == NULL) {
+               ret = lowmem_mem_usage_rss(tsk->pid, &size);
 
-       if (pids_array->len == 0)
-               /*
-                * if task read in this cgroup fails,
-                * return the current number of victims
+               /* If there is no proc entry for given pid the process
+                * should be abandoned during further processing
                 */
-               return tasks_array->len;
+               if (ret < 0)
+                       _D("failed to get rss memory usage of %d", tsk->pid);
 
-       for (pid_idx = 0; pid_idx < pids_array->len; pid_idx++) {
-               pid_t tpid = 0;
-               int toom = 0;
-               unsigned int tsize = 0;
-
-               tpid = g_array_index(pids_array, pid_t, pid_idx);
+               return size;
+       }
 
-               if (proc_get_oom_score_adj(tpid, &toom) < 0 ||
-                       toom <= OOMADJ_SERVICE_MIN) {
-                       _D("pid(%d) was already terminated or high priority oom = %d",
-                               tpid, toom);
+       for (index = 0; index < tsk->pids->len; index++) {
+               pid = g_array_index(tsk->pids, pid_t, index);
+               ret = lowmem_mem_usage_rss(pid, &size);
+               if (ret != RESOURCED_ERROR_NONE)
                        continue;
-               }
+               total_size += size;
+       }
 
-               if (get_proc_mem_usage(tpid, &tsize) < 0) {
-                       _D("pid(%d) size is not available\n", tpid);
-                       continue;
-               }
+       return total_size;
+}
 
-               if (proc_get_cmdline(tpid, appname) < 0)
-                       continue;
+static unsigned int get_task_mem_usage_uss(const struct task_info *tsk)
+{
+       unsigned int size = 0, total_size = 0;
+       int index, ret;
+       pid_t pid;
 
-               for (tsk_idx = 0; tsk_idx < tasks_array->len; tsk_idx++) {
-                       struct task_info *tsk = &g_array_index(tasks_array,
-                                       struct task_info, tsk_idx);
-                       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 pids are allocated only when there are multiple processes with
+        * the same pgid e.g., browser and web process. Mostly, single process
+        * is used.
+        */
+       if (tsk->pids == NULL) {
+               ret = lowmem_mem_usage_uss(tsk->pid, &size);
 
-               if (tsk_idx == tasks_array->len) {
-                       struct task_info tsk;
-                       tsk.pid = tpid;
-                       tsk.pgid = getpgid(tpid);
-                       tsk.oom_score_adj = toom;
-                       tsk.size = tsize;
+               if (ret < 0)
+                       _D("failed to get uss memory usage of %d", tsk->pid);
 
-                       g_array_append_val(tasks_array, tsk);
-               }
+               return size;
+       }
 
+       for (index = 0; index < tsk->pids->len; index++) {
+               pid = g_array_index(tsk->pids, pid_t, index);
+               ret = lowmem_mem_usage_uss(pid, &size);
+               if (ret != RESOURCED_ERROR_NONE)
+                       continue;
+               total_size += size;
        }
 
-       g_array_free(pids_array, TRUE);
-       return tasks_array->len;
+       return total_size;
+}
+
+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 lowmem_kill_victim(struct task_info *tsk,
-               int flags, unsigned int *total_size)
+static int lowmem_kill_victim(const struct task_info *tsk,
+               int flags, unsigned int *victim_size)
 {
        pid_t pid;
        int ret;
-       unsigned int total = 0;
        char appname[PATH_MAX];
-       int sigterm;
+       int sigterm = 0;
+       unsigned int size;
+       struct proc_app_info *pai;
 
        pid = tsk->pid;
 
        if (pid <= 0 || pid == getpid())
-               return;
+               return RESOURCED_ERROR_FAIL;
 
        ret = proc_get_cmdline(pid, appname);
        if (ret == RESOURCED_ERROR_FAIL)
-               return;
+               return RESOURCED_ERROR_FAIL;
 
-       if (!strncmp("memps", appname, strlen(appname)+1) ||
-           !strncmp("crash-worker", appname, strlen(appname)+1) ||
-           !strncmp("system-syspopup", appname, strlen(appname)+1)) {
+       if (!strcmp("crash-worker", appname) ||
+           !strcmp("system-syspopup", appname)) {
                _E("%s(%d) was selected, skip it", appname, pid);
-               return;
+               return RESOURCED_ERROR_FAIL;
        }
 
-       ret = get_proc_mem_usage(tsk->pid, &total);
-       if (ret != RESOURCED_ERROR_NONE) {
-               _E("Failed to get memory usage : %d", ret);
-               return;
-       }
-       total += *total_size;
+       size = get_task_mem_usage_uss(tsk);
+       if (size == 0)
+               return ret;
 
-       resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
-                   pid, NULL, NULL, PROC_TYPE_NONE);
+       pai = find_app_info(pid);
 
-       if (tsk->oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
-               sigterm = 1;
-       } else if (tsk->oom_score_adj == OOMADJ_BACKGRD_LOCKED) {
-               int app_flag = proc_get_appflag(pid);
-               sigterm = app_flag & PROC_SIGTERM;
-       } else
-               sigterm = 0;
+       if (pai) {
+               resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
+                       pid, NULL, NULL, PROC_TYPE_NONE);
+
+               if (tsk->oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
+                       sigterm = 1;
+               } else if (tsk->oom_score_adj == OOMADJ_BACKGRD_LOCKED) {
+                       int app_flag = pai->flags;
+                       sigterm = app_flag & PROC_SIGTERM;
+               }
+
+               if (pai->memory.oom_killed)
+                       sigterm = 0;
+
+               pai->memory.oom_killed = true;
+       }
 
        if (sigterm)
                kill(pid, SIGTERM);
        else
                kill(pid, SIGKILL);
 
-       _E("we killed, force(%d), %d (%s) score = %d, size = %u KB, victim total size = %u KB, sigterm = %d\n",
-                       flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
-                       tsk->size, total, sigterm);
-       *total_size = total;
+       _E("we killed, force(%d), %d (%s) score = %d, size: rss = %u  uss = %u KB, sigterm = %d\n",
+          flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
+          tsk->size, size, sigterm);
+       *victim_size = size;
 
        if (tsk->oom_score_adj > OOMADJ_FOREGRD_UNLOCKED)
-               return;
+               return RESOURCED_ERROR_NONE;
 
        if (oom_popup_enable && !oom_popup) {
                lowmem_launch_oompopup();
                oom_popup = true;
        }
+
+       return RESOURCED_ERROR_NONE;
 }
 
-/* return RESOURCED_ERROR_NONE when kill should be continued */
+/* return LOWMEM_RECLAIM_CONT when killing should be continued */
 static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
 {
        unsigned int available;
@@ -535,20 +580,20 @@ static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
         * only when the available memory is less than dynamic oom threshold.
         */
        if (tsk->oom_score_adj > OOMADJ_BACKGRD_PERCEPTIBLE)
-               return RESOURCED_ERROR_NONE;
+               return LOWMEM_RECLAIM_CONT;
 
-       if ((flags & OOM_FORCE) || !(flags & OOM_TIMER_CHECK)) {
-               _I("%d is skipped during force kill, flag = %d",
+       if ((flags & (OOM_FORCE|OOM_SINGLE_SHOT)) || !(flags & OOM_REVISE)) {
+               _I("%d is dropped during force kill, flag = %d",
                        tsk->pid, flags);
-               return RESOURCED_ERROR_FAIL;
+               return LOWMEM_RECLAIM_DROP;
        }
        available = proc_get_mem_available();
        if (available > dynamic_oom_threshold) {
                _I("available: %d MB, larger than %u MB, do not kill foreground",
                        available, dynamic_oom_threshold);
-               return RESOURCED_ERROR_FAIL;
+               return LOWMEM_RECLAIM_WAIT;
        }
-       return RESOURCED_ERROR_NONE;
+       return LOWMEM_RECLAIM_CONT;
 }
 
 static int compare_victims(const struct task_info *ta, const struct task_info *tb)
@@ -563,81 +608,44 @@ static int compare_victims(const struct task_info *ta, const struct task_info *t
        if (ta->oom_score_adj != tb->oom_score_adj)
                return tb->oom_score_adj - ta->oom_score_adj;
 
+       /*
+        * Get memory usage for tasks with the same oom score.
+        * Since there could be multiple tasks with the same pgid,
+        * we sum all of the tasks.
+        * Even though we calculate memory usage when we should compare it,
+        * there could be frequent cases to get memory usage of tasks that
+        * would not be selected as victim. Therefore we just use RSS + Swap,
+        * which causes much less overhead.
+        */
        return (int)(tb->size) - (int)(ta->size);
 }
 
 static int compare_victims_point(const struct task_info *ta, const struct task_info *tb)
 {
        unsigned int pa, pb;
+
        assert(ta != NULL);
        assert(tb != NULL);
 
-       /*
-        * followed by kernel badness point calculation using heuristic.
-        * oom_score_adj is normalized by its unit, which varies -1000 ~ 1000.
-        * Since we only consider tasks with oom_score_adj larger than 0
-        * as victim candidates, point always has positive value.
-        */
        pa = ta->oom_score_adj * (ktotalram / 1000) + ta->size;
        pb = tb->oom_score_adj * (ktotalram / 1000) + tb->size;
 
        return pb - pa;
 }
 
-static int lowmem_kill_cgroup_victims(int type, struct memcg_info *mi,
-       int max_victims, unsigned should_be_freed, int flags,
-       unsigned int *total_size, int *completed)
+static void lowmem_free_task_info_array(GArray *array)
 {
-       int i, ret, victim = 0, count = 0;
-       unsigned total_victim_size = 0;
-       GArray *candidates = NULL;
-
-       candidates = g_array_new(false, false, sizeof(struct task_info));
-
-       /* if g_array_new fails, return the current number of victims */
-       if (candidates == NULL)
-               return victim;
-
-       /*
-        * if there is no tasks in this cgroup,
-        * return the current number of victims
-        */
-       count = lowmem_get_task_info_array_for_memcg(mi, candidates);
-       if (count == 0) {
-               g_array_free(candidates, true);
-               return victim;
-       }
-
-       g_array_sort(candidates,
-               (GCompareFunc)compare_victims);
+       int i;
 
-       for (i = 0; i < candidates->len; i++) {
+       for (i = 0; i < array->len; i++) {
                struct task_info *tsk;
-               if (i >= max_victims ||
-                   (!(flags & OOM_NOMEMORY_CHECK) &&
-                   total_victim_size >= MBtoKB(should_be_freed))) {
-                       _E("victim = %d, max_victims = %d, total_size = %u",
-                               i, max_victims, total_victim_size);
-                       break;
-               }
-
-               tsk = &g_array_index(candidates, struct task_info, i);
-
-               ret = lowmem_check_kill_continued(tsk, flags);
-               if (ret == RESOURCED_ERROR_FAIL && completed) {
-                       _E("checked kill continued and completed");
-                       *completed = 1;
-                       break;
-               }
 
-               lowmem_kill_victim(tsk, flags, &total_victim_size);
+               tsk = &g_array_index(array, struct task_info, i);
+               if (tsk->pids)
+                       g_array_free(tsk->pids, true);
        }
 
-       victim = i;
-       g_array_free(candidates, true);
-       *total_size = total_victim_size;
-
-       return victim;
+       g_array_free(array, true);
 }
 
 static inline int is_dynamic_process_killer(int flags)
@@ -645,43 +653,6 @@ static inline int is_dynamic_process_killer(int flags)
        return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK);
 }
 
-static int lowmem_kill_subcgroup_victims(int type, int max_victims, int flags,
-       unsigned int *total_size, int *completed)
-{
-       GSList *iter = NULL;
-       GArray *candidates = NULL;
-       int i, ret, victim = 0;
-       unsigned int total_victim_size = 0;
-       struct task_info *tsk;
-
-       candidates = g_array_new(false, false, sizeof(struct task_info));
-       gslist_for_each_item(iter, memcg_tree[type]->cgroups) {
-               struct memcg_info *mi =
-                       (struct memcg_info *)(iter->data);
-               int count = lowmem_get_task_info_array_for_memcg(mi, candidates);
-               _D("get %d pids", count);
-       }
-
-       g_array_sort(candidates, (GCompareFunc)compare_victims);
-
-       for (i = 0; i < candidates->len; i++) {
-               if (i == max_victims)
-                       break;
-
-               tsk = &g_array_index(candidates, struct task_info, i);
-
-               ret = lowmem_check_kill_continued(tsk, flags);
-               if (ret == RESOURCED_ERROR_FAIL)
-                       break;
-
-               lowmem_kill_victim(tsk, flags, &total_victim_size);
-       }
-
-       victim = i;
-       g_array_free(candidates, true);
-       return victim;
-}
-
 static unsigned int is_memory_recovered(unsigned int *avail, unsigned int *thres)
 {
        unsigned int available = proc_get_mem_available();
@@ -715,21 +686,17 @@ static int lowmem_get_pids_proc(GArray *pids)
                _E("fail to open /proc");
                return RESOURCED_ERROR_FAIL;
        }
-       while ((dentry = readdir(dp))) {
+       while ((dentry = readdir(dp)) != NULL) {
                struct task_info tsk;
                pid_t pid = 0, pgid = 0;
                int oom = 0;
-               unsigned int size = 0;
 
                if (!isdigit(dentry->d_name[0]))
                        continue;
 
                pid = (pid_t)atoi(dentry->d_name);
-               if (pid < 0)
-                       continue;
-
                pgid = getpgid(pid);
-               if (pgid < 0)
+               if (!pgid)
                        continue;
 
                if (proc_get_oom_score_adj(pid, &oom) < 0) {
@@ -737,34 +704,33 @@ static int lowmem_get_pids_proc(GArray *pids)
                        continue;
                }
 
-               if (get_proc_mem_usage(pid, &size) < 0) {
-                       _D("pid(%d) size is not available\n", pid);
-                       continue;
-               }
-
                if (proc_get_cmdline(pid, appname) < 0)
                        continue;
 
+               /*
+                * Currently, for tasks in the memory cgroup,
+                * do not consider multiple tasks with one pgid.
+                */
                tsk.pid = pid;
                tsk.pgid = pgid;
                tsk.oom_score_adj = oom;
-               tsk.size = size;
+               tsk.pids = NULL;
+               tsk.size = lowmem_get_task_mem_usage_rss(&tsk);
 
                g_array_append_val(pids, tsk);
        }
 
        closedir(dp);
-
-       if (pids->len)
-               return pids->len;
-       return RESOURCED_ERROR_FAIL;
+       return RESOURCED_ERROR_NONE;
 }
 
-static int lowmem_kill_memory_cgroup_victims(int flags)
+static int lowmem_kill_victims_from_proc(int flags, int *completed, int threshold)
 {
        GArray *candidates = NULL;
-       int i, count, victim = 0;
-       unsigned int av, total_victim_size = 0;
+       int i, ret, victim = 0;
+       unsigned int victim_size = 0;
+       unsigned int total_size = 0;
+       unsigned int available  = 0;
        struct task_info *tsk;
 
        candidates = g_array_new(false, false, sizeof(struct task_info));
@@ -773,246 +739,394 @@ static int lowmem_kill_memory_cgroup_victims(int flags)
        if (candidates == NULL)
                return victim;
 
-       count = lowmem_get_pids_proc(candidates);
+       ret = lowmem_get_pids_proc(candidates);
 
-       if (count <= 0)
-               return victim;
+       if (ret != RESOURCED_ERROR_NONE || !candidates->len)
+               goto leave;
 
        g_array_sort(candidates, (GCompareFunc)compare_victims_point);
 
        _I("start to kill for memory cgroup");
+       available = proc_get_mem_available();
+
        for (i = 0; i < candidates->len; i++) {
-               tsk = &g_array_index(candidates, struct task_info, i);
+               if (i >= num_max_victims)
+                       break;
 
-               av = proc_get_mem_available();
+               /*
+                * Available memory is checking only every
+                * num_vict_between_check process for reducing burden.
+                */
 
-               if (av > dynamic_oom_threshold || i >= num_max_victims) {
-                       _I("checking proc, available: %d MB, larger than threshold margin", av);
-                       g_array_free(candidates, true);
-                       victim = i;
-                       return victim;
+               if (!(i % num_vict_between_check)) {
+                       if (proc_get_mem_available() > threshold) {
+                               *completed = LOWMEM_RECLAIM_DONE;
+                               break;
+                       }
                }
-               lowmem_kill_victim(tsk, flags, &total_victim_size);
+
+               tsk = &g_array_index(candidates, struct task_info, i);
+
+               if (available  + total_size > dynamic_oom_threshold)
+                       break;
+               ret = lowmem_kill_victim(tsk, flags, &victim_size);
+               if (ret != RESOURCED_ERROR_NONE)
+                       continue;
+               victim++;
+               total_size += KBYTE_TO_MBYTE(victim_size);
+       }
+
+       if (available + total_size  > dynamic_oom_threshold) {
+               _I("Reached the threshold margin: available mem: %d MB\n",
+                       available);
+               *completed = LOWMEM_RECLAIM_DONE;
+       } else {
+               _I("Failed to reach the threshold margin: available mem: %d "
+                       "with %d processes killed\n", available, victim);
+               *completed = LOWMEM_RECLAIM_CONT;
        }
-       victim = i;
-       g_array_free(candidates, true);
+
+leave:
+       lowmem_free_task_info_array(candidates);
+
        return victim;
 }
 
-/* Find victims: (SWAP -> ) BACKGROUND */
-static int lowmem_kill_all_cgroup_victims(int flags, int *completed)
+/**
+ * @brief Terminate up to max_victims processes after finding them from pai.
+       It depends on proc_app_info lists
+       and it also reference systemservice cgroup
+       because some processes in this group don't have proc_app_info.
+ *
+ * @max_victims:           max number of processes to be terminated
+ * @start_oom:     find victims from start oom adj score value
+ * @end_oom: find victims to end oom adj score value
+ * @should_be_freed: amount of memory to be reclaimed (in MB)
+ * @total_size[out]: total size of possibly reclaimed memory (required)
+ * @completed:     final outcome (optional)
+ * @threshold:         desired value of memory available
+ */
+static int lowmem_kill_victims(int max_victims,
+       int start_oom, int end_oom, unsigned should_be_freed, int flags,
+       unsigned int *total_size, int *completed, int threshold)
 {
-       int i, count = 0;
-       unsigned int available = 0, should_be_freed = 0, leave_threshold = 0;
-       struct memcg_info *mi;
-       unsigned int total_size = 0;
+       GSList *proc_app_list = NULL;
+       int i, ret, victim = 0;
+       unsigned int victim_size = 0;
+       unsigned int total_victim_size = 0;
+       unsigned int total_task_size = 0;
+       int status = LOWMEM_RECLAIM_NONE;
+       GArray *candidates = NULL;
+       GSList *iter, *iterchild;
+       struct proc_app_info *pai = NULL;
+       int oom_score_adj;
+       int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
+
+       candidates = g_array_new(false, false, sizeof(struct task_info));
 
-       for (i = MEMCG_MAX - 1; i > 0; i--) {
-               adjust_dynamic_threshold(i);
+       proc_app_list = proc_app_list_open();
+       gslist_for_each_item(iter, proc_app_list) {
+               struct task_info ti;
 
-               should_be_freed = is_memory_recovered(&available, &leave_threshold);
+               pai = (struct proc_app_info *)iter->data;
+               if (!pai->main_pid)
+                       continue;
 
-               if (should_be_freed == 0)
-                       return count;
+               oom_score_adj = pai->memory.oom_score_adj;
+               if (oom_score_adj > end_oom || oom_score_adj < start_oom)
+                       continue;
 
-               if (!memcg_tree[i] || !memcg_tree[i]->info)
+               if ((flags & OOM_REVISE) && pai->memory.oom_killed)
                        continue;
 
-               mi = memcg_tree[i]->info;
+               ti.pid = pai->main_pid;
+               ti.pgid = getpgid(ti.pid);
+               ti.oom_score_adj = oom_score_adj;
 
-               /*
-                * Processes in the previous cgroup are killed only when
-                * the available memory is less than dynamic oom threshold.
-                */
-               if ((i <= MEMCG_PREVIOUS) &&
-                   (available > dynamic_oom_threshold)) {
-                       _E("do not try fg group, %u > %u, completed",
-                               available, dynamic_oom_threshold);
+               if (pai->childs) {
+                       ti.pids = g_array_new(false, false, sizeof(pid_t));
+                       g_array_append_val(ti.pids, ti.pid);
+                       gslist_for_each_item(iterchild, pai->childs) {
+                               pid_t child = GPOINTER_TO_PID(iterchild->data);
+                               g_array_append_val(ti.pids, child);
+                       }
+               } else
+                       ti.pids = NULL;
 
-                       if (completed)
-                               *completed = 1;
+               ti.size = lowmem_get_task_mem_usage_rss(&ti);
+               g_array_append_val(candidates, ti);
+               total_task_size += ti.size;
+       }
 
-                       return count;
-               }
+       proc_app_list_close();
 
-               _I("%s start, available = %u, should_be_freed = %u",
-                       mi->name, available, should_be_freed);
+       if (!candidates->len)
+               goto leave;
 
-               if (memcg_tree[i]->use_hierarchy)
-                       count = lowmem_kill_subcgroup_victims(i, num_max_victims,
-                                       flags, &total_size, completed);
-               else
-                       count = lowmem_kill_cgroup_victims(i, mi,
-                                       num_max_victims, should_be_freed,
-                                       flags, &total_size, completed);
+       g_array_sort(candidates, (GCompareFunc)compare_victims);
 
-               if (count == 0) {
-                       _E("%s: there is no victim", mi->name);
-                       continue;
-               }
+       for (i = 0; i < candidates->len; i++) {
+               struct task_info *tsk;
 
-               if (completed && *completed) {
-                       _E("completed after kill %s cgroup", mi->name);
+               if (i >= max_victims) {
+                       status = LOWMEM_RECLAIM_WAIT;
                        break;
                }
 
-               if ((flags & OOM_TIMER_CHECK) && (i <= MEMCG_PREVIOUS)) {
-                       if (++fg_killed >= MAX_FGRD_KILL) {
-                               _E("foreground is killed %d times and search from proc", fg_killed);
-                               fg_killed = 0;
-                               continue;
+               /*
+                * Available memory is checking only every
+                * num_vict_between_check process for reducing burden.
+                */
+               if (!(i % num_vict_between_check)) {
+                       if (proc_get_mem_available() > threshold) {
+                               status = LOWMEM_RECLAIM_DONE;
+                               break;
                        }
-                       _E("foreground is killed %d times", fg_killed);
                }
 
-               _E("%s: kill %d victims, total_size = %u",
-                               mi->name, count, total_size);
-               return count;
-       }
+               if (!(flags & OOM_NOMEMORY_CHECK) &&
+                   total_victim_size >= should_be_freed_kb) {
+                       _E("victim = %d, max_victims = %d, total_size = %u",
+                               victim, max_victims, total_victim_size);
+                       status = LOWMEM_RECLAIM_DONE;
+                       break;
+               }
 
-       if (completed && !(*completed))
-               count = lowmem_kill_memory_cgroup_victims(flags);
+               tsk = &g_array_index(candidates, struct task_info, i);
 
-       return count;
-}
+               status = lowmem_check_kill_continued(tsk, flags);
+               if (status != LOWMEM_RECLAIM_CONT)
+                       break;
 
-static int lowmem_kill_victims(int type, struct memcg_info *mi, int flags,
-       int *completed)
-{
-       unsigned int total_size = 0;
-       int count;
+               _I("select victims from proc_app_list pid(%d)\n", tsk->pid);
 
-       if (type == MEMCG_MEMORY)
-               count = lowmem_kill_all_cgroup_victims(flags, completed);
-       else
-               count = lowmem_kill_cgroup_victims(type, mi,
-                               MAX_CGROUP_VICTIMS, mi->threshold_leave,
-                               flags, &total_size, completed);
+               ret = lowmem_kill_victim(tsk, flags, &victim_size);
+               if (ret != RESOURCED_ERROR_NONE)
+                       continue;
+               victim++;
+               total_victim_size += victim_size;
+       }
 
-       return count;
+leave:
+       lowmem_free_task_info_array(candidates);
+       *total_size = total_victim_size;
+       *completed = status;
+       return victim;
 }
 
-static int lowmem_oom_killer_cb(int type, struct memcg_info *mi, int flags,
-       int *completed)
+static void calualate_range_of_oom(enum lmk_type lmk, int *min, int *max)
 {
-       int count = 0;
-
-       /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
-       count = lowmem_kill_victims(type, mi, flags, completed);
-
-       if (count == 0) {
-               _D("victim count = %d", count);
-               return count;
+       if (lmk == LMK_INACTIVE) {
+               *max = OOMADJ_APP_MAX;
+               *min = OOMADJ_FAVORITE;
+       } else if (lmk == LMK_ACTIVE) {
+               *max = OOMADJ_APP_MAX;
+               *min = OOMADJ_BACKGRD_PERCEPTIBLE;
+       } else {
+               *max = OOMADJ_APP_MAX;
+               *min = OOMADJ_SU;
        }
-
-       /* check current memory status */
-       if (!(flags & OOM_FORCE) && type != MEMCG_MEMORY &&
-                       lowmem_check_current_state(mi) >= 0)
-               return count;
-
-       return count;
 }
 
-static int lowmem_force_oom_killer(int flags, unsigned int should_be_freed,
-       int max_victims)
+static void lowmem_handle_request(struct lowmem_control *ctl)
 {
-       int count = 0, completed = 0, i;
-       unsigned int total_size, freed = 0;
+       int start_oom, end_oom;
+       int count = 0, victim_cnt = 0;
+       int status = LOWMEM_RECLAIM_NONE;
+       unsigned int available = 0, leave_threshold = 0;
+       unsigned int total_size = 0;
+       unsigned int current_size = 0;
+       unsigned int reclaim_size, shortfall = 0;
+       enum lmk_type lmk_type = ctl->type;
 
-       lowmem_change_memory_state(LOWMEM_LOW, 1);
-       for (i = MEMCG_MAX - 1; i >= MEMCG_BACKGROUND; i--) {
-               int num_max = max_victims - count;
-               unsigned int remained = should_be_freed - freed;
-               count += lowmem_kill_cgroup_victims(i, memcg_tree[i]->info,
-                       num_max, remained, flags, &total_size, &completed);
-               freed += KBtoMB(total_size);
-               _D("force kill total %d victims, freed = %u", count, freed);
-               if (should_be_freed > 0 && freed >= should_be_freed)
-                       break;
-       }
-       lowmem_change_memory_state(LOWMEM_NORMAL, 0);
+       available = proc_get_mem_available();
+       reclaim_size = ctl->size  > available
+                    ? ctl->size - available : 0;
 
-       return count;
-}
+       if (!reclaim_size) {
+               status = LOWMEM_RECLAIM_DONE;
+               goto done;
+       }
 
-static void *lowmem_oom_killer_pthread(void *arg)
+       /*
+        * We've entered here after LOWMEM_RECLAIM_WAIT with lmk_type == LMK_MEMORY.
+        * We're going to try to kill some of processes in /procfs to handle
+        * low memory situation. If this doesn't end with success let's try again
+        * starting from Inactive.
+        */
+       if (lmk_type == LMK_MEMORY) {
+               count += lowmem_kill_victims_from_proc(ctl->flags, &status, ctl->size);
+               _D("Returned from /proc killing, count: %d, status: %d", count, status);
+               if (status == LOWMEM_RECLAIM_DONE)
+                       goto done;
+               else
+                       lmk_type = LMK_INACTIVE;
+       }
+retry:
+       /* Prepare LMK to start doing it's job. Check preconditions. */
+       calualate_range_of_oom(lmk_type, &start_oom, &end_oom);
+       adjust_dynamic_threshold(lmk_type);
+       shortfall = is_memory_recovered(&available, &leave_threshold);
+
+       if (!shortfall || !reclaim_size) {
+               status = LOWMEM_RECLAIM_DONE;
+               goto done;
+       }
+       _D("reclaim start, available = %u, currently required = %u, possibly reclaimed: %u, type: %d",
+               available, reclaim_size, total_size, lmk_type);
+
+       /* precaution */
+       current_size = 0;
+       victim_cnt = lowmem_kill_victims(ctl->count - count, start_oom, end_oom,
+                           reclaim_size, ctl->flags, &current_size, &status, ctl->size);
+
+       current_size = KBYTE_TO_MBYTE(current_size);
+       count += victim_cnt;
+       total_size += current_size;
+
+       reclaim_size -= reclaim_size > current_size
+                           ? current_size : reclaim_size;
+       _E("kill %d victims, total_size = %u from %d to %d %d",
+               victim_cnt, current_size, start_oom, end_oom, status);
+
+       if ((status == LOWMEM_RECLAIM_DONE) ||
+           (status == LOWMEM_RECLAIM_WAIT) ||
+           (status == LOWMEM_RECLAIM_DROP))
+               goto done;
+
+       if (victim_cnt)
+               _E("So far: killed %d processes reclaimed: %u remaining: %u shortfall: %u\n",
+                       count, total_size, reclaim_size, shortfall);
+
+       /*
+        * If it doesn't finish reclaiming memory in first operation,
+               - if flags has OOM_IN_DEPTH,
+                  try to find victims again in the active cgroup.
+                  otherwise, just return because there is no more victims in the desired cgroup.
+               - if flags has OOM_REVISE,
+                  it means that resourced can't find victims from proc_app_list.
+                  So, it should search victims or malicious process from /proc.
+                  But searching /proc leads to abnormal behaviour.
+                  (Make sluggish or kill same victims continuously)
+                  Thus, otherwise, just return in first operation and wait some period.
+        */
+       if ((count < ctl->count) && (ctl->flags & OOM_IN_DEPTH)) {
+               if (lmk_type == LMK_INACTIVE) {
+                       /* We tried in inactive processes and didn't succeed, try immediately in active */
+                       _D("Inactive wasn't enough, lets try in Active.");
+                       lmk_type = LMK_ACTIVE;
+                       goto retry;
+               } else if (lmk_type == LMK_ACTIVE) {
+                       /*
+                        * We tried in INACTIVE and ACTIVE but still didn't succeed
+                        * so it's time to try in /proc. Before doing it wait some time.
+                        */
+                       ctl->status = LOWMEM_RECLAIM_WAIT;
+                       ctl->type = LMK_MEMORY;
+                       _D("We would need to kill from /proc wait some time and try again");
+                       return;
+               }
+       }
+done:
+       _E("Done: killed %d processes reclaimed: %u remaining: %u shortfall: %u status: %d\n",
+               count, total_size, reclaim_size, shortfall, status);
+       ctl->status = status;
+       return;
+}
+
+static void *lowmem_reclaim_worker(void *arg)
 {
-       int ret = RESOURCED_ERROR_NONE;
+       struct lowmem_worker *lmw = (struct lowmem_worker *)arg;
 
        setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
 
+       g_async_queue_ref(lmw->queue);
+
        while (1) {
-               /*
-                * When signalled by main thread,
-                * it starts lowmem_oom_killer_cb().
-                */
-               ret = pthread_mutex_lock(&oom_mutex);
-               if (ret) {
-                       _E("oom thread::pthread_mutex_lock() failed, %d", ret);
-                       break;
-               }
+               struct lowmem_control *ctl;
 
-               ret = pthread_cond_wait(&oom_cond, &oom_mutex);
-               if (ret) {
-                       _E("oom thread::pthread_cond_wait() failed, %d", ret);
-                       pthread_mutex_unlock(&oom_mutex);
-                       break;
-               }
+               LOWMEM_WORKER_IDLE(lmw);
+               /* Wait on any wake-up call */
+               ctl = g_async_queue_pop(lmw->queue);
 
-               _I("oom thread conditional signal received and start");
-               lowmem_oom_killer_cb(MEMCG_MEMORY, memcg_root, OOM_NONE, NULL);
+               if (!LOWMEM_WORKER_IS_ACTIVE(lmw) || (ctl->flags & OOM_DROP))
+                       break;
 
-               _I("lowmem_oom_killer_cb finished");
+               LOWMEM_WORKER_RUN(lmw);
+process_again:
+               lowmem_handle_request(ctl);
+               /**
+                * Case the process failed to reclaim requested amount of memory
+                * or still under have memory pressure - try the timeout wait.
+                * There is a chance this will get woken-up in a better reality.
+                */
+               if (ctl->status != LOWMEM_RECLAIM_DONE &&
+                   !(ctl->flags & OOM_SINGLE_SHOT)) {
+                       unsigned int available = proc_get_mem_available();
+
+                       if (available >= ctl->size) {
+                               _E("Memory restored: requested: %u available: %u\n",
+                                       ctl->size, available);
+                               ctl->status = LOWMEM_RECLAIM_DONE;
+                               if (ctl->callback)
+                                       ctl->callback(ctl);
+                               LOWMEM_DESTROY_REQUEST(ctl);
+                               LOWMEM_WORKER_IDLE(lmw);
+                               continue;
+                       }
 
-               ret = pthread_mutex_unlock(&oom_mutex);
-               if (ret) {
-                       _E("oom thread::pthread_mutex_unlock() failed, %d", ret);
-                       break;
+                       if (LOWMEM_WORKER_IS_ACTIVE(lmw)) {
+                               g_usleep(LMW_RETRY_WAIT_TIMEOUT_MSEC);
+                               ctl->flags |= OOM_REVISE;
+                               goto process_again;
+                       }
                }
-       }
 
-       /* Now our thread finishes - cleanup TID */
-       oom_thread = 0;
+               /*
+                * The ctl callback would check available size again.
+                * And it is last point in reclaiming worker.
+                * Resourced sent SIGKILL signal to victim processes
+                * so it should wait for a some seconds until each processes returns memory.
+                */
+               g_usleep(LMW_LOOP_WAIT_TIMEOUT_MSEC);
+               if (ctl->callback)
+                       ctl->callback(ctl);
 
-       return NULL;
+               /* The lmk becomes the owner of all queued requests .. */
+               LOWMEM_DESTROY_REQUEST(ctl);
+               LOWMEM_WORKER_IDLE(lmw);
+       }
+       g_async_queue_unref(lmw->queue);
+       pthread_exit(NULL);
 }
 
 static void change_lowmem_state(unsigned int mem_state)
 {
-       if (cur_mem_state == mem_state)
-               return;
-
-       _I("[LOW MEM STATE] %s ==> %s, changed available = %d MB",
-                       convert_memstate_to_str(cur_mem_state),
-                       convert_memstate_to_str(mem_state),
-                       proc_get_mem_available());
-
+       _I("[LOW MEM STATE] %s ==> %s", convert_memstate_to_str(cur_mem_state),
+               convert_memstate_to_str(mem_state));
        cur_mem_state = mem_state;
 
-       adjust_dynamic_threshold(MEMCG_BACKGROUND);
+       adjust_dynamic_threshold(LMK_INACTIVE);
+       resourced_notify(RESOURCED_NOTIFIER_MEM_STATE_CHANGED,
+               (void *)cur_mem_state);
 }
 
 static void lowmem_swap_memory(enum memcg_type type, struct memcg_info *mi)
 {
        unsigned int available;
        struct swap_status_msg msg;
-       static const struct module_ops *swap;
 
        if (cur_mem_state == LOWMEM_NORMAL)
                return;
 
-       if (!swap) {
-               swap = find_module("swap");
-               if (!swap)
-                       return;
-       }
+       if (swap_get_state() != SWAP_ON)
+               return;
 
        available = proc_get_mem_available();
        if (cur_mem_state != LOWMEM_SWAP &&
            available <= memcg_root->threshold[LOWMEM_SWAP])
                swap_act();
 
-       memcg_swap_status[type] = true;
        msg.type = type;
        msg.info = mi;
        resourced_notify(RESOURCED_NOTIFIER_SWAP_START, &msg);
@@ -1065,8 +1179,6 @@ static void memory_level_send_system_event(int lv)
 static void normal_act(void)
 {
        int ret, status;
-       int index;
-       struct swap_status_msg msg;
 
        ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
        if (ret)
@@ -1078,19 +1190,9 @@ static void normal_act(void)
        }
 
        change_lowmem_state(LOWMEM_NORMAL);
-       for (index = 0; index < MEMCG_MAX; ++index) {
-               if (!memcg_swap_status[index])
-                       continue;
-
-               msg.type = index;
-               msg.info = memcg_tree[index]->info;
-               resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, &msg);
-               memcg_swap_status[index] = false;
-       }
-
        if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
                resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
-                        (void *)CGROUP_FREEZER_ENABLED);
+                       (void *)CGROUP_FREEZER_ENABLED);
 }
 
 static void swap_act(void)
@@ -1109,7 +1211,7 @@ static void swap_act(void)
        change_lowmem_state(LOWMEM_SWAP);
        if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
                resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
-                        (void *)CGROUP_FREEZER_ENABLED);
+                       (void *)CGROUP_FREEZER_ENABLED);
 
        if (swap_get_state() != SWAP_ON)
                resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
@@ -1117,127 +1219,124 @@ static void swap_act(void)
 
 static void low_act(void)
 {
-       int ret, status;
-
-       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
-
-       if (ret)
-               _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
-
-       if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
-               resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
-                        (void *)CGROUP_FREEZER_PAUSED);
        change_lowmem_state(LOWMEM_LOW);
        resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_LOWMEM_LOW);
-
-       /* Since vconf for soft warning could be set during low memory check,
-        * we set it only when the current status is not soft warning.
-        */
-       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
-               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
-                             VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING);
-               memory_level_send_system_event(MEMORY_LEVEL_LOW);
-       }
+       memory_level_send_system_event(MEMORY_LEVEL_LOW);
 }
 
-static Eina_Bool medium_cb(void *data)
+static void medium_cb(struct lowmem_control *ctl)
 {
-       unsigned int available;
-       int count = 0;
-       int completed = 0;
-
-       available = proc_get_mem_available();
-       _I("available = %u, timer run until reaching leave threshold", available);
-
-       if (available >= memcg_root->threshold_leave && oom_check_timer != NULL) {
-               ecore_timer_del(oom_check_timer);
-               oom_check_timer = NULL;
-               _I("oom_check_timer deleted after reaching leave threshold");
-               normal_act();
-               fg_killed = 0;
+       if (ctl->status == LOWMEM_RECLAIM_DONE)
                oom_popup = false;
-               return ECORE_CALLBACK_CANCEL;
-       }
-
-       _I("available = %u cannot reach leave threshold %u, timer again",
-               available, memcg_root->threshold_leave);
-       count = lowmem_oom_killer_cb(MEMCG_MEMORY,
-                       memcg_root, OOM_TIMER_CHECK, &completed);
-
-       /*
-        * After running oom killer in timer, but there is no victim,
-        * stop timer.
-        */
-       if (oom_check_timer != NULL &&
-           (completed || (!count && available >= dynamic_oom_threshold))) {
-               ecore_timer_del(oom_check_timer);
-               oom_check_timer = NULL;
-               _I("timer deleted, avail:%u, thres:%u, count:%d, completed:%d",
-                       available, dynamic_oom_threshold, count, completed);
-               normal_act();
-               fg_killed = 0;
-               oom_popup = false;
-               return ECORE_CALLBACK_CANCEL;
-       }
-       return ECORE_CALLBACK_RENEW;
+       lowmem_change_memory_state(LOWMEM_NORMAL, 0);
 }
 
 static void medium_act(void)
 {
-       int ret = 0;
-
-       change_lowmem_state(LOWMEM_MEDIUM);
+       unsigned int available;
+       int ret;
+       int status = VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL;
 
-       /* signal to lowmem_oom_killer_pthread to start killer */
-       ret = pthread_mutex_trylock(&oom_mutex);
-       if (ret) {
-               _E("medium_act::pthread_mutex_trylock() failed, %d, errno: %d", ret, errno);
+       /*
+        * Don't trigger reclaim worker
+        * if it is already running
+        */
+       if (LOWMEM_WORKER_IS_RUNNING(&lmw))
                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);
+       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+       if (ret)
+               _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
        memory_level_send_system_event(MEMORY_LEVEL_CRITICAL);
+       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING) {
+               if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
+                       resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+                               (void *)CGROUP_FREEZER_PAUSED);
+               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                             VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
+       }
+       available = proc_get_mem_available();
+
+       change_lowmem_state(LOWMEM_MEDIUM);
 
-       if (oom_check_timer == NULL) {
-               _D("timer run until reaching leave threshold");
-               oom_check_timer =
-                       ecore_timer_add(OOM_TIMER_INTERVAL, medium_cb, (void *)NULL);
+       if (available < memcg_root->threshold_leave) {
+               struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
+
+               if (ctl) {
+                       LOWMEM_SET_REQUEST(ctl, OOM_IN_DEPTH,
+                               LMK_INACTIVE, memcg_root->threshold_leave,
+                               num_max_victims, medium_cb);
+                       lowmem_queue_request(&lmw, ctl);
+               }
        }
+
        resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_LOWMEM_MEDIUM);
 
        return;
 }
 
+void lowmem_trigger_memory_state_action(int mem_state)
+{
+       /*
+        * Check if the state we want to set is different from current
+        * But it should except this condition if mem_state is already medium.
+        * Otherwise, recalim worker couldn't run any more.
+        */
+       if (mem_state != LOWMEM_MEDIUM && cur_mem_state == mem_state)
+               return;
+
+       switch (mem_state) {
+       case LOWMEM_NORMAL:
+               normal_act();
+               break;
+       case LOWMEM_SWAP:
+               swap_act();
+               break;
+       case LOWMEM_LOW:
+               low_act();
+               break;
+       case LOWMEM_MEDIUM:
+               medium_act();
+               break;
+       default:
+               assert(0);
+       }
+}
+
 static void lowmem_dump_cgroup_procs(struct memcg_info *mi)
 {
        int i;
        unsigned int size;
        pid_t pid;
-       GArray *pids_array = g_array_new(false, false, sizeof(pid_t));
+       GArray *pids_array = NULL;
 
-       memcg_get_pids(mi, pids_array);
+       cgroup_get_pids(mi->name, &pids_array);
 
        for (i = 0; i < pids_array->len; i++) {
                pid = g_array_index(pids_array, pid_t, i);
-               get_proc_mem_usage(pid, &size);
+               lowmem_mem_usage_uss(pid, &size);
                _I("pid = %d, size = %u KB", pid, size);
        }
-       g_array_free(pids_array, TRUE);
+       g_array_free(pids_array, true);
 }
 
-static void memory_cgroup_medium_act(int type, struct memcg_info *mi)
+static void memory_cgroup_medium_act(enum lmk_type type, struct memcg_info *mi)
 {
+       struct lowmem_control *ctl;
+
        _I("[LOW MEM STATE] memory cgroup %s oom state",
                mi->name);
 
        /* To Do: only start to kill fg victim when no pending fg victim */
        lowmem_dump_cgroup_procs(mi);
-       lowmem_oom_killer_cb(type, mi, OOM_NONE, NULL);
+
+       ctl = LOWMEM_NEW_REQUEST();
+       if (ctl) {
+               LOWMEM_SET_REQUEST(ctl, OOM_SINGLE_SHOT | OOM_IN_DEPTH, type,
+                       mi->oomleave, num_max_victims, NULL);
+               lowmem_queue_request(&lmw, ctl);
+       }
 }
 
 static unsigned int check_mem_state(unsigned int available)
@@ -1315,18 +1414,17 @@ static int set_memory_config(const char *section_name, const struct parse_result
                lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, value);
        } else if (!strncmp(result->name, "ForegroundRatio", strlen("ForegroundRatio")+1)) {
                float ratio = atof(result->value);
-               memcg_info_set_limit(memcg_tree[MEMCG_FOREGROUND]->info, ratio, totalram);
-       } else if (!strncmp(result->name, "ForegroundUseHierarchy", strlen("ForegroundUseHierarchy")+1)) {
-               int use_hierarchy = atoi(result->value);
-               memcg_tree[MEMCG_FOREGROUND]->use_hierarchy = use_hierarchy;
-       } else if (!strncmp(result->name, "ForegroundNumCgroups", strlen("ForegroundNumCgroups")+1)) {
-               int num_cgroups = atoi(result->value);
-               if (num_cgroups > 0)
-                       memcg_add_cgroups(memcg_tree[MEMCG_FOREGROUND], num_cgroups);
-               memcg_show(memcg_tree[MEMCG_FOREGROUND]);
+               memcg_info_set_limit(memcg_tree[MEMCG_APPS]->info, ratio, totalram);
        } else if (!strncmp(result->name, "NumMaxVictims", strlen("NumMaxVictims")+1)) {
                int value = atoi(result->value);
                num_max_victims = value;
+               /*
+                * calculate number of kill victims between check memory available
+                * depends on number of max kill victims
+                */
+               num_vict_between_check = value > MAX_MEMORY_CGROUP_VICTIMS/2
+                                               ? 3 : value > MAX_MEMORY_CGROUP_VICTIMS/4
+                                                               ? 2 : 1;
        } else if (!strncmp(result->name, "ProactiveThreshold", strlen("ProactiveThreshold")+1)) {
                int value = atoi(result->value);
                proactive_threshold = value;
@@ -1336,7 +1434,13 @@ static int set_memory_config(const char *section_name, const struct parse_result
        } else if (!strncmp(result->name, "DynamicThreshold", strlen("DynamicThreshold")+1)) {
                int value = atoi(result->value);
                dynamic_threshold_min = value;
+       } else if (!strncmp(result->name, "EventLevel", strlen("EventLevel")+1)) {
+               if (strncmp(event_level, result->value, strlen(event_level)))
+                       event_level = strdup(result->value);
+               if (!event_level)
+                       return RESOURCED_ERROR_OUT_OF_MEMORY;
        }
+
        return RESOURCED_ERROR_NONE;
 }
 
@@ -1379,7 +1483,7 @@ static int memory_load_2048_config(struct parse_result *result, void *user_data)
 static void setup_memcg_params(void)
 {
        int i;
-       unsigned long total_ramsize = BtoMB(totalram);
+       unsigned long total_ramsize = BYTE_TO_MBYTE(totalram);
        _D("Total: %lu MB", total_ramsize);
        if (total_ramsize <= MEM_SIZE_64) {
                /* set thresholds for ram size 64M */
@@ -1458,7 +1562,7 @@ static void setup_memcg_params(void)
                        dynamic_threshold_min) >> 2;
        dynamic_oom_threshold = memcg_root->threshold[LOWMEM_MEDIUM];
 
-       for (i = LOWMEM_SWAP; i < LOWMEM_MAX_LEVEL; i++)
+       for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
                _I("set threshold for state '%s' to %u MB", convert_memstate_to_str(i), memcg_root->threshold[i]);
 
        _I("set number of max victims as %d", num_max_victims);
@@ -1474,35 +1578,32 @@ static void setup_memcg_params(void)
 static void init_memcg_params(void)
 {
        int idx = 0;
-       char buf[MAX_PATH_LENGTH];
+       GSList *cgroups;
+
        memcg_tree = (struct memcg **)malloc(sizeof(struct memcg *) *
                MEMCG_MAX);
        assert(memcg_tree);
 
        for (idx = 0; idx < MEMCG_MAX; idx++) {
-               struct memcg_info *mi = NULL;
+               struct memcg_info *mi = &gmi[idx];
                memcg_tree[idx] = (struct memcg *)malloc(sizeof(struct memcg));
                assert(memcg_tree[idx]);
 
                memcg_init(memcg_tree[idx]);
-               if (memcg_name[idx])
-                       snprintf(buf, MAX_PATH_LENGTH, "%s/%s", LOWMEM_DEFAULT_CGROUP,
-                                       memcg_name[idx]);
-               else
-                       snprintf(buf, MAX_PATH_LENGTH, "%s", LOWMEM_DEFAULT_CGROUP);
-               mi = (struct memcg_info *)malloc(sizeof(struct memcg_info));
-               assert(mi);
-
-               memcg_info_init(mi, buf);
                memcg_tree[idx]->info = mi;
-               _I("init memory cgroup for %s", buf);
-               if (idx == MEMCG_MEMORY)
+               _I("init memory cgroup for %s", mi->name);
+
+               if (mi->parent_memcg == MEMCG_ROOT) {
                        memcg_root = memcg_tree[idx]->info;
+               } else {
+                       cgroups = memcg_tree[mi->parent_memcg]->cgroups;
+                       cgroups = g_slist_prepend(cgroups, mi);
+                       memcg_tree[mi->parent_memcg]->use_hierarchy = true;
+               }
        }
 }
 
-static int write_params_memcg_info(struct memcg_info *mi,
-       int write_limit)
+static int write_params_memcg_info(struct memcg_info *mi)
 {
        unsigned int limit = mi->limit;
        const char *name = mi->name;
@@ -1514,12 +1615,14 @@ static int write_params_memcg_info(struct memcg_info *mi,
        if (ret)
                return ret;
 
+       if (mi->limit_ratio == LOWMEM_NO_LIMIT)
+               return ret;
+
        /*
         * for memcg with LOWMEM_NO_LIMIT or write_limit is not set,
         * do not set limit for cgroup limit.
         */
-       if (mi->limit_ratio == LOWMEM_NO_LIMIT ||
-               !write_limit)
+       if (mi->limit_ratio == LOWMEM_NO_LIMIT || !limit)
                return ret;
 
        /* disable memcg OOM-killer */
@@ -1538,74 +1641,15 @@ static int write_params_memcg_info(struct memcg_info *mi,
 static int write_memcg_params(void)
 {
        unsigned int i;
-       GSList *iter = NULL;
 
        for (i = 0; i < MEMCG_MAX; i++) {
                struct memcg_info *mi = memcg_tree[i]->info;
-               int write_limit = !memcg_tree[i]->use_hierarchy;
-               GSList *list = memcg_tree[i]->cgroups;
-               write_params_memcg_info(mi, write_limit);
-               /* write limit to the node for sub cgroups */
-               write_limit = 1;
-               /* write node for sub cgroups */
-               gslist_for_each_item(iter, list) {
-                       struct memcg_info *mi =
-                               (struct memcg_info *)(iter->data);
-                       write_params_memcg_info(mi, write_limit);
-               }
+               write_params_memcg_info(mi);
        }
 
        return RESOURCED_ERROR_NONE;
 }
 
-static struct memcg_info *find_foreground_cgroup(struct proc_app_info *pai)
-{
-       unsigned int usage;
-       unsigned int min_usage = UINT_MAX;
-       struct memcg_info *min_mi = NULL, *mi;
-       GSList *iter = NULL;
-
-       /*
-        * 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 (pai && (pai->memory.memcg_idx == MEMCG_FOREGROUND)) {
-               _D("%s is already in foreground", pai->appid);
-               return pai->memory.memcg_info;
-       }
-
-       /*
-        * if any of the process in this group is not in foreground,
-        * find foreground cgroup with minimum usage
-        */
-       if (memcg_tree[MEMCG_FOREGROUND]->use_hierarchy) {
-               gslist_for_each_item(iter,
-                       memcg_tree[MEMCG_FOREGROUND]->cgroups) {
-                       mi = (struct memcg_info *)(iter->data);
-
-                       memcg_get_usage(mi, &usage);
-                       /* select foreground memcg with no task first */
-                       if (usage == 0) {
-                               _D("%s' usage is 0, selected", mi->name);
-                                       return mi;
-                       }
-
-                       /* select forground memcg with minimum usage */
-                       if (usage > 0 && min_usage > usage) {
-                               min_usage = usage;
-                               min_mi = mi;
-                       }
-               }
-               _D("%s is selected at min usage = %u",
-                       min_mi->name, min_usage);
-
-       } else {
-               return memcg_tree[MEMCG_FOREGROUND]->info;
-       }
-
-       return min_mi;
-}
-
 static void lowmem_move_memcgroup(int pid, int oom_score_adj)
 {
        struct proc_app_info *pai = find_app_info(pid);
@@ -1615,43 +1659,17 @@ static void lowmem_move_memcgroup(int pid, int oom_score_adj)
        if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED + OOMADJ_APP_INCREASE) {
                if (pai && (oom_score_adj != pai->memory.oom_score_adj))
                        proc_set_process_memory_state(pai, pai->memory.memcg_idx,
-                                       pai->memory.memcg_info, oom_score_adj);
+                       pai->memory.memcg_info, oom_score_adj);
                return;
-       } else if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
-               memcg_idx = MEMCG_BACKGROUND;
-               mi = memcg_tree[memcg_idx]->info;
-               should_swap = 1;
-       } else if (oom_score_adj >= OOMADJ_PREVIOUS_BACKGRD) {
-               memcg_idx = MEMCG_PREVIOUS;
-               mi = memcg_tree[memcg_idx]->info;
-       } else if (oom_score_adj >= OOMADJ_FAVORITE) {
-               memcg_idx = MEMCG_FAVORITE;
-               mi = memcg_tree[memcg_idx]->info;
-               should_swap = 1;
-       } else if (oom_score_adj == OOMADJ_SERVICE_DEFAULT) {
-               memcg_idx = MEMCG_PREVIOUS;
+       } else if (oom_score_adj >= OOMADJ_INIT) {
+               memcg_idx = MEMCG_APPS;
                mi = memcg_tree[memcg_idx]->info;
-       } else if (oom_score_adj >= OOMADJ_BACKGRD_PERCEPTIBLE) {
-               memcg_idx = MEMCG_PREVIOUS;
-               mi = memcg_tree[memcg_idx]->info;
-       } else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED ||
-                   oom_score_adj == OOMADJ_INIT) {
-               /*
-                * When resume occurs, to prevent resuming process
-                * from being killed, raise its oom score to OOMADJ_INIT.
-                * However, it could be still in the background group, and
-                * selected as a victim. So, we move it to foreground group
-                * in advanve.
-                */
-               memcg_idx = MEMCG_FOREGROUND;
-               mi = find_foreground_cgroup(pai);
-       } else {
+
+               if (oom_score_adj >= OOMADJ_FAVORITE)
+                       should_swap = 1;
+       } else
                return;
-       }
 
-       _D("pid: %d, proc_name: %s, cg_name: %s, oom_score_adj: %d", pid,
-                       pai ? pai->appid : "---", memcg_name[memcg_idx],
-                       oom_score_adj);
        cgroup_write_node_uint32(mi->name, CGROUP_FILE_NAME, pid);
        proc_set_process_memory_state(pai, memcg_idx, mi, oom_score_adj);
 
@@ -1664,54 +1682,65 @@ static void lowmem_move_memcgroup(int pid, int oom_score_adj)
 
 }
 
-static int oom_thread_create(void)
+static int lowmem_activate_worker(void)
 {
        int ret = RESOURCED_ERROR_NONE;
 
-       if (oom_thread) {
-               _I("oom thread %u already created", (unsigned)oom_thread);
-       } else {
-               /* initialize oom killer thread */
-               ret = pthread_create(&oom_thread, NULL, (void *)lowmem_oom_killer_pthread, (void *)NULL);
-               if (ret) {
-                       _E("pthread creation for lowmem_oom_killer_pthread failed, %d\n", ret);
-                       oom_thread = 0;
-               } else {
-                       pthread_detach(oom_thread);
-               }
+       if (LOWMEM_WORKER_IS_ACTIVE(&lmw)) {
+               _I("LMK worker thread [%d] has already been created\n",
+                       (unsigned)lmw.worker_thread);
+               return ret;
        }
 
+       lmw.queue = g_async_queue_new_full(lowmem_request_destroy);
+       if (!lmw.queue) {
+               _E("Failed to create request queue\n");
+               return RESOURCED_ERROR_FAIL;
+       }
+       LOWMEM_WORKER_ACTIVATE(&lmw);
+       ret = pthread_create(&lmw.worker_thread, NULL,
+               (void *)lowmem_reclaim_worker, (void *)&lmw);
+       if (ret) {
+               LOWMEM_WORKER_DEACTIVATE(&lmw);
+               _E("Failed to create LMK thread: %d\n", ret);
+       } else {
+               pthread_detach(lmw.worker_thread);
+               ret = RESOURCED_ERROR_NONE;
+       }
        return ret;
 }
 
+static void lowmem_deactivate_worker(void)
+{
+       struct lowmem_control *ctl;
+
+       if (!LOWMEM_WORKER_IS_ACTIVE(&lmw))
+               return;
+
+       LOWMEM_WORKER_DEACTIVATE(&lmw);
+       lowmem_drain_queue(&lmw);
+
+       ctl = LOWMEM_NEW_REQUEST();
+       ctl->flags = OOM_DROP;
+       g_async_queue_push(lmw.queue, ctl);
+       g_async_queue_unref(lmw.queue);
+}
+
 static int create_memcgs(void)
 {
        int i = 0;
        int ret = RESOURCED_ERROR_NONE;
-       GSList *iter = NULL;
        struct memcg_info *mi;
        char *name;
-       char parent_dir[MAX_PATH_LENGTH];
 
        /* skip for memory cgroup */
        for (i = 0; i < MEMCG_MAX; i++) {
-               if (!memcg_name[i])
+               if (memcg_root == memcg_tree[i]->info)
                        continue;
                mi = memcg_tree[i]->info;
-               name = mi->name;
-               ret = cgroup_make_subdir(LOWMEM_DEFAULT_CGROUP, memcg_name[i], NULL);
-               _D("Create subcgroup of memory : name = %s, ret = %d", memcg_name[i], ret);
-               if (!memcg_tree[i]->use_hierarchy)
-                       continue;
-               /* create sub cgroups */
-               gslist_for_each_item(iter, memcg_tree[i]->cgroups) {
-                       mi = (struct memcg_info *)iter->data;
-                       name = strstr(mi->name, memcg_name[i]) + strlen(memcg_name[i]) + 1;
-                       snprintf(parent_dir, MAX_PATH_LENGTH,
-                                       "%s/%s", LOWMEM_DEFAULT_CGROUP, memcg_name[i]);
-                       ret = cgroup_make_subdir(parent_dir, name, NULL);
-                       _D("Create subcgroup of memory/%s : name = %s, ret = %d", memcg_name[i], name, ret);
-               }
+               name = mi->hashname;
+               ret = cgroup_make_subdir(LOWMEM_ROOT_CGROUP, name, NULL);
+               _D("create memory cgroup for %s, ret = %d", name, ret);
        }
 
        return ret;
@@ -1730,29 +1759,21 @@ static void lowmem_press_root_cgroup_handler(void)
 {
        static unsigned int prev_available;
        unsigned int available;
-       int i, mem_state;
+       int mem_state;
 
        available = proc_get_mem_available();
        if (prev_available == available)
                return;
 
        mem_state = check_mem_state(available);
-       for (i = 0; i < ARRAY_SIZE(lpe); i++) {
-               if ((cur_mem_state == lpe[i].cur_mem_state)
-                               && (mem_state == lpe[i].new_mem_state)) {
-                       _D("cur_mem_state = %s, new_mem_state = %s, available = %d",
-                                       convert_memstate_to_str(cur_mem_state),
-                                       convert_memstate_to_str(mem_state),
-                                       available);
-                       lpe[i].action();
-               }
-       }
+       lowmem_trigger_memory_state_action(mem_state);
+
        prev_available = available;
 }
 
-static void lowmem_press_cgroup_handler(int type, struct memcg_info *mi)
+static void lowmem_press_cgroup_handler(enum lmk_type type, struct memcg_info *mi)
 {
-       unsigned long long usage, threshold;
+       unsigned int usage, threshold;
        int ret;
 
        ret = memcg_get_anon_usage(mi, &usage);
@@ -1761,12 +1782,12 @@ static void lowmem_press_cgroup_handler(int type, struct memcg_info *mi)
                return;
        }
 
-       threshold = (unsigned long long)(mi->threshold[LOWMEM_MEDIUM]);
+       threshold = mi->threshold[LOWMEM_MEDIUM];
        if (usage >= threshold)
                memory_cgroup_medium_act(type, mi);
        else
-               _I("anon page %llu MB < medium threshold %llu MB", BtoMB(usage),
-                               BtoMB(threshold));
+               _I("anon page %u MB < medium threshold %u MB", BYTE_TO_MBYTE(usage),
+                               BYTE_TO_MBYTE(threshold));
 }
 
 static Eina_Bool lowmem_press_eventfd_handler(void *data,
@@ -1775,6 +1796,7 @@ static Eina_Bool lowmem_press_eventfd_handler(void *data,
        int fd, i;
        struct memcg_info *mi;
        GSList *iter = NULL;
+       enum lmk_type lmk_type = LMK_MEMORY;
 
        if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
                _E("ecore_main_fd_handler_active_get error , return\n");
@@ -1796,8 +1818,13 @@ static Eina_Bool lowmem_press_eventfd_handler(void *data,
                        /* call low memory handler for this memcg */
                        if (i == MEMCG_MEMORY)
                                lowmem_press_root_cgroup_handler();
-                       else
-                               lowmem_press_cgroup_handler(i, mi);
+                       else {
+                               if (i == MEMCG_APPS)
+                                       lmk_type = LMK_ACTIVE;
+                               else if (i == MEMCG_SWAP)
+                                       lmk_type = LMK_INACTIVE;
+                               lowmem_press_cgroup_handler(lmk_type, mi);
+                       }
                        return ECORE_CALLBACK_RENEW;
                }
                /* ToDo: iterate child memcgs */
@@ -1805,7 +1832,11 @@ static Eina_Bool lowmem_press_eventfd_handler(void *data,
                {
                        mi = (struct memcg_info *)(iter->data);
                        if (fd == mi->evfd) {
-                               lowmem_press_cgroup_handler(i, mi);
+                               if (i == MEMCG_APPS)
+                                       lmk_type = LMK_ACTIVE;
+                               else if (i == MEMCG_SWAP)
+                                       lmk_type = LMK_INACTIVE;
+                               lowmem_press_cgroup_handler(lmk_type, mi);
                                _D("lowmem cgroup handler is called for %s",
                                                mi->name);
                                return ECORE_CALLBACK_RENEW;
@@ -1816,90 +1847,177 @@ static Eina_Bool lowmem_press_eventfd_handler(void *data,
        return ECORE_CALLBACK_RENEW;
 }
 
-/*
-From memory.txt kernel document -
-To register a notifier, application need:
-- create an eventfd using eventfd(2)
-- open memory.oom_control file
-- write string like "<event_fd> <fd of memory.oom_control>"
-to cgroup.event_control
-*/
 static void lowmem_press_register_eventfd(struct memcg_info *mi)
 {
-       int cgfd, pressurefd, evfd, res, sz;
-       char buf[BUF_MAX] = {0, };
+       int evfd;
        const char *name = mi->name;
 
        if (mi->threshold[LOWMEM_MEDIUM] == LOWMEM_THRES_INIT)
                return;
 
-       snprintf(buf, sizeof(buf), "%s/%s", name, MEMCG_EVENTFD_CONTROL);
-       cgfd = open(buf, O_WRONLY);
-       if (cgfd < 0) {
-               _E("open event_control failed");
-               return;
-       }
-
-       snprintf(buf, sizeof(buf), "%s/%s", name, MEMCG_EVENTFD_MEMORY_PRESSURE);
-       pressurefd = open(buf, O_RDONLY);
-       if (pressurefd < 0) {
-               _E("open pressure control failed");
-               close(cgfd);
-               return;
-       }
+       evfd = memcg_set_eventfd(name, MEMCG_EVENTFD_MEMORY_PRESSURE,
+                       event_level);
 
-       /* create an eventfd using eventfd(2)
-        use same event fd for using ecore event loop */
-       evfd = eventfd(0, O_NONBLOCK);
        if (evfd < 0) {
-               _E("eventfd() error");
-               close(cgfd);
-               close(pressurefd);
+               _I("fail to register event press fd %s cgroup", name);
                return;
        }
-       mi->evfd = evfd;
 
-       /* pressure level*/
-       /* write event fd low level */
-       sz = snprintf(buf, sizeof(buf), "%d %d %s", evfd, pressurefd, mi->event_level);
-       sz += 1;
-       res = write(cgfd, buf, sz);
-       if (res != sz) {
-               _E("write cgfd failed : %d for %s", res, name);
-               close(cgfd);
-               close(pressurefd);
-               close(evfd);
-               mi->evfd = -1;
-               return;
-       }
+       mi->evfd = evfd;
 
        _I("register event fd success for %s cgroup", name);
        ecore_main_fd_handler_add(evfd, ECORE_FD_READ,
                        (Ecore_Fd_Cb)lowmem_press_eventfd_handler, NULL, NULL,
                        NULL);
-
-       close(cgfd);
-       close(pressurefd);
        return;
 }
 
 static int lowmem_press_setup_eventfd(void)
 {
        unsigned int i;
-       struct memcg_info *mi;
-       GSList *iter = NULL;
 
        for (i = 0; i < MEMCG_MAX; i++) {
-               if (!memcg_tree[i]->use_hierarchy) {
-                       lowmem_press_register_eventfd(memcg_tree[i]->info);
-               } else {
-                       GSList *list = memcg_tree[i]->cgroups;
-                       gslist_for_each_item(iter, list)
-                       {
-                               mi = (struct memcg_info *)(iter->data);
-                               lowmem_press_register_eventfd(mi);
-                       }
+               if (!memcg_tree[i]->use_hierarchy)
+                       continue;
+
+               lowmem_press_register_eventfd(memcg_tree[i]->info);
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+int lowmem_trigger_reclaim(int flags)
+{
+       struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
+
+       if (!ctl)
+               return RESOURCED_ERROR_OUT_OF_MEMORY;
+
+       LOWMEM_SET_REQUEST(ctl, flags | OOM_IN_DEPTH | OOM_SINGLE_SHOT,
+               MEMCG_MAX -1, memcg_root->threshold_leave, MAX_FD_VICTIMS, NULL);
+       lowmem_queue_request(&lmw, ctl);
+       return RESOURCED_ERROR_NONE;
+}
+
+static void lowmem_force_reclaim_cb(struct lowmem_control *ctl)
+{
+       lowmem_change_memory_state(LOWMEM_NORMAL, 0);
+}
+
+static void lowmem_trigger_force_reclaim(unsigned int size)
+{
+       struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
+
+       lowmem_change_memory_state(LOWMEM_LOW, 1);
+       if (ctl) {
+               LOWMEM_SET_REQUEST(ctl, OOM_FORCE | OOM_SINGLE_SHOT,
+                       LMK_INACTIVE, size, num_max_victims,
+                       lowmem_force_reclaim_cb);
+
+               lowmem_queue_request(&lmw, ctl);
+       }
+}
+
+static void lowmem_proactive_oom_killer(int flags, char *appid)
+{
+       unsigned int before;
+
+       before = proc_get_mem_available();
+
+       /* If low memory state, just return and kill in oom killer */
+       if (before < memcg_root->threshold[LOWMEM_MEDIUM])
+               return;
+
+#ifdef HEART_SUPPORT
+       struct heart_memory_data *md = NULL;
+
+       /* Get HEART-memory data only if this module is enabled */
+       if (find_module("MEMORY") != NULL)
+               md = heart_memory_get_data(appid, DATA_6HOUR);
+
+       if (md) {
+               unsigned int uss;
+
+               uss = KBYTE_TO_MBYTE(md->avg_uss);
+
+               free(md);
+
+               /*
+                * if launching app is predicted to consume all memory,
+                * free memory up to leave threshold after launching the app.
+                */
+               if (before <= uss) {
+                       _D("run history based proactive killer, (before), required level = %u MB",
+                                               memcg_root->threshold_leave + uss);
+                       lowmem_trigger_force_reclaim(memcg_root->threshold_leave + uss);
+                       return;
                }
+
+               unsigned int after = before - uss;
+               _D("available after launch = %u MB, available = %u MB, uss = %u MB",
+                       after, before, uss);
+
+               /*
+                * after launching app, ensure that available memory is
+                * above threshold_leave
+                */
+               if (after >= memcg_root->threshold[LOWMEM_MEDIUM])
+                       return;
+
+               _D("run history based proactive killer (after), required level = %u MB",
+                       memcg_root->threshold_leave + THRESHOLD_MARGIN);
+               lowmem_trigger_force_reclaim(memcg_root->threshold_leave + THRESHOLD_MARGIN);
+
+               return;
+       }
+#endif
+
+       /*
+        * When there is no history data for the launching app but it is
+        * indicated as PROC_LARGEMEMORY, run oom killer based on dynamic
+        * threshold.
+        */
+       if (!(flags & PROC_LARGEMEMORY))
+               return;
+       /*
+        * run proactive oom killer only when available is larger than
+        * dynamic process threshold
+        */
+       if (!proactive_threshold || before >= proactive_threshold)
+               return;
+
+       /*
+        * free THRESHOLD_MARGIN more than real should be freed,
+        * because launching app is consuming up the memory.
+        */
+       _D("Run threshold based proactive LMK: memory level to reach: %u\n",
+               proactive_leave + THRESHOLD_MARGIN);
+       lowmem_trigger_force_reclaim(proactive_leave + THRESHOLD_MARGIN);
+       return;
+}
+
+static int lowmem_prelaunch_handler(void *data)
+{
+       struct proc_status *ps = (struct proc_status *)data;
+
+       if (!ps->pai)
+               return RESOURCED_ERROR_NO_DATA;
+
+       lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int lowmem_control_handler(void *data)
+{
+       struct lowmem_control_data *lowmem_data;
+
+       lowmem_data = (struct lowmem_control_data *)data;
+       switch (lowmem_data->control_type) {
+       case LOWMEM_MOVE_CGROUP:
+               lowmem_move_memcgroup((pid_t)lowmem_data->args[0],
+                                       (int)lowmem_data->args[1]);
+               break;
+       default:
+               break;
        }
        return RESOURCED_ERROR_NONE;
 }
@@ -1975,7 +2093,6 @@ int lowmem_init(void)
 
        init_memcg_params();
        setup_memcg_params();
-
        if (allocate_vip_app_list() != RESOURCED_ERROR_NONE)
                _E("allocate_vip_app_list FAIL");
 
@@ -1987,15 +2104,14 @@ int lowmem_init(void)
 
        /* vip_list is only needed at the set_vip_list */
        free_vip_app_list();
-
        config_parse(MEM_CONF_FILE, load_mem_config, NULL);
 
        create_memcgs();
        write_memcg_params();
 
-       ret = oom_thread_create();
+       ret = lowmem_activate_worker();
        if (ret) {
-               _E("oom thread create failed");
+               _E("oom thread create failed\n");
                return ret;
        }
 
@@ -2008,6 +2124,9 @@ int lowmem_init(void)
 
        lowmem_dbus_init();
 
+       register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
+       register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
+
        return ret;
 }
 
@@ -2016,9 +2135,14 @@ static int lowmem_exit(void)
        int i;
        for (i = 0; i < MEMCG_MAX; i++) {
                g_slist_free_full(memcg_tree[i]->cgroups, free);
-               free(memcg_tree[i]->info);
                free(memcg_tree[i]);
        }
+       if (event_level != (char*)MEMCG_DEFAULT_EVENT_LEVEL)
+               free(event_level);
+
+       lowmem_deactivate_worker();
+       unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
+       unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
        return RESOURCED_ERROR_NONE;
 }
 
@@ -2033,117 +2157,6 @@ static int resourced_memory_finalize(void *data)
        return lowmem_exit();
 }
 
-static int resourced_memory_control(void *data)
-{
-       struct lowmem_data_type *l_data;
-
-       l_data = (struct lowmem_data_type *)data;
-       switch (l_data->control_type) {
-       case LOWMEM_MOVE_CGROUP:
-               lowmem_move_memcgroup((pid_t)l_data->args[0],
-                                       (int)l_data->args[1]);
-               break;
-       default:
-               break;
-       }
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_memory_oom_killer(int flags)
-{
-       if (flags & OOM_FORCE)
-               return lowmem_force_oom_killer(flags, 0, MAX_FD_VICTIMS);
-       return lowmem_oom_killer_cb(MEMCG_MEMORY, memcg_root, flags, NULL);
-}
-
-int lowmem_proactive_oom_killer(int flags, char *appid)
-{
-       int count = 0;
-       unsigned int should_be_freed;
-       unsigned int before;
-#ifdef HEART_SUPPORT
-       struct heart_memory_data *md;
-#endif
-
-       before = proc_get_mem_available();
-
-       /* If low memory state, just return and kill in oom killer */
-       if (before < memcg_root->threshold[LOWMEM_MEDIUM])
-               return RESOURCED_ERROR_FAIL;
-
-#ifdef HEART_SUPPORT
-
-       /* Get HEART-memory data only if this module is enabled */
-       md = NULL;
-       if (find_module("MEMORY") != NULL)
-               md = heart_memory_get_data(appid, DATA_6HOUR);
-
-       if (md) {
-               unsigned int uss;
-
-               uss = KBtoMB(md->avg_uss);
-
-               free(md);
-
-               /*
-                * if launching app is predicted to consume all memory,
-                * free memory up to leave threshold after launching the app.
-                */
-               if (before <= uss) {
-                       should_be_freed = memcg_root->threshold_leave + uss;
-                       lowmem_force_oom_killer(OOM_FORCE, should_be_freed, num_max_victims);
-                       return RESOURCED_ERROR_NONE;
-               }
-
-               unsigned int after = before - uss;
-               _D("available after launch = %u MB, available = %u MB, uss = %u MB",
-                       after, before, uss);
-
-               /*
-                * after launching app, ensure that available memory is
-                * above threshold_leave
-                */
-                if (after >= memcg_root->threshold[LOWMEM_MEDIUM])
-                        return RESOURCED_ERROR_FAIL;
-
-                should_be_freed = memcg_root->threshold_leave +
-                        THRESHOLD_MARGIN - after;
-                _D("run history based proactive killer, should_be_freed = %u MB",
-                        should_be_freed);
-               lowmem_force_oom_killer(OOM_FORCE, should_be_freed, num_max_victims);
-
-               return RESOURCED_ERROR_NONE;
-       }
-#endif
-
-       /*
-        * When there is no history data for the launching app but it is
-        * indicated as PROC_LARGEMEMORY, run oom killer based on dynamic
-        * threshold.
-        */
-       if (!(flags & PROC_LARGEMEMORY))
-               return RESOURCED_ERROR_FAIL;
-       /*
-        * run proactive oom killer only when available is larger than
-        * dynamic process threshold
-        */
-       if (!proactive_threshold || before >= proactive_threshold)
-               return RESOURCED_ERROR_FAIL;
-
-       /*
-        * free THRESHOLD_MARGIN more than real should be freed,
-        * because launching app is consuming up the memory.
-        */
-       should_be_freed = proactive_leave - before + THRESHOLD_MARGIN;
-       _D("run threshold based proactive killer, should_be_freed = %u MB",
-                       should_be_freed);
-
-       count = lowmem_force_oom_killer(OOM_FORCE, should_be_freed, num_max_victims);
-       _D("kill %d victim total", count);
-
-       return RESOURCED_ERROR_NONE;
-}
-
 void lowmem_change_memory_state(int state, int force)
 {
        int mem_state;
@@ -2153,26 +2166,9 @@ void lowmem_change_memory_state(int state, int force)
        } else {
                unsigned int available = proc_get_mem_available();
                mem_state = check_mem_state(available);
-               _D("available = %u, mem_state = %s", available,
-                               convert_memstate_to_str(mem_state));
        }
 
-       switch (mem_state) {
-       case LOWMEM_NORMAL:
-               normal_act();
-               break;
-       case LOWMEM_SWAP:
-               swap_act();
-               break;
-       case LOWMEM_LOW:
-               low_act();
-               break;
-       case LOWMEM_MEDIUM:
-               medium_act();
-               break;
-       default:
-               assert(0);
-       }
+       lowmem_trigger_memory_state_action(mem_state);
 }
 
 void lowmem_memcg_set_threshold(int type, int level, int value)
@@ -2201,12 +2197,31 @@ int lowmem_get_memcg(enum memcg_type type, struct memcg **memcg_ptr)
        return RESOURCED_ERROR_NONE;
 }
 
-static struct module_ops memory_modules_ops = {
+void lowmem_restore_memcg(struct proc_app_info *pai)
+{
+       char *cgpath;
+       int index, ret;
+       struct memcg_info *mi;
+       pid_t pid = pai->main_pid;
+
+       ret = cgroup_pid_get_path("memory", pid, &cgpath);
+       if (ret < 0)
+               return;
+
+       for (index = MEMCG_MAX-1; index >= MEMCG_MEMORY; index--) {
+               mi = &gmi[index];
+               if (strstr(cgpath, mi->hashname))
+                       break;
+       }
+       pai->memory.memcg_idx = index;
+       pai->memory.memcg_info = mi;
+}
+
+static const struct module_ops memory_modules_ops = {
        .priority       = MODULE_PRIORITY_HIGH,
        .name           = "lowmem",
        .init           = resourced_memory_init,
        .exit           = resourced_memory_finalize,
-       .control        = resourced_memory_control,
 };
 
 MODULE_REGISTER(&memory_modules_ops)
index a5bc6fac54951de9a3940c55313962eba09df0f0..351ae921b11bcf25cd7f1094213e2dac03c99d8c 100644 (file)
@@ -1225,6 +1225,7 @@ static int proc_restore_runtime_app_info(const char *path)
                return ret;
 
        pai->program = proc_add_program_list(pai->type, pai, pkgname, true);
+       lowmem_restore_memcg(pai);
 
        (void) proc_app_list_add_app_info(pai);
 
index 005818ecc03effd3b872898515c5088ba36cfb71..57ca9df194422d783b5fead8af07e7ee9e1c6e93 100755 (executable)
@@ -595,7 +595,6 @@ static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
        pai = proc_add_app_info(appid, pkgid, 0, flags, categories, PROC_TYPE_READY, PROC_STATE_DEFAULT);
        ps.pai = pai;
        resourced_notify(RESOURCED_NOTIFIER_APP_PRELAUNCH, &ps);
-       lowmem_proactive_oom_killer(flags, appid);
 }
 
 static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)