#include "notifier.h"
#include "cpu-hotplug.h"
#include "proc-common.h"
+#include "file-helper.h"
+#include "util.h"
#define CPU_SCHED_CONF_FILE RD_CONFIG_FILE(cpu-sched)
#define CPU_SCHED_FG_NAME "foreground"
struct cpu_sched {
struct coreset fg;
+ GSList *apps;
bool is_initalized;
};
static struct cpu_sched cs;
+struct coreset *cpu_sched_find_coreset(const char *name)
+{
+ GSList *i;
+ struct coreset *c;
+
+ gslist_for_each_item(i, cs.apps) {
+ c = (struct coreset *)i->data;
+ if (!strcmp(name, c->name))
+ return c;
+ }
+ return NULL;
+}
+
/* check if cpuset subsystem is mounted at the right location */
static bool cpu_sched_is_cpuset_mounted()
{
static int cpu_sched_init_cgroup(struct cpu_sched *cs)
{
int r;
+ GSList *i;
+ struct coreset *c;
_D("cpu-sched: init cgroup subsystem");
if (false == cpu_sched_is_cpuset_mounted()) {
}
}
+ gslist_for_each_item(i, cs->apps) {
+ c = (struct coreset *)i->data;
+ r = cpu_sched_init_cgroup_set(c);
+ if (r < 0) {
+ _E("cpu-set: error setting up cpuset (%s)", c->name);
+ return r;
+ }
+ }
return cpu_sched_init_cgroup_set(&cs->fg);
}
set->name = NULL;
}
+/* free memory allocated in coreset structure and the structure */
+static void cpu_sched_free_cpuset_full(void *data)
+{
+ struct coreset *set = (struct coreset *)data;
+
+ assert(set);
+
+ cpu_sched_free_cpuset(set);
+ free(set);
+}
+
/* parse config for specific coreset line */
static int cpu_sched_parse_cpuset(struct coreset *set, char *value)
{
assert(data);
- if (strcmp(result->name, CPU_SCHED_FG_NAME))
- return RESOURCED_ERROR_NONE;
+ if (strcmp(result->name, CPU_SCHED_FG_NAME)) { /* not a 'foreground' group */
+ struct coreset *c = (struct coreset *)calloc(1, sizeof *c);
+ if (NULL == c)
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+
+ c->name = strdup(result->name);
- r = cpu_sched_parse_cpuset(&data->fg, result->value);
+ r = cpu_sched_parse_cpuset(c, result->value);
+
+ if (RESOURCED_ERROR_NONE == r)
+ data->apps = g_slist_append(data->apps, c);
+ } else {
+ data->fg.name = strdup(CPU_SCHED_FG_NAME);
+ r = cpu_sched_parse_cpuset(&data->fg, result->value);
+ }
if (r < 0) {
_E("cpu-sched parse fg coreset: could not parse");
return RESOURCED_ERROR_FAIL;
}
- data->fg.name = strdup(CPU_SCHED_FG_NAME);
return RESOURCED_ERROR_NONE;
}
static int cpu_sched_cpu_on(void *data)
{
int id;
+ GSList *i;
assert(data);
id = *(int*)(data);
_D("cpu-sched: core %d plugged in", id);
+ gslist_for_each_item(i, cs.apps) {
+ cpu_sched_cpu_on_for_coreset((struct coreset *)i->data, id);
+ }
cpu_sched_cpu_on_for_coreset(&cs.fg, id);
return RESOURCED_ERROR_NONE;
static int cpu_sched_cpu_off(void *data)
{
int id;
+ GSList *i;
assert(data);
id = *(int*)(data);
_D("cpu-sched: core %d plugged out", id);
+ gslist_for_each_item(i, cs.apps) {
+ cpu_sched_cpu_off_for_coreset((struct coreset *)i->data, id);
+ }
+
cpu_sched_cpu_off_for_coreset(&cs.fg, id);
return RESOURCED_ERROR_NONE;
}
-static int cpu_sched_add_pid_to_cpuset(struct coreset *set, pid_t pid)
+static int cpu_sched_add_pid_to_cpuset(struct coreset *set, pid_t pid, bool move_pid)
{
pid_t old_pid;
- char path[128];
+ char path[PATH_MAX];
+ _cleanup_free_ char *buf = NULL;
int r;
assert(set);
return r;
}
- /* read pid of previous foreground app */
- if (RESOURCED_ERROR_NONE != cgroup_read_node_int32(path, "tasks", &old_pid)) {
- _E("cpu-sched: could not read old value of fg app's pid");
- return RESOURCED_ERROR_FAIL;
- }
+ buf = (char *)calloc(1, PATH_MAX);
+ if (NULL == buf)
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
- /* and write it to default cpuset */
- r = cgroup_write_node_int32(CPUSET_CGROUP, "tasks", (u_int32_t)old_pid);
- ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
- "Failed to attach pid %d to cgroup %s : %m",
- old_pid, CPUSET_CGROUP);
+
+ if (true == move_pid) { /* in case of foreground app previous pid needs to be moved to main cpuset first */
+ /* read pid of previous foreground app, there can be only one */
+ if (RESOURCED_ERROR_NONE == cgroup_read_node_int32(path, "tasks", &old_pid)) {
+ /* and write it to default cpuset */
+ r = cgroup_write_node_int32(CPUSET_CGROUP, "tasks", (u_int32_t)old_pid);
+ ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
+ "Failed to attach pid %d to cgroup %s : %m",
+ old_pid, CPUSET_CGROUP);
+ }
+
+ r = snprintf(buf, PATH_MAX, "%d", pid);
+ if (r < 0) {
+ _E("cpu-sched: failed to create pid list for cpuset (%s)", set->name);
+ return r;
+ }
+
+ } else { /* in case of static apps new pid needs to be appended to existing pids */
+ char path_full[PATH_MAX];
+
+ r = snprintf(path_full, sizeof path_full, "%s/tasks", path);
+ if (r < 0) {
+ _E("cpu-sched: failed to setup path for cpuset (%s)", set->name);
+ return r;
+ }
+
+ r = 0;
+ /* read pid of previous apps in this cpuset, there can be more than one */
+ if (RESOURCED_ERROR_NONE != fread_str(path_full, &buf)) {
+ _I("cpu-sched: could not read old value of app's pids, adding first one");
+ r = snprintf(buf, PATH_MAX, "%d", pid);
+ } else {
+ /* append new pid at the end */
+ r = snprintf(buf + strlen(buf), PATH_MAX - strlen(buf), ",%d", pid);
+ }
+
+ if (r < 0) {
+ _E("cpu-sched: failed to create pid list for cpuset (%s)", set->name);
+ return r;
+ }
+ _D("cpu-sched: add new pids to cpuset %s: %s (%d)", set->name, buf, r);
+
+ }
/* write current foreground app to proper cpuset */
- r = cgroup_write_node_int32(path, "tasks", (u_int32_t)pid);
+ r = cgroup_write_node_str(path, "tasks", buf);
ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
"Failed to attach pid %d to cgroup %s : %m",
pid, path);
if (false == cs.is_initalized)
return RESOURCED_ERROR_NONE;
+ /* if this app is subject to static coreset config don't change that */
+ if (NULL != cpu_sched_find_coreset(ps->pai->appid))
+ return 0;
+
_D("cpu-sched: app %s moved to foreground; pid=%d", ps->pai->appid, ps->pid);
- return cpu_sched_add_pid_to_cpuset(&cs.fg, ps->pid);
+ return cpu_sched_add_pid_to_cpuset(&cs.fg, ps->pid, true);
+}
+
+
+static int cpu_sched_app_launch(void *data)
+{
+ struct proc_status *ps = (struct proc_status *)data;
+ struct coreset *c;
+
+ assert(ps);
+ assert(ps->pai);
+
+ _D("cpu-sched: app launch: %s", ps->pai->appid);
+
+ c = cpu_sched_find_coreset(ps->pai->appid);
+ if (NULL == c)
+ return 0;
+
+ return cpu_sched_add_pid_to_cpuset(c, ps->pid, false);
}
static void register_notifiers()
register_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
register_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
+
+ register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
}
static void unregister_notifiers()
unregister_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
unregister_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
+
+ unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
+}
+
+static void cpu_sched_free_cpusets()
+{
+ g_slist_free_full(g_steal_pointer(&cs.apps), cpu_sched_free_cpuset_full);
+ cpu_sched_free_cpuset(&cs.fg);
}
static int cpu_sched_init(void *data)
init_failed:
unregister_notifiers();
cpu_hotplug_finalize();
- cpu_sched_free_cpuset(&cs.fg);
+ cpu_sched_free_cpusets();
cs.is_initalized = false;
return RESOURCED_ERROR_FAIL;
}
_D("cpu-sched: deinit module");
unregister_notifiers();
cpu_hotplug_finalize();
- cpu_sched_free_cpuset(&cs.fg);
+ cpu_sched_free_cpusets();
cs.is_initalized = false;
return RESOURCED_ERROR_NONE;
}