tizen 2.3 release
[kernel/api/system-resource.git] / src / timer-slack / timer-slack.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18 */
19
20 /*
21  * @file timer-slack.c
22  * @desc control timer about timer-slack cgroup
23  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
24  */
25
26 #include "macro.h"
27 #include "module.h"
28 #include "module-data.h"
29 #include "edbus-handler.h"
30 #include "resourced.h"
31 #include "trace.h"
32 #include "vconf.h"
33 #include "cgroup.h"
34 #include "config-parser.h"
35 #include "const.h"
36 #include "timer-slack.h"
37 #include "notifier.h"
38 #include "proc-main.h"
39 #include "proc-process.h"
40
41 #include <resourced.h>
42 #include <trace.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <dirent.h>
47
48 #define TIMER_EXCLUDE_CGROUP    "exclude"
49 #define TIMER_SERVICE_CGROUP    "service"
50 #define TIMER_BACKGRD_CGROUP    "background"
51 #define TIMER_STATUS_LCDOFF     "LCDOFF"
52 #define TIMER_SLACK_ROOT                NULL
53 #define TIMER_STATUS_POWERSAVING        "POWERSAVING"
54
55 #define TIMER_CONF_FILE         "/etc/resourced/timer-slack.conf"
56 #define EXCLUDE_CONF_SECTION            "EXCLUDE_TIMER_SLACK"
57 #define EXCLUDE_CONF_NAME       "EXCLUDE_PROC_NAME"
58
59 #define TIMER_SLACK_MODE        "/timer_slack.timer_mode"
60 #define TIMER_SLACK_VALUE       "/timer_slack.min_slack_ns"
61
62 struct timer_slack_class {
63         char *name;
64         int timer_mode;
65         int slack_value;
66 };
67
68 enum {
69         TIMER_SLACK_DEFAULT,
70         TIMER_SLACK_SERVICE,
71         TIMER_SLACK_BACKGROUND,
72         TIMER_SLACK_LCDOFF,
73         TIMER_SLACK_POWERSAVIG,
74         TIMER_SLACK_MAX,
75 };
76
77 static struct timer_slack_class timer_slack[TIMER_SLACK_MAX] = {
78         {"DEFAULT", 0, 0},
79         {TIMER_SERVICE_CGROUP, 0, 0},
80         {TIMER_BACKGRD_CGROUP, 0, 0},
81         {TIMER_STATUS_LCDOFF, 0, 0},
82         {TIMER_STATUS_POWERSAVING, 0, 0},
83 };
84
85 static int current_root_timer_state = TIMER_SLACK_DEFAULT;
86
87 static const struct module_ops timer_modules_ops;
88 static const struct module_ops *timer_ops;
89
90 static int timer_slack_write(char *sub_cgroup, char *node, int val)
91 {
92         char path_buf[MAX_PATH_LENGTH];
93         int ret;
94         if (sub_cgroup) {
95                 strncpy(path_buf, TIMER_CGROUP_PATH, sizeof(TIMER_CGROUP_PATH));
96                 strcat(path_buf, "/");
97                 strcat(path_buf, sub_cgroup);
98                 ret = cgroup_write_node(path_buf, node, val);
99         } else
100                 ret = cgroup_write_node(TIMER_CGROUP_PATH, node, val);
101         return ret;
102 }
103
104 static int launch_service(void *data)
105 {
106         struct proc_status *p_data = (struct proc_status*)data;
107         int ret;
108         ret = timer_slack_write(TIMER_SERVICE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
109         _I("move to service timer slack cgroup : pid (%d), ret (%d)", p_data->pid, ret);
110         return ret;
111 }
112
113 static int wakeup_timer_state(void *data)
114 {
115         struct proc_status *p_data = (struct proc_status*)data;
116         int ret;
117         ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
118         return ret;
119 }
120
121 static int background_timer_state(void *data)
122 {
123         struct proc_status *p_data = (struct proc_status*)data;
124         int ret;
125         ret = timer_slack_write(TIMER_BACKGRD_CGROUP, CGROUP_FILE_NAME, p_data->pid);
126         return ret;
127 }
128
129 static int active_timer_state(void *data)
130 {
131         struct proc_status *p_data = (struct proc_status*)data;
132         int ret;
133         ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
134         return ret;
135 }
136
137 static int inactive_timer_state(void *data)
138 {
139         struct proc_status *p_data = (struct proc_status*)data;
140         int ret;
141         ret = timer_slack_write(TIMER_SLACK_ROOT, CGROUP_FILE_NAME, p_data->pid);
142         return ret;
143 }
144
145 static int timer_lcd_off(void *data)
146 {
147         if (current_root_timer_state == TIMER_SLACK_DEFAULT) {
148                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
149                             timer_slack[TIMER_SLACK_LCDOFF].timer_mode);
150                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
151                             timer_slack[TIMER_SLACK_LCDOFF].slack_value);
152         }
153         current_root_timer_state = TIMER_SLACK_LCDOFF;
154         return RESOURCED_ERROR_NONE;
155 }
156
157 static int timer_lcd_on(void *data)
158 {
159         if (current_root_timer_state == TIMER_SLACK_LCDOFF) {
160                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
161                             timer_slack[TIMER_SLACK_DEFAULT].timer_mode);
162                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
163                             timer_slack[TIMER_SLACK_DEFAULT].slack_value);
164                 current_root_timer_state = TIMER_SLACK_DEFAULT;
165         }
166         return RESOURCED_ERROR_NONE;
167 }
168
169 static void set_default_cgroup_value(void)
170 {
171         int i;
172         char *cgroup;
173         for (i = 0; i < TIMER_SLACK_MAX; i++) {
174                 if (i == TIMER_SLACK_DEFAULT)
175                         cgroup = TIMER_SLACK_ROOT;
176                 else if (i == TIMER_SLACK_SERVICE)
177                         cgroup = TIMER_SERVICE_CGROUP;
178                 else if (i == TIMER_SLACK_BACKGROUND)
179                         cgroup = TIMER_BACKGRD_CGROUP;
180                 else
181                         continue;
182                 timer_slack_write(cgroup, TIMER_SLACK_MODE, timer_slack[i].timer_mode);
183                 timer_slack_write(cgroup, TIMER_SLACK_VALUE, timer_slack[i].slack_value);
184         }
185 }
186
187 static int load_timer_config(struct parse_result *result, void *user_data)
188 {
189         int i;
190         pid_t pid = 0;
191
192         if (!result)
193                 return -EINVAL;
194
195         if (!strcmp(result->section, EXCLUDE_CONF_SECTION)) {
196                 if (strcmp(result->name, EXCLUDE_CONF_NAME))
197                         return RESOURCED_ERROR_NO_DATA;
198                 pid = find_pid_from_cmdline(result->value);
199                 if (pid > 0)
200                         timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, pid);
201         } else {
202                 for (i = 0; i < TIMER_SLACK_MAX; i++) {
203                         if (strcmp(result->section, timer_slack[i].name))
204                                 continue;
205                         if (!strcmp(result->name, "timer_mode"))
206                                 timer_slack[i].timer_mode = atoi(result->value);
207                         if (!strcmp(result->name, "min_slack_ns"))
208                                 timer_slack[i].slack_value = atoi(result->value);
209                 }
210         }
211        return RESOURCED_ERROR_NONE;
212 }
213
214 static void timer_slack_cgroup_init(void)
215 {
216         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_EXCLUDE_CGROUP, NULL);
217         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_SERVICE_CGROUP, NULL);
218         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_BACKGRD_CGROUP, NULL);
219
220         config_parse(TIMER_CONF_FILE, load_timer_config, NULL);
221         set_default_cgroup_value();
222 }
223
224 static int resourced_timer_slack_check_runtime_support(void *data)
225 {
226         DIR *dir = 0;
227
228         dir = opendir(TIMER_CGROUP_PATH);
229
230         if (dir) {
231                 closedir(dir);
232                 return RESOURCED_ERROR_NONE;
233         }
234         return RESOURCED_ERROR_NO_DATA;
235 }
236
237 static int resourced_timer_slack_init(void *data)
238 {
239         timer_ops = &timer_modules_ops; 
240
241         timer_slack_cgroup_init();
242
243         register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
244         register_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
245         register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
246         register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
247         register_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
248         register_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
249         register_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
250         register_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
251         return RESOURCED_ERROR_NONE;
252 }
253
254 static int resourced_timer_slack_finalize(void *data)
255 {
256         unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
257         unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
258         unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
259         unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
260         unregister_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
261         unregister_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
262         unregister_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
263         unregister_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
264         return RESOURCED_ERROR_NONE;
265 }
266
267 static const struct module_ops timer_modules_ops = {
268         .priority = MODULE_PRIORITY_NORMAL,
269         .name = TIMER_MODULE_NAME,
270         .init = resourced_timer_slack_init,
271         .exit = resourced_timer_slack_finalize,
272         .check_runtime_support = resourced_timer_slack_check_runtime_support,
273 };
274 MODULE_REGISTER(&timer_modules_ops)