tizen 2.3.1 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                 snprintf(path_buf, sizeof(path_buf), "%s/%s", TIMER_CGROUP_PATH, sub_cgroup);
96                 ret = cgroup_write_node(path_buf, node, val);
97         } else
98                 ret = cgroup_write_node(TIMER_CGROUP_PATH, node, val);
99         return ret;
100 }
101
102 static int launch_service(void *data)
103 {
104         struct proc_status *p_data = (struct proc_status*)data;
105         int ret;
106         ret = timer_slack_write(TIMER_SERVICE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
107         _I("move to service timer slack cgroup : pid (%d), ret (%d)", p_data->pid, ret);
108         return ret;
109 }
110
111 static int wakeup_timer_state(void *data)
112 {
113         struct proc_status *p_data = (struct proc_status*)data;
114         int ret;
115         ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
116         return ret;
117 }
118
119 static int background_timer_state(void *data)
120 {
121         struct proc_status *p_data = (struct proc_status*)data;
122         int ret;
123         ret = timer_slack_write(TIMER_BACKGRD_CGROUP, CGROUP_FILE_NAME, p_data->pid);
124         return ret;
125 }
126
127 static int active_timer_state(void *data)
128 {
129         struct proc_status *p_data = (struct proc_status*)data;
130         int ret;
131         ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
132         return ret;
133 }
134
135 static int inactive_timer_state(void *data)
136 {
137         struct proc_status *p_data = (struct proc_status*)data;
138         int ret;
139         ret = timer_slack_write(TIMER_SLACK_ROOT, CGROUP_FILE_NAME, p_data->pid);
140         return ret;
141 }
142
143 static int timer_lcd_off(void *data)
144 {
145         if (current_root_timer_state == TIMER_SLACK_DEFAULT) {
146                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
147                             timer_slack[TIMER_SLACK_LCDOFF].timer_mode);
148                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
149                             timer_slack[TIMER_SLACK_LCDOFF].slack_value);
150         }
151         current_root_timer_state = TIMER_SLACK_LCDOFF;
152         return RESOURCED_ERROR_NONE;
153 }
154
155 static int timer_lcd_on(void *data)
156 {
157         if (current_root_timer_state == TIMER_SLACK_LCDOFF) {
158                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
159                             timer_slack[TIMER_SLACK_DEFAULT].timer_mode);
160                 timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
161                             timer_slack[TIMER_SLACK_DEFAULT].slack_value);
162                 current_root_timer_state = TIMER_SLACK_DEFAULT;
163         }
164         return RESOURCED_ERROR_NONE;
165 }
166
167 static void set_default_cgroup_value(void)
168 {
169         int i;
170         char *cgroup;
171         for (i = 0; i < TIMER_SLACK_MAX; i++) {
172                 if (i == TIMER_SLACK_DEFAULT)
173                         cgroup = TIMER_SLACK_ROOT;
174                 else if (i == TIMER_SLACK_SERVICE)
175                         cgroup = TIMER_SERVICE_CGROUP;
176                 else if (i == TIMER_SLACK_BACKGROUND)
177                         cgroup = TIMER_BACKGRD_CGROUP;
178                 else
179                         continue;
180                 timer_slack_write(cgroup, TIMER_SLACK_MODE, timer_slack[i].timer_mode);
181                 timer_slack_write(cgroup, TIMER_SLACK_VALUE, timer_slack[i].slack_value);
182         }
183 }
184
185 static int load_timer_config(struct parse_result *result, void *user_data)
186 {
187         int i;
188         pid_t pid = 0;
189
190         if (!result)
191                 return -EINVAL;
192
193         if (!strcmp(result->section, EXCLUDE_CONF_SECTION)) {
194                 if (strcmp(result->name, EXCLUDE_CONF_NAME))
195                         return RESOURCED_ERROR_NO_DATA;
196                 pid = find_pid_from_cmdline(result->value);
197                 if (pid > 0)
198                         timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, pid);
199         } else {
200                 for (i = 0; i < TIMER_SLACK_MAX; i++) {
201                         if (strcmp(result->section, timer_slack[i].name))
202                                 continue;
203                         if (!strcmp(result->name, "timer_mode"))
204                                 timer_slack[i].timer_mode = atoi(result->value);
205                         if (!strcmp(result->name, "min_slack_ns"))
206                                 timer_slack[i].slack_value = atoi(result->value);
207                 }
208         }
209        return RESOURCED_ERROR_NONE;
210 }
211
212 static void timer_slack_cgroup_init(void)
213 {
214         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_EXCLUDE_CGROUP, NULL);
215         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_SERVICE_CGROUP, NULL);
216         make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_BACKGRD_CGROUP, NULL);
217
218         config_parse(TIMER_CONF_FILE, load_timer_config, NULL);
219         set_default_cgroup_value();
220 }
221
222 static int resourced_timer_slack_check_runtime_support(void *data)
223 {
224         DIR *dir = 0;
225
226         dir = opendir(TIMER_CGROUP_PATH);
227
228         if (dir) {
229                 closedir(dir);
230                 return RESOURCED_ERROR_NONE;
231         }
232         return RESOURCED_ERROR_NO_DATA;
233 }
234
235 static int resourced_timer_slack_init(void *data)
236 {
237         timer_ops = &timer_modules_ops; 
238
239         timer_slack_cgroup_init();
240
241         register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
242         register_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
243         register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
244         register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
245         register_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
246         register_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
247         register_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
248         register_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
249         return RESOURCED_ERROR_NONE;
250 }
251
252 static int resourced_timer_slack_finalize(void *data)
253 {
254         unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
255         unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
256         unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
257         unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
258         unregister_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
259         unregister_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
260         unregister_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
261         unregister_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
262         return RESOURCED_ERROR_NONE;
263 }
264
265 static const struct module_ops timer_modules_ops = {
266         .priority = MODULE_PRIORITY_NORMAL,
267         .name = TIMER_MODULE_NAME,
268         .init = resourced_timer_slack_init,
269         .exit = resourced_timer_slack_finalize,
270         .check_runtime_support = resourced_timer_slack_check_runtime_support,
271 };
272 MODULE_REGISTER(&timer_modules_ops)