static GHashTable *memory_limit_hash;
static char *registerpath;
-static unsigned int mem_service_limit;
-static unsigned int mem_widget_limit;
-static unsigned int mem_guiapp_limit;
-static unsigned int mem_bgapp_limit;
+static unsigned long long mem_service_limit_bytes;
+static unsigned long long mem_widget_limit_bytes;
+static unsigned long long mem_guiapp_limit_bytes;
+static unsigned long long mem_bgapp_limit_bytes;
static int mem_service_action = PROC_ACTION_IGNORE;
static int mem_widget_action = PROC_ACTION_IGNORE;
if (mle->pids_array == NULL) {
_E("[MEMORY-LIMIT] pids array should not be NULL");
- goto mle_timer_init;
+ goto timer_out;
}
for (int i = 0; i < mle->pids_array->len; i++) {
g_array_free(mle->pids_array, true);
-mle_timer_init:
mle->pids_array = NULL;
timer_out:
return G_SOURCE_REMOVE;
int result;
pid_t pid;
GArray *pids_array = NULL;
- uint32_t usage;
- uint64_t dummy_efd;
+ unsigned long long usage_bytes;
+ unsigned long long dummy_efd;
char *cg_dir = (char *)data;
struct memory_limit_event *mle;
goto remove_mle;
}
- result = cgroup_read_node_uint32(cg_dir, MEMCG_SWAP_USAGE, &usage);
+ result = cgroup_read_node_ulonglong(cg_dir, MEMCG_SWAP_USAGE, &usage_bytes);
if (result < 0) {
- result = cgroup_read_node_uint32(cg_dir, MEMCG_USAGE, &usage);
+ result = cgroup_read_node_ulonglong(cg_dir, MEMCG_USAGE, &usage_bytes);
if (result < 0) {
_D("[MEMORY-LIMIT] there is no (%s) cgroup any longer, removed it", cg_dir);
goto remove_mle;
}
}
- if (usage < mle->threshold) {
- _D("[MEMORY-LIMIT] (%s) cgroup escaped low memory status. usage(%d), threshold(%d)",
- cg_dir, usage, mle->threshold);
+ if (usage_bytes < mle->threshold_bytes) {
+ _D("[MEMORY-LIMIT] (%s) cgroup escaped low memory status. usage(%llu) bytes, threshold(%llu) bytes",
+ cg_dir, usage_bytes, mle->threshold_bytes);
return true;
}
}
int lowmem_reassign_limit(const char *dir,
- unsigned int limit, enum proc_action action)
+ unsigned long long limit_bytes, enum proc_action action)
{
int fd;
fd_handler_h fdh = NULL;
gpointer hash_entry;
struct memory_limit_event *mle = NULL;
char buf[MAX_DEC_SIZE(int)] = {0};
+ unsigned long long max_limit_bytes;
if (memory_limit_hash) {
/* TO DO: currently concurrent processes with same app name are located
hash_entry = g_hash_table_lookup(memory_limit_hash, dir);
if (hash_entry) {
mle = (struct memory_limit_event *)hash_entry;
- if (mle->threshold == limit) {
+ if (mle->threshold_bytes == limit_bytes) {
return RESOURCED_ERROR_NONE;
}
}
}
}
- check_oom_and_set_limit(dir, limit * 1.2);
- snprintf(buf, sizeof(buf), "%d", limit);
+ if (limit_bytes > lowmem_get_totalram()) {
+ max_limit_bytes = lowmem_get_totalram();
+ limit_bytes = lowmem_get_totalram();
+ }
+ else if (limit_bytes * 1.2 > lowmem_get_totalram()) {
+ max_limit_bytes = lowmem_get_totalram();
+ }
+ else
+ max_limit_bytes = limit_bytes * 1.2;
+
+ check_oom_and_set_limit(dir, max_limit_bytes);
+
+ snprintf(buf, sizeof(buf), "%llu", limit_bytes);
if (mle) {
- mle->threshold = limit;
+ mle->threshold_bytes = limit_bytes;
memcg_init_eventfd(mle->fd, dir, registerpath, buf);
return RESOURCED_ERROR_NONE;
}
return RESOURCED_ERROR_OUT_OF_MEMORY;
}
mle->action = action;
- mle->threshold = limit;
+ mle->threshold_bytes = limit_bytes;
mle->pids_array = NULL;
add_fd_read_handler(fd, memory_action_cb, mle->path, NULL, &fdh);
mle->fdh = fdh;
return RESOURCED_ERROR_NONE;
}
-void lowmem_limit_set_system_service(pid_t pid, unsigned int limit,
+int lowmem_limit_set_system_service(pid_t pid, unsigned long long limit_bytes,
const char *name, enum proc_action action)
{
_cleanup_free_ char *path = NULL;
int result;
- unsigned int totalram = lowmem_get_totalram();
+ unsigned long long totalram_bytes = lowmem_get_totalram();
- if (limit < MIN_LIMIT_VALUE || limit > totalram) {
- _E("[MEMORY-LIMIT] It's meaningless to set memory limit with size (%d)", limit);
- return;
+ if (limit_bytes < MIN_LIMIT_VALUE || limit_bytes > totalram_bytes) {
+ _E("[MEMORY-LIMIT] It's meaningless to set memory limit with size (%llu) bytes", limit_bytes);
+ return RESOURCED_ERROR_INVALID_PARAMETER;
}
if (action == PROC_ACTION_IGNORE)
- return;
+ return RESOURCED_ERROR_NONE;
if (!name) {
_E("[MEMORY-LIMIT] service name is NULL");
- return;
+ return RESOURCED_ERROR_FAIL;
}
result = asprintf(&path, "%s/%s", MEMCG_HIGH_PP_PATH, name);
if (result < 0) {
_E("[MEMORY-LIMIT] not enough memory");
- return;
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
}
result = cgroup_make_subdir(MEMCG_HIGH_PP_PATH, name, NULL);
if (result < 0) {
_E("[MEMORY-LIMIT] Failed to create cgroup subdir '%s/%s'",
MEMCG_HIGH_PP_PATH, name);
- return;
+ return result;
}
- result = lowmem_reassign_limit(path, limit, action);
+ result = lowmem_reassign_limit(path, limit_bytes, action);
if (result < 0) {
_W("[MEMORY-LIMIT] Failed to reassign limit for %s", path);
- return;
+ return result;
}
result = cgroup_write_node_uint32(path, MEMCG_MOVE_CHARGE, 3U);
- if (result < 0)
+ if (result < 0) {
_W("[MEMORY-LIMIT] Failed to set immigrate mode for %s (non-crucial, continuing)", path);
+ return result;
+ }
cgroup_write_pid_fullpath(path, pid);
+
+ return RESOURCED_ERROR_NONE;
}
-int lowmem_limit_set_app(unsigned int limit, struct proc_app_info *pai,
+int lowmem_limit_set_app(unsigned long long limit_bytes, struct proc_app_info *pai,
enum proc_action action)
{
_cleanup_free_ char *path = NULL;
GSList *iter = NULL;
int result;
- unsigned int totalram = lowmem_get_totalram();
+ unsigned long long totalram_bytes = lowmem_get_totalram();
- if (limit < MIN_LIMIT_VALUE || limit > totalram) {
- _E("[MEMORY-LIMIT] It's meaningless to set memory limit with size (%d)", limit);
+ if (limit_bytes < MIN_LIMIT_VALUE || limit_bytes > totalram_bytes) {
+ _E("[MEMORY-LIMIT] It's meaningless to set memory limit with size (%llu) bytes", limit_bytes);
return RESOURCED_ERROR_INVALID_PARAMETER;
}
+ if (action == PROC_ACTION_IGNORE)
+ return RESOURCED_ERROR_NONE;
+
if (!pai) {
_E("[MEMORY-LIMIT] process app information is NULL");
return RESOURCED_ERROR_INVALID_PARAMETER;
return result;
}
- result = lowmem_reassign_limit(path, limit, action);
+ result = lowmem_reassign_limit(path, limit_bytes, action);
if (result < 0) {
_W("[MEMORY-LIMIT] Failed to reassign limit for %s", path);
return result;
struct proc_limit_status *pls = (struct proc_limit_status *)data;
- error = lowmem_limit_set_app(pls->limit, pls->ps.pai, pls->action);
+ error = lowmem_limit_set_app(pls->limit_bytes, pls->ps.pai, pls->action);
if (!error)
pls->ps.pai->memory.memlimit_update_exclude = true;
- return RESOURCED_ERROR_NONE;
+
+ return error;
}
static int lowmem_limit_system_service(void *data)
{
+ int error;
+
assert(data);
struct proc_limit_status *pls = (struct proc_limit_status *)data;
- lowmem_limit_set_system_service(pls->ps.pid, pls->limit, pls->ps.pci->name, pls->action);
- return RESOURCED_ERROR_NONE;
+ error = lowmem_limit_set_system_service(pls->ps.pid, pls->limit_bytes,
+ pls->ps.pci->name, pls->action);
+
+ return error;
}
static int lowmem_limit_service(void *data)
if (ps->pai && ps->pai->memory.memlimit_update_exclude)
return RESOURCED_ERROR_NONE;
- if (mem_service_limit && mem_service_action != PROC_ACTION_IGNORE) {
- lowmem_limit_set_app(mem_service_limit, ps->pai, mem_service_action);
+ if (mem_service_limit_bytes && mem_service_action != PROC_ACTION_IGNORE) {
+ lowmem_limit_set_app(mem_service_limit_bytes, ps->pai, mem_service_action);
}
return RESOURCED_ERROR_NONE;
}
if (ps->pai && ps->pai->memory.memlimit_update_exclude)
return RESOURCED_ERROR_NONE;
- if (mem_guiapp_limit && mem_guiapp_action != PROC_ACTION_IGNORE &&
+ if (mem_guiapp_limit_bytes && mem_guiapp_action != PROC_ACTION_IGNORE &&
ps->pai->type == PROC_TYPE_GUI) {
- lowmem_limit_set_app(mem_guiapp_limit, ps->pai, mem_guiapp_action);
+ lowmem_limit_set_app(mem_guiapp_limit_bytes, ps->pai, mem_guiapp_action);
}
- if (mem_widget_limit && mem_widget_action != PROC_ACTION_IGNORE &&
+ if (mem_widget_limit_bytes && mem_widget_action != PROC_ACTION_IGNORE &&
ps->pai->type == PROC_TYPE_WIDGET) {
- lowmem_limit_set_app(mem_widget_limit, ps->pai, mem_widget_action);
+ lowmem_limit_set_app(mem_widget_limit_bytes, ps->pai, mem_widget_action);
}
return RESOURCED_ERROR_NONE;
if (ps->pai && ps->pai->memory.memlimit_update_exclude)
return RESOURCED_ERROR_NONE;
- lowmem_limit_set_app(mem_bgapp_limit, ps->pai, mem_bgapp_action);
+ lowmem_limit_set_app(mem_bgapp_limit_bytes, ps->pai, mem_bgapp_action);
return RESOURCED_ERROR_NONE;
}
struct proc_status *ps = (struct proc_status *)data;
- if ((mem_guiapp_limit && ps->pai->type == PROC_TYPE_GUI) ||
- (mem_widget_limit && ps->pai->type == PROC_TYPE_WIDGET))
+ if ((mem_guiapp_limit_bytes && ps->pai->type == PROC_TYPE_GUI) ||
+ (mem_widget_limit_bytes && ps->pai->type == PROC_TYPE_WIDGET))
return lowmem_limit_appwidget(data);
_E("[MEMORY-LIMIT] Unable to set foreground app limit - app type not supported");
return RESOURCED_ERROR_NONE;
}
-void lowmem_memory_init(unsigned int service_limit, unsigned int widget_limit,
- unsigned int guiapp_limit, unsigned int bgapp_limit)
+void lowmem_memory_init(unsigned long long service_limit_bytes, unsigned long long widget_limit_bytes,
+ unsigned long long guiapp_limit_bytes, unsigned long long bgapp_limit_bytes)
{
- mem_service_limit = service_limit;
- mem_widget_limit = widget_limit;
- mem_guiapp_limit = guiapp_limit;
- mem_bgapp_limit = bgapp_limit;
+ mem_service_limit_bytes = service_limit_bytes;
+ mem_widget_limit_bytes = widget_limit_bytes;
+ mem_guiapp_limit_bytes = guiapp_limit_bytes;
+ mem_bgapp_limit_bytes = bgapp_limit_bytes;
+
+ _I("[MEMORY-LIMIT] service = %llu bytes, widget = %llu bytes, guiapp = %llu bytes, bgapp = %llu",
+ mem_service_limit_bytes, mem_widget_limit_bytes, mem_guiapp_limit_bytes, mem_bgapp_limit_bytes);
}
void lowmem_action_init(int service_action, int widget_action,
void lowmem_limit_init(void)
{
int result;
- unsigned int usage;
+ unsigned long long usage_bytes;
- result = cgroup_read_node_uint32(MEMCG_PATH, MEMCG_SWAP_USAGE, &usage);
+ result = cgroup_read_node_ulonglong(MEMCG_PATH, MEMCG_SWAP_USAGE, &usage_bytes);
if (result == RESOURCED_ERROR_NONE)
registerpath = MEMCG_SWAP_USAGE;
else
register_notifier(RESOURCED_NOTIFIER_LIMIT_SYSTEM_SERVICE, lowmem_limit_system_service);
register_notifier(RESOURCED_NOTIFIER_LIMIT_APP, lowmem_limit_app);
- if (mem_service_limit && mem_service_action != PROC_ACTION_IGNORE)
+ if (mem_service_limit_bytes && mem_service_action != PROC_ACTION_IGNORE)
register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, lowmem_limit_service);
- if ((mem_guiapp_limit && mem_guiapp_action != PROC_ACTION_IGNORE) ||
- (mem_widget_limit && mem_widget_action != PROC_ACTION_IGNORE))
+ if ((mem_guiapp_limit_bytes && mem_guiapp_action != PROC_ACTION_IGNORE) ||
+ (mem_widget_limit_bytes && mem_widget_action != PROC_ACTION_IGNORE))
register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_limit_appwidget);
- if (mem_bgapp_limit && mem_bgapp_action != PROC_ACTION_IGNORE) {
- if (!(mem_guiapp_limit && mem_guiapp_action != PROC_ACTION_IGNORE) ||
- !(mem_widget_limit && mem_widget_action != PROC_ACTION_IGNORE)) {
+ if (mem_bgapp_limit_bytes && mem_bgapp_action != PROC_ACTION_IGNORE) {
+ if (!(mem_guiapp_limit_bytes && mem_guiapp_action != PROC_ACTION_IGNORE) ||
+ !(mem_widget_limit_bytes && mem_widget_action != PROC_ACTION_IGNORE)) {
_W("[MEMORY-LIMIT] Background app limit requires that both GUIApp and Widget limits to be set to work properly. Ignoring.");
} else {
register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, lowmem_limit_bgapp);