blob: 78e0943763a6b6de51b852a9b3f747549ba2a74e [file] [log] [blame]
Raphael0384a982009-09-15 17:10:17 -07001
San Mehat493dad92009-09-12 10:06:57 -07002/* libs/cutils/sched_policy.c
3**
4** Copyright 2007, The Android Open Source Project
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#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include <errno.h>
24#include <fcntl.h>
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070025#include <pthread.h>
Raphael0384a982009-09-15 17:10:17 -070026
San Mehatd2e4e462009-10-29 11:48:00 -070027#define LOG_TAG "SchedPolicy"
28#include "cutils/log.h"
29
Raphael0384a982009-09-15 17:10:17 -070030#ifdef HAVE_SCHED_H
31
San Mehat493dad92009-09-12 10:06:57 -070032#include <sched.h>
San Mehat493dad92009-09-12 10:06:57 -070033
34#include <cutils/sched_policy.h>
35
San Mehat3cd5b662009-09-14 16:05:24 -070036#ifndef SCHED_NORMAL
37 #define SCHED_NORMAL 0
38#endif
39
40#ifndef SCHED_BATCH
41 #define SCHED_BATCH 3
42#endif
43
San Mehat805d67a2009-10-29 13:56:26 -070044#define POLICY_DEBUG 0
San Mehatd2e4e462009-10-29 11:48:00 -070045
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070046static pthread_once_t the_once = PTHREAD_ONCE_INIT;
47
San Mehatc0dfca72009-10-27 11:52:55 -070048static int __sys_supports_schedgroups = -1;
49
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070050// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
51static int normal_cgroup_fd = -1;
52static int bg_cgroup_fd = -1;
53
54/* Add tid to the scheduling group defined by the policy */
55static int add_tid_to_cgroup(int tid, SchedPolicy policy)
San Mehat493dad92009-09-12 10:06:57 -070056{
57 int fd;
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070058
59 if (policy == SP_BACKGROUND) {
60 fd = bg_cgroup_fd;
61 } else {
62 fd = normal_cgroup_fd;
63 }
64
65 if (fd < 0) {
66 SLOGE("add_tid_to_cgroup failed; background=%d\n",
67 policy == SP_BACKGROUND ? 1 : 0);
San Mehat493dad92009-09-12 10:06:57 -070068 return -1;
San Mehat805d67a2009-10-29 13:56:26 -070069 }
San Mehat493dad92009-09-12 10:06:57 -070070
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070071 // specialized itoa -- works for tid > 0
72 char text[22];
73 char *end = text + sizeof(text) - 1;
74 char *ptr = end;
75 *ptr = '\0';
76 while (tid > 0) {
77 *--ptr = '0' + (tid % 10);
78 tid = tid / 10;
79 }
80
81 if (write(fd, ptr, end - ptr) < 0) {
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070082 /*
83 * If the thread is in the process of exiting,
84 * don't flag an error
85 */
86 if (errno == ESRCH)
87 return 0;
88 SLOGW("add_tid_to_cgroup failed to write '%s' (%s); background=%d\n",
89 ptr, strerror(errno), policy == SP_BACKGROUND ? 1 : 0);
San Mehat493dad92009-09-12 10:06:57 -070090 return -1;
91 }
92
San Mehat493dad92009-09-12 10:06:57 -070093 return 0;
94}
95
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070096static void __initialize(void) {
97 char* filename;
98 if (!access("/dev/cpuctl/tasks", F_OK)) {
99 __sys_supports_schedgroups = 1;
100
101 filename = "/dev/cpuctl/tasks";
102 normal_cgroup_fd = open(filename, O_WRONLY);
103 if (normal_cgroup_fd < 0) {
104 SLOGE("open of %s failed: %s\n", filename, strerror(errno));
San Mehat493dad92009-09-12 10:06:57 -0700105 }
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700106
107 filename = "/dev/cpuctl/bg_non_interactive/tasks";
108 bg_cgroup_fd = open(filename, O_WRONLY);
109 if (bg_cgroup_fd < 0) {
110 SLOGE("open of %s failed: %s\n", filename, strerror(errno));
111 }
112 } else {
113 __sys_supports_schedgroups = 0;
San Mehat493dad92009-09-12 10:06:57 -0700114 }
San Mehatc0dfca72009-10-27 11:52:55 -0700115}
116
117/*
118 * Try to get the scheduler group.
119 *
San Mehat503df202010-03-02 17:09:56 -0800120 * The data from /proc/<pid>/cgroup looks (something) like:
San Mehatc0dfca72009-10-27 11:52:55 -0700121 * 2:cpu:/bg_non_interactive
San Mehat503df202010-03-02 17:09:56 -0800122 * 1:cpuacct:/
San Mehatc0dfca72009-10-27 11:52:55 -0700123 *
124 * We return the part after the "/", which will be an empty string for
125 * the default cgroup. If the string is longer than "bufLen", the string
126 * will be truncated.
127 */
128static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
129{
130#ifdef HAVE_ANDROID_OS
131 char pathBuf[32];
San Mehat503df202010-03-02 17:09:56 -0800132 char lineBuf[256];
133 FILE *fp;
San Mehatc0dfca72009-10-27 11:52:55 -0700134
135 snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
San Mehat503df202010-03-02 17:09:56 -0800136 if (!(fp = fopen(pathBuf, "r"))) {
San Mehatc0dfca72009-10-27 11:52:55 -0700137 return -1;
138 }
139
San Mehat503df202010-03-02 17:09:56 -0800140 while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
141 char *next = lineBuf;
142 char *subsys;
143 char *grp;
144 size_t len;
San Mehatc0dfca72009-10-27 11:52:55 -0700145
San Mehat503df202010-03-02 17:09:56 -0800146 /* Junk the first field */
147 if (!strsep(&next, ":")) {
148 goto out_bad_data;
149 }
San Mehatc0dfca72009-10-27 11:52:55 -0700150
San Mehat503df202010-03-02 17:09:56 -0800151 if (!(subsys = strsep(&next, ":"))) {
152 goto out_bad_data;
153 }
154
155 if (strcmp(subsys, "cpu")) {
156 /* Not the subsys we're looking for */
157 continue;
158 }
159
160 if (!(grp = strsep(&next, ":"))) {
161 goto out_bad_data;
162 }
163 grp++; /* Drop the leading '/' */
164 len = strlen(grp);
165 grp[len-1] = '\0'; /* Drop the trailing '\n' */
166
167 if (bufLen <= len) {
168 len = bufLen - 1;
169 }
170 strncpy(buf, grp, len);
171 buf[len] = '\0';
172 fclose(fp);
173 return 0;
San Mehatc0dfca72009-10-27 11:52:55 -0700174 }
175
San Mehat7e8529a2010-03-25 09:31:42 -0700176 SLOGE("Failed to find cpu subsys");
San Mehat503df202010-03-02 17:09:56 -0800177 fclose(fp);
178 return -1;
179 out_bad_data:
San Mehat7e8529a2010-03-25 09:31:42 -0700180 SLOGE("Bad cgroup data {%s}", lineBuf);
San Mehat503df202010-03-02 17:09:56 -0800181 fclose(fp);
182 return -1;
San Mehatc0dfca72009-10-27 11:52:55 -0700183#else
184 errno = ENOSYS;
185 return -1;
186#endif
187}
188
189int get_sched_policy(int tid, SchedPolicy *policy)
190{
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700191 pthread_once(&the_once, __initialize);
San Mehatc0dfca72009-10-27 11:52:55 -0700192
193 if (__sys_supports_schedgroups) {
194 char grpBuf[32];
195 if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
196 return -1;
197 if (grpBuf[0] == '\0') {
198 *policy = SP_FOREGROUND;
199 } else if (!strcmp(grpBuf, "bg_non_interactive")) {
200 *policy = SP_BACKGROUND;
201 } else {
202 errno = ERANGE;
203 return -1;
204 }
205 } else {
206 int rc = sched_getscheduler(tid);
207 if (rc < 0)
208 return -1;
209 else if (rc == SCHED_NORMAL)
210 *policy = SP_FOREGROUND;
211 else if (rc == SCHED_BATCH)
212 *policy = SP_BACKGROUND;
213 else {
214 errno = ERANGE;
215 return -1;
216 }
217 }
218 return 0;
219}
220
221int set_sched_policy(int tid, SchedPolicy policy)
222{
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700223 pthread_once(&the_once, __initialize);
San Mehat493dad92009-09-12 10:06:57 -0700224
San Mehatd2e4e462009-10-29 11:48:00 -0700225#if POLICY_DEBUG
226 char statfile[64];
227 char statline[1024];
228 char thread_name[255];
229 int fd;
230
231 sprintf(statfile, "/proc/%d/stat", tid);
232 memset(thread_name, 0, sizeof(thread_name));
233
234 fd = open(statfile, O_RDONLY);
235 if (fd >= 0) {
236 int rc = read(fd, statline, 1023);
237 close(fd);
238 statline[rc] = 0;
239 char *p = statline;
240 char *q;
241
242 for (p = statline; *p != '('; p++);
243 p++;
244 for (q = p; *q != ')'; q++);
245
246 strncpy(thread_name, p, (q-p));
247 }
248 if (policy == SP_BACKGROUND) {
San Mehat7e8529a2010-03-25 09:31:42 -0700249 SLOGD("vvv tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700250 } else if (policy == SP_FOREGROUND) {
San Mehat7e8529a2010-03-25 09:31:42 -0700251 SLOGD("^^^ tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700252 } else {
San Mehat7e8529a2010-03-25 09:31:42 -0700253 SLOGD("??? tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700254 }
255#endif
256
San Mehat493dad92009-09-12 10:06:57 -0700257 if (__sys_supports_schedgroups) {
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700258 if (add_tid_to_cgroup(tid, policy)) {
San Mehat493dad92009-09-12 10:06:57 -0700259 if (errno != ESRCH && errno != ENOENT)
260 return -errno;
261 }
262 } else {
263 struct sched_param param;
264
265 param.sched_priority = 0;
266 sched_setscheduler(tid,
267 (policy == SP_BACKGROUND) ?
268 SCHED_BATCH : SCHED_NORMAL,
269 &param);
270 }
271
272 return 0;
273}
Raphael0384a982009-09-15 17:10:17 -0700274
275#endif /* HAVE_SCHED_H */