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