blob: 8357bba33429726a7f565e986a60ac9dec6537ad [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 Mehatd2e4e462009-10-29 11:48:00 -070043#define POLICY_DEBUG 1
44
San Mehatc0dfca72009-10-27 11:52:55 -070045static int __sys_supports_schedgroups = -1;
46
San Mehat493dad92009-09-12 10:06:57 -070047static int add_tid_to_cgroup(int tid, const char *grp_name)
48{
49 int fd;
50 char path[255];
51 char text[64];
52
53 sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
54
55 if ((fd = open(path, O_WRONLY)) < 0)
56 return -1;
57
58 sprintf(text, "%d", tid);
59 if (write(fd, text, strlen(text)) < 0) {
60 close(fd);
61 return -1;
62 }
63
64 close(fd);
65 return 0;
66}
67
San Mehatc0dfca72009-10-27 11:52:55 -070068static inline void initialize()
San Mehat493dad92009-09-12 10:06:57 -070069{
San Mehat493dad92009-09-12 10:06:57 -070070 if (__sys_supports_schedgroups < 0) {
71 if (!access("/dev/cpuctl/tasks", F_OK)) {
72 __sys_supports_schedgroups = 1;
73 } else {
74 __sys_supports_schedgroups = 0;
75 }
76 }
San Mehatc0dfca72009-10-27 11:52:55 -070077}
78
79/*
80 * Try to get the scheduler group.
81 *
82 * The data from /proc/<pid>/cgroup looks like:
83 * 2:cpu:/bg_non_interactive
84 *
85 * We return the part after the "/", which will be an empty string for
86 * the default cgroup. If the string is longer than "bufLen", the string
87 * will be truncated.
88 */
89static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
90{
91#ifdef HAVE_ANDROID_OS
92 char pathBuf[32];
93 char readBuf[256];
94 ssize_t count;
95 int fd;
96
97 snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
98 if ((fd = open(pathBuf, O_RDONLY)) < 0) {
99 return -1;
100 }
101
102 count = read(fd, readBuf, sizeof(readBuf));
103 if (count <= 0) {
104 close(fd);
105 errno = ENODATA;
106 return -1;
107 }
108 close(fd);
109
110 readBuf[--count] = '\0'; /* remove the '\n', now count==strlen */
111
112 char* cp = strchr(readBuf, '/');
113 if (cp == NULL) {
114 readBuf[sizeof(readBuf)-1] = '\0';
115 errno = ENODATA;
116 return -1;
117 }
118
119 memcpy(buf, cp+1, count); /* count-1 for cp+1, count+1 for NUL */
120 return 0;
121#else
122 errno = ENOSYS;
123 return -1;
124#endif
125}
126
127int get_sched_policy(int tid, SchedPolicy *policy)
128{
129 initialize();
130
131 if (__sys_supports_schedgroups) {
132 char grpBuf[32];
133 if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
134 return -1;
135 if (grpBuf[0] == '\0') {
136 *policy = SP_FOREGROUND;
137 } else if (!strcmp(grpBuf, "bg_non_interactive")) {
138 *policy = SP_BACKGROUND;
139 } else {
140 errno = ERANGE;
141 return -1;
142 }
143 } else {
144 int rc = sched_getscheduler(tid);
145 if (rc < 0)
146 return -1;
147 else if (rc == SCHED_NORMAL)
148 *policy = SP_FOREGROUND;
149 else if (rc == SCHED_BATCH)
150 *policy = SP_BACKGROUND;
151 else {
152 errno = ERANGE;
153 return -1;
154 }
155 }
156 return 0;
157}
158
159int set_sched_policy(int tid, SchedPolicy policy)
160{
161 initialize();
San Mehat493dad92009-09-12 10:06:57 -0700162
San Mehatd2e4e462009-10-29 11:48:00 -0700163#if POLICY_DEBUG
164 char statfile[64];
165 char statline[1024];
166 char thread_name[255];
167 int fd;
168
169 sprintf(statfile, "/proc/%d/stat", tid);
170 memset(thread_name, 0, sizeof(thread_name));
171
172 fd = open(statfile, O_RDONLY);
173 if (fd >= 0) {
174 int rc = read(fd, statline, 1023);
175 close(fd);
176 statline[rc] = 0;
177 char *p = statline;
178 char *q;
179
180 for (p = statline; *p != '('; p++);
181 p++;
182 for (q = p; *q != ')'; q++);
183
184 strncpy(thread_name, p, (q-p));
185 }
186 if (policy == SP_BACKGROUND) {
187 LOGD("vvv tid %d (%s)", tid, thread_name);
188 } else if (policy == SP_FOREGROUND) {
189 LOGD("^^^ tid %d (%s)", tid, thread_name);
190 } else {
191 LOGD("??? tid %d (%s)", tid, thread_name);
192 }
193#endif
194
San Mehat493dad92009-09-12 10:06:57 -0700195 if (__sys_supports_schedgroups) {
196 const char *grp = NULL;
197
198 if (policy == SP_BACKGROUND) {
199 grp = "bg_non_interactive";
200 }
201
202 if (add_tid_to_cgroup(tid, grp)) {
203 if (errno != ESRCH && errno != ENOENT)
204 return -errno;
205 }
206 } else {
207 struct sched_param param;
208
209 param.sched_priority = 0;
210 sched_setscheduler(tid,
211 (policy == SP_BACKGROUND) ?
212 SCHED_BATCH : SCHED_NORMAL,
213 &param);
214 }
215
216 return 0;
217}
Raphael0384a982009-09-15 17:10:17 -0700218
219#endif /* HAVE_SCHED_H */