c69abf6eb96d76bd9f88bab4fb970d94ffadbdb0
[platform/core/system/resourced.git] / src / resource-optimizer / cpu / cpu-sched.c
1 #include <stdio.h>
2 #include "module.h"
3 #include "macro.h"
4 #include "resourced.h"
5 #include "config-parser.h"
6 #include "trace.h"
7 #include "cgroup.h"
8 #include "notifier.h"
9 #include "cpu-hotplug.h"
10 #include "proc-common.h"
11 #include "file-helper.h"
12 #include "cpu-cgroup.h"
13 #include "cpu-common.h"
14 #include "util.h"
15
16 #define MOUNTS_PATH                     "/proc/mounts"
17 #define CPUSET_CGROUP           "/sys/fs/cgroup/cpuset"
18
19 #define GLOBAL_RT_PERIOD_US_PATH       "/proc/sys/kernel/sched_rt_period_us"
20 #define GLOBAL_RT_RUNTIME_US_PATH      "/proc/sys/kernel/sched_rt_runtime_us"
21 #define CPU_SCHED_FEATURE_PATH         "/sys/kernel/debug/sched_features"
22 #define ONLINE_CPU_PATH                "/sys/devices/system/cpu/online"
23
24 struct cpu_sched {
25         struct cpuset_info *fg;
26         GSList *apps;
27         bool is_initialized;
28 };
29
30 static struct cpu_sched cs;
31
32 static int cpu_sched_cpu_on(void *data);
33
34 static struct cpuset_info *cpu_sched_find_coreset(const char *name)
35 {
36         struct proc_conf_info *pci = fixed_app_and_service_exist_check(name, APP_TYPE);
37         if (pci == NULL)
38                 return NULL;
39
40         if (pci->cpuset_info.name == NULL)
41                 return NULL;
42
43         if (pci->cpuset_info.cpu_info == NULL)
44                 return NULL;
45
46         return &pci->cpuset_info;
47 }
48
49 /* check if cpuset subsystem is mounted at the right location */
50 static bool cpu_sched_is_cpuset_mounted()
51 {
52         FILE *f;
53         ssize_t r;
54         size_t len = 0;
55         char *buf = NULL;
56         char mountpoint[128], opts[128];
57         bool ret = false;
58
59         f = fopen(MOUNTS_PATH, "r");
60         if (f == NULL) {
61                 _E("cpu-sched: could not open " MOUNTS_PATH);
62                 return ret;
63         }
64
65         while ((r = getline(&buf, &len, f)) != -1) {
66                 if (sscanf(buf, "%*s %127s %*s %127s %*d %*d", mountpoint, opts) != 2)
67                         continue;
68
69                 if (!strcmp(mountpoint, CPUSET_CGROUP) && strstr(opts, "cpuset") != NULL) {
70                         ret = true;
71                         break;
72                 }
73         }
74
75         free(buf);
76         fclose(f);
77
78         return ret;
79 }
80
81 static int cpu_sched_init_cgroup_set(const struct cpuset_info *set)
82 {
83         int r;
84         char buf[512];
85
86         if (set == NULL)
87                 return 0;
88
89         assert(set->name);
90
91         r = cgroup_make_subdir(CPUSET_CGROUP, set->name, NULL);
92         if (r < 0) {
93                 _E("[CPU-SCHED] failed to make cpuset cgroup (%s)", set->name);
94                 return r;
95         }
96
97         r = snprintf(buf, sizeof buf, "%s/%s", CPUSET_CGROUP, set->name);
98         if (r < 0) {
99                 _E("[CPU-SCHED] failed to setup memory nodes for cpuset (%s)", set->name);
100                 return r;
101         }
102
103         /* don't force any memory nodes with this cpuset */
104         r = cgroup_write_node_uint32(buf, "cpuset.mems", 0);
105         ret_value_msg_if(r < 0, r,
106                 "[CPU-SCHED] Failed to reset memory nodes for cpuset: %m");
107
108         return 0;
109 }
110
111 static int cpu_sched_init_cpu_online_info(void)
112 {
113         int ret;
114         GSList *item;
115         struct cpuset_info cpuset_info = {0, };
116         _cleanup_free_ char *buf = NULL;
117
118         buf = calloc(1, PATH_MAX);
119         if (!buf)
120                 return RESOURCED_ERROR_OUT_OF_MEMORY;
121
122         /* Read the current online cpus */
123         ret = fread_str(ONLINE_CPU_PATH, &buf);
124         if (ret < 0) {
125                 _E("[CPU-SCHED] failed to read online cpu");
126                 return ret;
127         }
128
129         if (cpu_sched_parse_cpuset(&cpuset_info, buf) < 0) {
130                 _E("invalid cpu affinity value (%s)", buf);
131
132                 if (cpuset_info.cpu_info != NULL)
133                         g_slist_free_full(cpuset_info.cpu_info, free);
134
135                 return RESOURCED_ERROR_FAIL;
136         }
137
138         /* Pin cpu affinity */
139         gslist_for_each_item(item, cpuset_info.cpu_info) {
140                 struct cpu_info *cpu_info = (struct cpu_info *)item->data;
141                 if (cpu_info == NULL)
142                         continue;
143
144                 cpu_sched_cpu_on(&cpu_info->cpu_id);
145         }
146
147         return RESOURCED_ERROR_NONE;
148 }
149
150 /* init cpuset's cgroups */
151 static int cpu_sched_init_cgroup(struct cpu_sched *cs)
152 {
153         int r;
154         GSList *i;
155         struct cpuset_info *cpuset_info;
156
157         if (cpu_sched_is_cpuset_mounted() == false) {
158                 r = cgroup_make_subdir(CGROUP_PATH, "cpuset", NULL);
159                 if (r < 0) {
160                         _E("failed to make cpuset cgroup");
161                         return r;
162                 }
163
164                 r = cgroup_mount_subsystem("cpuset", CPUSET_CGROUP, "cpuset");
165                 if (r < 0) {
166                         _E("failed to mount cpuset cgroup: %m");
167                         return r;
168                 }
169         }
170
171         gslist_for_each_item(i, cs->apps) {
172                 cpuset_info = (struct cpuset_info *)i->data;
173                 r = cpu_sched_init_cgroup_set(cpuset_info);
174                 if (r < 0) {
175                         _E("cpu-set: error setting up cpuset (%s)", cpuset_info->name);
176                         return r;
177                 }
178         }
179
180         r = cpu_sched_init_cgroup_set(cs->fg);
181         if (r < 0) {
182                 _E("cpu-set: error setting up cpuset (%s)", cs->fg->name);
183                 return r;
184         }
185
186         return cpu_sched_init_cpu_online_info();
187 }
188
189 /* free memory allocated in cpuset_info structure */
190 static void cpu_sched_free_cpuset(struct cpuset_info **cpuset_info)
191 {
192         struct cpuset_info *set = *cpuset_info;
193
194         if (set->cpu_info != NULL)
195                 g_slist_free_full(set->cpu_info, free);
196         set->cpu_info = NULL;
197
198         free(set->name);
199         set->name = NULL;
200
201         free(set);
202         *cpuset_info = NULL;
203 }
204
205 /* free memory allocated in cpuset_info structure and the structure */
206 static void cpu_sched_free_cpuset_full(void *data)
207 {
208         struct cpuset_info *set = (struct cpuset_info *)data;
209
210         assert(set);
211
212         cpu_sched_free_cpuset(&set);
213 }
214
215
216 static int load_cpu_affinity_config(struct cpu_sched *data)
217 {
218         char *name;
219         gpointer app_name;
220         gpointer proc_conf_ptr;
221         GHashTableIter app_list_iter;
222
223         assert(data);
224
225         if (get_cpu_affinity_conf_name() == NULL)
226                 goto cpu_affinity_set_for_fixed_app;
227
228         if (strcmp(get_cpu_affinity_conf_name(), FOREGROUND_APPS_NAME_CONF)) {
229                 _E("[CPU-SCHED] Wrong name (%s), is should be 'ForegroundApps'",
230                                 get_cpu_affinity_conf_name());
231                 goto cpu_affinity_set_for_fixed_app;
232         }
233
234         name = strdup(get_cpu_affinity_conf_name());
235         if (!name) {
236                 _E("[CPU-SCHED] Failed to allocate memory during making a duplicate name (%s)",
237                                 get_cpu_affinity_conf_name());
238                 goto cpu_affinity_set_for_fixed_app;
239         }
240
241         struct cpuset_info *cpuset_info = (struct cpuset_info *)calloc(1, sizeof *cpuset_info);
242         if (cpuset_info == NULL) {
243                 free(name);
244                 _E("[CPU_SCHED] Failed to allocate memory");
245                 goto cpu_affinity_set_for_fixed_app;
246         }
247
248         cpuset_info->name = name;
249
250         if (!get_cpu_affinity_conf_value() ||
251                         cpu_sched_parse_cpuset(cpuset_info, get_cpu_affinity_conf_value()) < 0) {
252                 cpu_sched_free_cpuset(&cpuset_info);
253                 goto cpu_affinity_set_for_fixed_app;
254         }
255
256         data->fg = cpuset_info;
257
258 cpu_affinity_set_for_fixed_app:
259         /* Free memory if previously allocated memory for 'ForegroundApps' exists */
260         free_cpu_affinity_conf();
261
262         /* Register static fixed cpu affinity apps */
263         g_hash_table_iter_init(&app_list_iter, fixed_app_list_get());
264         while (g_hash_table_iter_next(&app_list_iter, &app_name, &proc_conf_ptr)) {
265                 struct proc_conf_info *pci = (struct proc_conf_info *)proc_conf_ptr;
266
267                 if (!pci) {
268                         _W("[CPU-SCHED] Process configuration information is NULL");
269                         continue;
270                 }
271
272                 if (pci->cpuset_info.cpu_info) {
273                         pci->cpuset_info.name = pci->name;
274                         data->apps = g_slist_append(data->apps, &pci->cpuset_info);
275                 }
276         }
277
278         return RESOURCED_ERROR_NONE;
279 }
280
281 static int load_cpu_sched_config(void)
282 {
283         struct cpu_sched_conf *cpu_sched_conf = get_cpu_sched_conf();
284         if (cpu_sched_conf == NULL) {
285                 _E("[CPU-SCHED] cpu sched configuration structure should not be NULL");
286                 return RESOURCED_ERROR_FAIL;
287         }
288
289         if (cpu_sched_conf->cpu_cgroup_info.rt_period_us > 0 &&
290             cpu_sched_conf->cpu_cgroup_info.rt_runtime_us > 0 &&
291                 cpu_sched_conf->cpu_cgroup_info.rt_period_us >
292                 cpu_sched_conf->cpu_cgroup_info.rt_runtime_us) {
293                 fwrite_ulonglong(CPUCG_PATH "/" CPUCG_RT_CONTROL_FULL_BANDWIDTH,
294                                 cpu_sched_conf->cpu_cgroup_info.rt_period_us);
295                 fwrite_ulonglong(CPUCG_PATH "/" CPUCG_RT_CONTROL_BANDWIDTH,
296                                 cpu_sched_conf->cpu_cgroup_info.rt_runtime_us);
297                 fwrite_ulonglong(GLOBAL_RT_PERIOD_US_PATH, cpu_sched_conf->cpu_cgroup_info.rt_period_us);
298                 fwrite_longlong(GLOBAL_RT_RUNTIME_US_PATH, cpu_sched_conf->cpu_cgroup_info.rt_runtime_us);
299         }
300
301         if (cpu_sched_conf->cpu_sched_flag) {
302                 if (CHECK_BIT(cpu_sched_conf->cpu_sched_flag, CPU_SCHED_RUNTIME_SHARE) &&
303                     CHECK_BIT(cpu_sched_conf->cpu_sched_flag, CPU_SCHED_NO_RUNTIME_SHARE)) {
304                         _E("[CPU-SCHED] RT_RUNTIME_SHARE and NO_RT_RUNTIME_SHARE cannot be coexisted");
305                 }
306                 else {
307                         /* RT_RUNTIME_SHARE */
308                         if (CHECK_BIT(cpu_sched_conf->cpu_sched_flag, CPU_SCHED_RUNTIME_SHARE))
309                                 fwrite_str(CPU_SCHED_FEATURE_PATH, "RT_RUNTIME_SHARE");
310                         else if (CHECK_BIT(cpu_sched_conf->cpu_sched_flag, CPU_SCHED_NO_RUNTIME_SHARE))
311                                 fwrite_str(CPU_SCHED_FEATURE_PATH, "NO_RT_RUNTIME_SHARE");
312
313                         /* RT_RUNTIME_GREED */
314 /*                      if (CHECK_BIT(cpu_sched_conf->cpu_sched_flag, CPU_SCHED_RUNTIME_GREED))
315                                 fwrite_str(CPU_SCHED_FEATURE_PATH, "RT_RUNTIME_GREED");*/
316                 }
317         }
318
319         _I("[CPU-SCHED] rt_period_us = %llu", cpu_sched_conf->cpu_cgroup_info.rt_period_us);
320         _I("[CPU-SCHED] rt_runtime_us = %lld", cpu_sched_conf->cpu_cgroup_info.rt_runtime_us);
321         _I("[CPU-SCHED] cpu_sched_feature = %d", cpu_sched_conf->cpu_sched_flag);
322
323         free_cpu_sched_conf();
324         return RESOURCED_ERROR_NONE;
325 }
326
327 static int cpu_sched_parse_config(struct cpu_sched *data)
328 {
329         load_cpu_affinity_config(data);
330         load_cpu_sched_config();
331         return RESOURCED_ERROR_NONE;
332 }
333
334 static int cpu_sched_write_coreset(struct cpuset_info *set)
335 {
336         GSList *i;
337         struct cpu_info *cpu_info;
338         char path[128], coreset[128];
339         int r;
340
341         assert(set);
342
343         r = snprintf(path, sizeof path, "%s/%s", CPUSET_CGROUP, set->name);
344         if (r < 0) {
345                 _E("cpu-sched: failed to setup path for cpuset (%s)", set->name);
346                 return r;
347         }
348
349         r = 0;
350         gslist_for_each_item(i, set->cpu_info) {
351                 cpu_info = (struct cpu_info *)i->data;
352                 if (cpu_info == NULL || cpu_info->online == false)
353                         continue;
354
355                 r += snprintf(coreset + r, sizeof coreset - r, "%d,", cpu_info->cpu_id);
356         }
357
358         if (r > 0)
359                 coreset[--r] = '\0';
360
361         return cgroup_write_node_str(path, "cpuset.cpus", coreset);
362 }
363
364 static int cpu_sched_cpu_on_for_coreset(struct cpuset_info *set, int core_id)
365 {
366         GSList *i;
367         struct cpu_info *cpu_info;
368         bool refresh = false;
369
370         assert(set);
371         assert(core_id >= 0);
372
373         if (set->cpu_info == NULL)
374                 return 0;
375
376         gslist_for_each_item(i, set->cpu_info) {
377                 cpu_info = (struct cpu_info *)i->data;
378                 if (cpu_info == NULL || cpu_info->cpu_id != core_id)
379                         continue;
380
381                 _D("cpu-sched: core %d on for cpuset_info %s", core_id, set->name);
382                 cpu_info->online = true;
383                 refresh = true;
384                 break;
385         }
386
387         if (refresh == false)
388                 return 0;
389
390         return cpu_sched_write_coreset(set);
391 }
392
393 static int cpu_sched_cpu_off_for_coreset(struct cpuset_info *set, int core_id)
394 {
395         GSList *i;
396         struct cpu_info *cpu_info;
397         bool refresh = false;
398
399         assert(set);
400         assert(core_id >= 0);
401
402         if (set->cpu_info == NULL)
403                 return 0;
404
405         gslist_for_each_item(i, set->cpu_info) {
406                 cpu_info = (struct cpu_info *)i->data;
407                 if (cpu_info == NULL || cpu_info->cpu_id != core_id)
408                         continue;
409
410                 _D("cpu-sched: core %d off for cpuset_info %s", core_id, set->name);
411                 cpu_info->online = false;
412                 refresh = true;
413                 break;
414         }
415
416         if (refresh == false)
417                 return 0;
418
419         return cpu_sched_write_coreset(set);
420 }
421
422 static int cpu_sched_cpu_on(void *data)
423 {
424         int id;
425         GSList *i;
426
427         assert(data);
428
429         id = *(int*)(data);
430
431         _D("cpu-sched: core %d plugged in", id);
432         gslist_for_each_item(i, cs.apps) {
433                 cpu_sched_cpu_on_for_coreset((struct cpuset_info *)i->data, id);
434         }
435         if (cs.fg)
436                 cpu_sched_cpu_on_for_coreset(cs.fg, id);
437
438         return RESOURCED_ERROR_NONE;
439 }
440
441 static int cpu_sched_cpu_off(void *data)
442 {
443         int id;
444         GSList *i;
445
446         assert(data);
447
448         id = *(int*)(data);
449
450         _D("cpu-sched: core %d plugged out", id);
451         gslist_for_each_item(i, cs.apps) {
452                 cpu_sched_cpu_off_for_coreset((struct cpuset_info *)i->data, id);
453         }
454
455         if (cs.fg)
456                 cpu_sched_cpu_off_for_coreset(cs.fg, id);
457
458         return RESOURCED_ERROR_NONE;
459 }
460
461 static int cpu_sched_add_pid_to_cpuset(struct cpuset_info *set, pid_t pid)
462 {
463         assert(set);
464
465         _D("cpu-sched: add pid %d to cpuset %s", pid, set->name);
466
467         cgroup_write_pid(CPUSET_CGROUP, set->name, pid);
468
469         return RESOURCED_ERROR_NONE;
470 }
471
472 static int cpu_sched_remove_pid_from_cpuset(struct cpuset_info *set, pid_t pid)
473 {
474         assert(set);
475
476         _D("cpu-sched: moving pid %d to toplevel cpuset (from %s cpuset)", pid, set->name);
477
478         cgroup_write_pid_fullpath(CPUSET_CGROUP, pid);
479
480         return RESOURCED_ERROR_NONE;
481 }
482
483 /* if app is subject to static cpuset_info config its cpuset_info should not be changed */
484 static bool cpu_sched_is_static_app(const char *appid)
485 {
486         assert (appid);
487
488         struct cpuset_info *cpuset_info = cpu_sched_find_coreset(appid);
489         if (!cpuset_info)
490                 return false;
491
492         if (cpuset_info->disclaimer_shown == false) {
493                 _D("cpu-sched: appid %s is statically configured - not subject to cpuset change", appid);
494                 cpuset_info->disclaimer_shown = true;
495         }
496
497         return true;
498 }
499
500 static int cpu_sched_app_foreground(void *data)
501 {
502         struct proc_status *ps = (struct proc_status *)data;
503
504         assert(cs.fg);
505         assert(ps);
506         assert(ps->pai);
507
508         if (cs.is_initialized == false || cpu_sched_is_static_app(ps->pai->appid) == true)
509                 return RESOURCED_ERROR_NONE;
510
511         _D("cpu-sched: app %s moved to foreground; pid=%d", ps->pai->appid, ps->pid);
512
513         return cpu_sched_add_pid_to_cpuset(cs.fg, ps->pid);
514 }
515
516 static int cpu_sched_app_background(void *data)
517 {
518         struct proc_status *ps = (struct proc_status *)data;
519
520         assert(cs.fg);
521         assert(ps);
522         assert(ps->pai);
523
524         if (cs.is_initialized == false || cpu_sched_is_static_app(ps->pai->appid) == true)
525                 return RESOURCED_ERROR_NONE;
526
527         _D("cpu-sched: app %s moved to background; pid=%d", ps->pai->appid, ps->pid);
528
529         return cpu_sched_remove_pid_from_cpuset(cs.fg, ps->pid);
530 }
531
532 static int cpu_sched_app_launch(void *data)
533 {
534         struct proc_status *ps = (struct proc_status *)data;
535         struct cpuset_info *cpuset_info;
536
537         assert(ps);
538         assert(ps->pai);
539
540         _D("cpu-sched: app launch: %s", ps->pai->appid);
541
542         cpuset_info = cpu_sched_find_coreset(ps->pai->appid);
543         if (cpuset_info == NULL)
544                 return 0;
545
546         return cpu_sched_add_pid_to_cpuset(cpuset_info, ps->pid);
547 }
548
549 /*static int cpu_sched_rt_scheduler(void *data)
550 {
551         _cleanup_free_ char *path = NULL;
552         int result;
553         int32_t runtime;
554         struct proc_status *ps = (struct proc_status *)data;
555
556         assert(ps);
557         assert(ps->pci);
558         assert(ps->pci->name);
559
560         result = cgroup_read_node_int32(CPUCG_PATH, CPUCG_RT_CONTROL_BANDWIDTH, &runtime);
561         if (result < 0) {
562                 _W("[CPU-SCHED] rt_runtime_us is not supported");
563                 return RESOURCED_ERROR_FAIL;
564         }
565
566         result = asprintf(&path, "%s/%s", CPUCG_PATH, ps->pci->name);
567         if (result < 0) {
568                 _E("[CPU-SCHED] not enough memory");
569                 return RESOURCED_ERROR_OUT_OF_MEMORY;
570         }
571
572         result = cgroup_make_subdir(CPUCG_PATH, ps->pci->name, NULL);
573         if (result < 0) {
574                 _E("[CPU-SCHED] Failed to create cgroup subdir '%s/%s'",
575                                 CPUCG_PATH, ps->pci->name);
576                 return RESOURCED_ERROR_FAIL;
577         }
578
579         cgroup_write_node_int32(path, CPUCG_RT_CONTROL_FULL_BANDWIDTH, ps->pci->cpu_sched_info.rt_period_us);
580         cgroup_write_node_int32(path, CPUCG_RT_CONTROL_BANDWIDTH, ps->pci->cpu_sched_info.rt_runtime_us);
581
582         cgroup_write_pid_fullpath(path, ps->pid);
583
584         return RESOURCED_ERROR_NONE;
585 }*/
586
587 static void register_notifiers()
588 {
589         if (cs.fg) {
590                 register_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_sched_app_foreground);
591                 register_notifier(RESOURCED_NOTIFIER_APP_SUSPEND, cpu_sched_app_background);
592
593                 register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_sched_app_foreground);
594                 register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_sched_app_background);
595
596                 register_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_sched_app_foreground);
597                 register_notifier(RESOURCED_NOTIFIER_WIDGET_BACKGRD, cpu_sched_app_background);
598         }
599
600 //      register_notifier(RESOURCED_NOTIFIER_RT_SCHEDULER, cpu_sched_rt_scheduler);
601
602         register_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
603         register_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
604
605         register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
606         register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, cpu_sched_app_launch);
607 }
608
609 static void unregister_notifiers()
610 {
611         if (cs.fg) {
612                 unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_sched_app_foreground);
613                 unregister_notifier(RESOURCED_NOTIFIER_APP_SUSPEND, cpu_sched_app_background);
614
615                 unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_sched_app_foreground);
616                 unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_sched_app_background);
617
618                 unregister_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_sched_app_foreground);
619                 unregister_notifier(RESOURCED_NOTIFIER_WIDGET_BACKGRD, cpu_sched_app_background);
620         }
621
622 //      unregister_notifier(RESOURCED_NOTIFIER_RT_SCHEDULER, cpu_sched_rt_scheduler);
623
624         unregister_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
625         unregister_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
626
627         unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
628         unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, cpu_sched_app_launch);
629 }
630
631 static void cpu_sched_free_cpusets()
632 {
633         g_slist_free_full(g_steal_pointer(&cs.apps), cpu_sched_free_cpuset_full);
634         if (cs.fg)
635                 cpu_sched_free_cpuset(&cs.fg);
636 }
637
638 static void cpu_sched_check_apps()
639 {
640         _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
641         GSList *giter;
642         struct proc_app_info *pai;
643         struct cpuset_info *cpuset_info;
644
645         proc_app_list = proc_app_list_open();
646         gslist_for_each_item(giter, proc_app_list) {
647                 pai = (struct proc_app_info *)giter->data;
648                 if (!pai || !pai->main_pid)
649                         continue;
650
651                 cpuset_info = cpu_sched_find_coreset(pai->appid);
652                 if (cpuset_info != NULL) {
653                         cpu_sched_add_pid_to_cpuset(cpuset_info, pai->main_pid);
654                         continue;
655                 }
656
657                 if (cs.fg && pai->state == PROC_STATE_FOREGROUND)
658                         cpu_sched_add_pid_to_cpuset(cs.fg, pai->main_pid);
659         }
660 }
661
662 static int cpu_sched_init(void *data)
663 {
664         int r;
665
666         if (cpu_sched_parse_config(&cs) != RESOURCED_ERROR_NONE) {
667                 _E("cpu-sched: error parsing config");
668                 return RESOURCED_ERROR_FAIL;
669         }
670
671         r = cpu_sched_init_cgroup(&cs);
672         if (r < 0)
673                 goto init_failed;
674
675         register_notifiers();
676         if (cpu_hotplug_init() != 0) {
677                 _E("cpu_sched: could not setup cpu hotplugging");
678                 return RESOURCED_ERROR_FAIL;
679         }
680
681         cs.is_initialized = true;
682         cpu_sched_check_apps();
683         return RESOURCED_ERROR_NONE;
684
685 init_failed:
686         unregister_notifiers();
687         cpu_hotplug_finalize();
688         cpu_sched_free_cpusets();
689         cs.is_initialized = false;
690         return RESOURCED_ERROR_FAIL;
691 }
692
693 static int cpu_sched_finalize(void *data)
694 {
695         _D("cpu-sched: deinit module");
696         unregister_notifiers();
697         cpu_hotplug_finalize();
698         cpu_sched_free_cpusets();
699         cs.is_initialized = false;
700         return RESOURCED_ERROR_NONE;
701 }
702
703 static struct module_ops cpu_sched_modules_ops = {
704         .priority = MODULE_PRIORITY_NORMAL,
705         .name = "cpu-sched",
706         .init = cpu_sched_init,
707         .exit = cpu_sched_finalize,
708 };
709
710 MODULE_REGISTER(&cpu_sched_modules_ops)