blob: 6d2727ba48c0b595699a000ffe2f0677de586c95 [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>
Raphael0384a982009-09-15 17:10:17 -070025
San Mehatd2e4e462009-10-29 11:48:00 -070026#define LOG_TAG "SchedPolicy"
27#include "cutils/log.h"
28
Raphael0384a982009-09-15 17:10:17 -070029#ifdef HAVE_SCHED_H
30
San Mehat493dad92009-09-12 10:06:57 -070031#include <sched.h>
San Mehat493dad92009-09-12 10:06:57 -070032
33#include <cutils/sched_policy.h>
34
San Mehat3cd5b662009-09-14 16:05:24 -070035#ifndef SCHED_NORMAL
36 #define SCHED_NORMAL 0
37#endif
38
39#ifndef SCHED_BATCH
40 #define SCHED_BATCH 3
41#endif
42
San Mehat805d67a2009-10-29 13:56:26 -070043#define POLICY_DEBUG 0
San Mehatd2e4e462009-10-29 11:48:00 -070044
San Mehatc0dfca72009-10-27 11:52:55 -070045static int __sys_supports_schedgroups = -1;
46
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070047/* Add tid to the group defined by dev_path ("/dev/cpuctl/.../tasks") */
48static int add_tid_to_cgroup(int tid, const char *dev_path)
San Mehat493dad92009-09-12 10:06:57 -070049{
50 int fd;
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070051 if ((fd = open(dev_path, O_WRONLY)) < 0) {
52 SLOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", dev_path,
San Mehatc1c38dd2009-12-03 12:19:12 -080053 strerror(errno));
San Mehat493dad92009-09-12 10:06:57 -070054 return -1;
San Mehat805d67a2009-10-29 13:56:26 -070055 }
San Mehat493dad92009-09-12 10:06:57 -070056
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070057 // specialized itoa -- works for tid > 0
58 char text[22];
59 char *end = text + sizeof(text) - 1;
60 char *ptr = end;
61 *ptr = '\0';
62 while (tid > 0) {
63 *--ptr = '0' + (tid % 10);
64 tid = tid / 10;
65 }
66
67 if (write(fd, ptr, end - ptr) < 0) {
San Mehat493dad92009-09-12 10:06:57 -070068 close(fd);
San Mehatc1c38dd2009-12-03 12:19:12 -080069 /*
70 * If the thread is in the process of exiting,
71 * don't flag an error
72 */
73 if (errno == ESRCH)
74 return 0;
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070075 SLOGW("add_tid_to_cgroup failed to write '%s' to '%s' (%s)\n",
76 ptr, dev_path, strerror(errno));
San Mehat493dad92009-09-12 10:06:57 -070077 return -1;
78 }
79
80 close(fd);
81 return 0;
82}
83
San Mehatc0dfca72009-10-27 11:52:55 -070084static inline void initialize()
San Mehat493dad92009-09-12 10:06:57 -070085{
San Mehat493dad92009-09-12 10:06:57 -070086 if (__sys_supports_schedgroups < 0) {
87 if (!access("/dev/cpuctl/tasks", F_OK)) {
88 __sys_supports_schedgroups = 1;
89 } else {
90 __sys_supports_schedgroups = 0;
91 }
92 }
San Mehatc0dfca72009-10-27 11:52:55 -070093}
94
95/*
96 * Try to get the scheduler group.
97 *
San Mehat503df202010-03-02 17:09:56 -080098 * The data from /proc/<pid>/cgroup looks (something) like:
San Mehatc0dfca72009-10-27 11:52:55 -070099 * 2:cpu:/bg_non_interactive
San Mehat503df202010-03-02 17:09:56 -0800100 * 1:cpuacct:/
San Mehatc0dfca72009-10-27 11:52:55 -0700101 *
102 * We return the part after the "/", which will be an empty string for
103 * the default cgroup. If the string is longer than "bufLen", the string
104 * will be truncated.
105 */
106static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
107{
108#ifdef HAVE_ANDROID_OS
109 char pathBuf[32];
San Mehat503df202010-03-02 17:09:56 -0800110 char lineBuf[256];
111 FILE *fp;
San Mehatc0dfca72009-10-27 11:52:55 -0700112
113 snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
San Mehat503df202010-03-02 17:09:56 -0800114 if (!(fp = fopen(pathBuf, "r"))) {
San Mehatc0dfca72009-10-27 11:52:55 -0700115 return -1;
116 }
117
San Mehat503df202010-03-02 17:09:56 -0800118 while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
119 char *next = lineBuf;
120 char *subsys;
121 char *grp;
122 size_t len;
San Mehatc0dfca72009-10-27 11:52:55 -0700123
San Mehat503df202010-03-02 17:09:56 -0800124 /* Junk the first field */
125 if (!strsep(&next, ":")) {
126 goto out_bad_data;
127 }
San Mehatc0dfca72009-10-27 11:52:55 -0700128
San Mehat503df202010-03-02 17:09:56 -0800129 if (!(subsys = strsep(&next, ":"))) {
130 goto out_bad_data;
131 }
132
133 if (strcmp(subsys, "cpu")) {
134 /* Not the subsys we're looking for */
135 continue;
136 }
137
138 if (!(grp = strsep(&next, ":"))) {
139 goto out_bad_data;
140 }
141 grp++; /* Drop the leading '/' */
142 len = strlen(grp);
143 grp[len-1] = '\0'; /* Drop the trailing '\n' */
144
145 if (bufLen <= len) {
146 len = bufLen - 1;
147 }
148 strncpy(buf, grp, len);
149 buf[len] = '\0';
150 fclose(fp);
151 return 0;
San Mehatc0dfca72009-10-27 11:52:55 -0700152 }
153
San Mehat7e8529a2010-03-25 09:31:42 -0700154 SLOGE("Failed to find cpu subsys");
San Mehat503df202010-03-02 17:09:56 -0800155 fclose(fp);
156 return -1;
157 out_bad_data:
San Mehat7e8529a2010-03-25 09:31:42 -0700158 SLOGE("Bad cgroup data {%s}", lineBuf);
San Mehat503df202010-03-02 17:09:56 -0800159 fclose(fp);
160 return -1;
San Mehatc0dfca72009-10-27 11:52:55 -0700161#else
162 errno = ENOSYS;
163 return -1;
164#endif
165}
166
167int get_sched_policy(int tid, SchedPolicy *policy)
168{
169 initialize();
170
171 if (__sys_supports_schedgroups) {
172 char grpBuf[32];
173 if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
174 return -1;
175 if (grpBuf[0] == '\0') {
176 *policy = SP_FOREGROUND;
177 } else if (!strcmp(grpBuf, "bg_non_interactive")) {
178 *policy = SP_BACKGROUND;
179 } else {
180 errno = ERANGE;
181 return -1;
182 }
183 } else {
184 int rc = sched_getscheduler(tid);
185 if (rc < 0)
186 return -1;
187 else if (rc == SCHED_NORMAL)
188 *policy = SP_FOREGROUND;
189 else if (rc == SCHED_BATCH)
190 *policy = SP_BACKGROUND;
191 else {
192 errno = ERANGE;
193 return -1;
194 }
195 }
196 return 0;
197}
198
199int set_sched_policy(int tid, SchedPolicy policy)
200{
201 initialize();
San Mehat493dad92009-09-12 10:06:57 -0700202
San Mehatd2e4e462009-10-29 11:48:00 -0700203#if POLICY_DEBUG
204 char statfile[64];
205 char statline[1024];
206 char thread_name[255];
207 int fd;
208
209 sprintf(statfile, "/proc/%d/stat", tid);
210 memset(thread_name, 0, sizeof(thread_name));
211
212 fd = open(statfile, O_RDONLY);
213 if (fd >= 0) {
214 int rc = read(fd, statline, 1023);
215 close(fd);
216 statline[rc] = 0;
217 char *p = statline;
218 char *q;
219
220 for (p = statline; *p != '('; p++);
221 p++;
222 for (q = p; *q != ')'; q++);
223
224 strncpy(thread_name, p, (q-p));
225 }
226 if (policy == SP_BACKGROUND) {
San Mehat7e8529a2010-03-25 09:31:42 -0700227 SLOGD("vvv tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700228 } else if (policy == SP_FOREGROUND) {
San Mehat7e8529a2010-03-25 09:31:42 -0700229 SLOGD("^^^ tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700230 } else {
San Mehat7e8529a2010-03-25 09:31:42 -0700231 SLOGD("??? tid %d (%s)", tid, thread_name);
San Mehatd2e4e462009-10-29 11:48:00 -0700232 }
233#endif
234
San Mehat493dad92009-09-12 10:06:57 -0700235 if (__sys_supports_schedgroups) {
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -0700236 const char *dev_path;
San Mehat493dad92009-09-12 10:06:57 -0700237 if (policy == SP_BACKGROUND) {
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -0700238 dev_path = "/dev/cpuctl/bg_non_interactive/tasks";
239 } else {
240 dev_path = "/dev/cpuctl/tasks";
San Mehat493dad92009-09-12 10:06:57 -0700241 }
242
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -0700243 if (add_tid_to_cgroup(tid, dev_path)) {
San Mehat493dad92009-09-12 10:06:57 -0700244 if (errno != ESRCH && errno != ENOENT)
245 return -errno;
246 }
247 } else {
248 struct sched_param param;
249
250 param.sched_priority = 0;
251 sched_setscheduler(tid,
252 (policy == SP_BACKGROUND) ?
253 SCHED_BATCH : SCHED_NORMAL,
254 &param);
255 }
256
257 return 0;
258}
Raphael0384a982009-09-15 17:10:17 -0700259
260#endif /* HAVE_SCHED_H */