sched_policy.c revision 805d67ab11c1bb21d494459d6167f5f67f0002eb
1 2/* 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> 25 26#define LOG_TAG "SchedPolicy" 27#include "cutils/log.h" 28 29#ifdef HAVE_SCHED_H 30 31#include <sched.h> 32 33#include <cutils/sched_policy.h> 34 35#ifndef SCHED_NORMAL 36 #define SCHED_NORMAL 0 37#endif 38 39#ifndef SCHED_BATCH 40 #define SCHED_BATCH 3 41#endif 42 43#define POLICY_DEBUG 0 44 45static int __sys_supports_schedgroups = -1; 46 47static 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 LOGE("add_tid_to_cgroup failed to open '%s' (%s)\n", path, strerror(errno)); 57 return -1; 58 } 59 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 70static inline void initialize() 71{ 72 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 } 79} 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(); 164 165#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 197 if (__sys_supports_schedgroups) { 198 const char *grp = ""; 199 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 ¶m); 216 } 217 218 return 0; 219} 220 221#endif /* HAVE_SCHED_H */ 222