2
/* libs/cutils/sched_policy.c
4
** Copyright 2007, The Android Open Source Project
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
10
** http://www.apache.org/licenses/LICENSE-2.0
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.
19
#define LOG_TAG "SchedPolicy"
27
#include <cutils/sched_policy.h>
28
#include <cutils/log.h>
30
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
31
* Call this any place a SchedPolicy is used as an input parameter.
32
* Returns the possibly re-mapped policy.
34
static inline SchedPolicy _policy(SchedPolicy p)
36
return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
39
#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
45
#define SCHED_NORMAL 0
52
#define POLICY_DEBUG 0
54
#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
56
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
58
static int __sys_supports_schedgroups = -1;
60
// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
61
static int bg_cgroup_fd = -1;
62
static int fg_cgroup_fd = -1;
64
static int system_cgroup_fd = -1;
67
/* Add tid to the scheduling group defined by the policy */
68
static int add_tid_to_cgroup(int tid, SchedPolicy policy)
83
fd = system_cgroup_fd;
92
SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
96
// specialized itoa -- works for tid > 0
98
char *end = text + sizeof(text) - 1;
102
*--ptr = '0' + (tid % 10);
106
if (write(fd, ptr, end - ptr) < 0) {
108
* If the thread is in the process of exiting,
109
* don't flag an error
113
SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
114
ptr, strerror(errno), policy);
121
static void __initialize(void) {
123
if (!access("/dev/cpuctl/tasks", F_OK)) {
124
__sys_supports_schedgroups = 1;
126
#if CAN_SET_SP_SYSTEM
127
filename = "/dev/cpuctl/tasks";
128
system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
129
if (system_cgroup_fd < 0) {
130
SLOGV("open of %s failed: %s\n", filename, strerror(errno));
134
filename = "/dev/cpuctl/apps/tasks";
135
fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
136
if (fg_cgroup_fd < 0) {
137
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
140
filename = "/dev/cpuctl/apps/bg_non_interactive/tasks";
141
bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
142
if (bg_cgroup_fd < 0) {
143
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
146
__sys_supports_schedgroups = 0;
151
* Try to get the scheduler group.
153
* The data from /proc/<pid>/cgroup looks (something) like:
154
* 2:cpu:/bg_non_interactive
157
* We return the part after the "/", which will be an empty string for
158
* the default cgroup. If the string is longer than "bufLen", the string
161
static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
163
#ifdef HAVE_ANDROID_OS
168
snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
169
if (!(fp = fopen(pathBuf, "r"))) {
173
while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
174
char *next = lineBuf;
179
/* Junk the first field */
180
if (!strsep(&next, ":")) {
184
if (!(subsys = strsep(&next, ":"))) {
188
if (strcmp(subsys, "cpu")) {
189
/* Not the subsys we're looking for */
193
if (!(grp = strsep(&next, ":"))) {
196
grp++; /* Drop the leading '/' */
198
grp[len-1] = '\0'; /* Drop the trailing '\n' */
203
strncpy(buf, grp, len);
209
SLOGE("Failed to find cpu subsys");
213
SLOGE("Bad cgroup data {%s}", lineBuf);
222
int get_sched_policy(int tid, SchedPolicy *policy)
229
pthread_once(&the_once, __initialize);
231
if (__sys_supports_schedgroups) {
233
if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
235
if (grpBuf[0] == '\0') {
237
} else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
238
*policy = SP_BACKGROUND;
239
} else if (!strcmp(grpBuf, "apps")) {
240
*policy = SP_FOREGROUND;
246
int rc = sched_getscheduler(tid);
249
else if (rc == SCHED_NORMAL)
250
*policy = SP_FOREGROUND;
251
else if (rc == SCHED_BATCH)
252
*policy = SP_BACKGROUND;
261
int set_sched_policy(int tid, SchedPolicy policy)
268
policy = _policy(policy);
269
pthread_once(&the_once, __initialize);
274
char thread_name[255];
277
sprintf(statfile, "/proc/%d/stat", tid);
278
memset(thread_name, 0, sizeof(thread_name));
280
fd = open(statfile, O_RDONLY);
282
int rc = read(fd, statline, 1023);
288
for (p = statline; *p != '('; p++);
290
for (q = p; *q != ')'; q++);
292
strncpy(thread_name, p, (q-p));
296
SLOGD("vvv tid %d (%s)", tid, thread_name);
301
SLOGD("^^^ tid %d (%s)", tid, thread_name);
304
SLOGD("/// tid %d (%s)", tid, thread_name);
307
SLOGD("??? tid %d (%s)", tid, thread_name);
312
if (__sys_supports_schedgroups) {
313
if (add_tid_to_cgroup(tid, policy)) {
314
if (errno != ESRCH && errno != ENOENT)
318
struct sched_param param;
320
param.sched_priority = 0;
321
sched_setscheduler(tid,
322
(policy == SP_BACKGROUND) ?
323
SCHED_BATCH : SCHED_NORMAL,
332
/* Stubs for non-Android targets. */
334
int set_sched_policy(int tid, SchedPolicy policy)
339
int get_sched_policy(int tid, SchedPolicy *policy)
341
*policy = SP_SYSTEM_DEFAULT;
347
const char *get_sched_policy_name(SchedPolicy policy)
349
policy = _policy(policy);
350
static const char * const strings[SP_CNT] = {
351
[SP_BACKGROUND] = "bg",
352
[SP_FOREGROUND] = "fg",
354
[SP_AUDIO_APP] = "aa",
355
[SP_AUDIO_SYS] = "as",
357
if ((policy < SP_CNT) && (strings[policy] != NULL))
358
return strings[policy];