sched_policy.c revision 503df2075991cd03ddf43d14e05768a2138b9028
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, 57 strerror(errno)); 58 return -1; 59 } 60 61 sprintf(text, "%d", tid); 62 if (write(fd, text, strlen(text)) < 0) { 63 close(fd); 64 /* 65 * If the thread is in the process of exiting, 66 * don't flag an error 67 */ 68 if (errno == ESRCH) 69 return 0; 70 LOGW("add_tid_to_cgroup failed to write '%s' (%s)\n", path, 71 strerror(errno)); 72 return -1; 73 } 74 75 close(fd); 76 return 0; 77} 78 79static inline void initialize() 80{ 81 if (__sys_supports_schedgroups < 0) { 82 if (!access("/dev/cpuctl/tasks", F_OK)) { 83 __sys_supports_schedgroups = 1; 84 } else { 85 __sys_supports_schedgroups = 0; 86 } 87 } 88} 89 90/* 91 * Try to get the scheduler group. 92 * 93 * The data from /proc/<pid>/cgroup looks (something) like: 94 * 2:cpu:/bg_non_interactive 95 * 1:cpuacct:/ 96 * 97 * We return the part after the "/", which will be an empty string for 98 * the default cgroup. If the string is longer than "bufLen", the string 99 * will be truncated. 100 */ 101static int getSchedulerGroup(int tid, char* buf, size_t bufLen) 102{ 103#ifdef HAVE_ANDROID_OS 104 char pathBuf[32]; 105 char lineBuf[256]; 106 FILE *fp; 107 108 snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid); 109 if (!(fp = fopen(pathBuf, "r"))) { 110 return -1; 111 } 112 113 while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) { 114 char *next = lineBuf; 115 char *subsys; 116 char *grp; 117 size_t len; 118 119 /* Junk the first field */ 120 if (!strsep(&next, ":")) { 121 goto out_bad_data; 122 } 123 124 if (!(subsys = strsep(&next, ":"))) { 125 goto out_bad_data; 126 } 127 128 if (strcmp(subsys, "cpu")) { 129 /* Not the subsys we're looking for */ 130 continue; 131 } 132 133 if (!(grp = strsep(&next, ":"))) { 134 goto out_bad_data; 135 } 136 grp++; /* Drop the leading '/' */ 137 len = strlen(grp); 138 grp[len-1] = '\0'; /* Drop the trailing '\n' */ 139 140 if (bufLen <= len) { 141 len = bufLen - 1; 142 } 143 strncpy(buf, grp, len); 144 buf[len] = '\0'; 145 fclose(fp); 146 return 0; 147 } 148 149 LOGE("Failed to find cpu subsys"); 150 fclose(fp); 151 return -1; 152 out_bad_data: 153 LOGE("Bad cgroup data {%s}", lineBuf); 154 fclose(fp); 155 return -1; 156#else 157 errno = ENOSYS; 158 return -1; 159#endif 160} 161 162int get_sched_policy(int tid, SchedPolicy *policy) 163{ 164 initialize(); 165 166 if (__sys_supports_schedgroups) { 167 char grpBuf[32]; 168 if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0) 169 return -1; 170 if (grpBuf[0] == '\0') { 171 *policy = SP_FOREGROUND; 172 } else if (!strcmp(grpBuf, "bg_non_interactive")) { 173 *policy = SP_BACKGROUND; 174 } else { 175 errno = ERANGE; 176 return -1; 177 } 178 } else { 179 int rc = sched_getscheduler(tid); 180 if (rc < 0) 181 return -1; 182 else if (rc == SCHED_NORMAL) 183 *policy = SP_FOREGROUND; 184 else if (rc == SCHED_BATCH) 185 *policy = SP_BACKGROUND; 186 else { 187 errno = ERANGE; 188 return -1; 189 } 190 } 191 return 0; 192} 193 194int set_sched_policy(int tid, SchedPolicy policy) 195{ 196 initialize(); 197 198#if POLICY_DEBUG 199 char statfile[64]; 200 char statline[1024]; 201 char thread_name[255]; 202 int fd; 203 204 sprintf(statfile, "/proc/%d/stat", tid); 205 memset(thread_name, 0, sizeof(thread_name)); 206 207 fd = open(statfile, O_RDONLY); 208 if (fd >= 0) { 209 int rc = read(fd, statline, 1023); 210 close(fd); 211 statline[rc] = 0; 212 char *p = statline; 213 char *q; 214 215 for (p = statline; *p != '('; p++); 216 p++; 217 for (q = p; *q != ')'; q++); 218 219 strncpy(thread_name, p, (q-p)); 220 } 221 if (policy == SP_BACKGROUND) { 222 LOGD("vvv tid %d (%s)", tid, thread_name); 223 } else if (policy == SP_FOREGROUND) { 224 LOGD("^^^ tid %d (%s)", tid, thread_name); 225 } else { 226 LOGD("??? tid %d (%s)", tid, thread_name); 227 } 228#endif 229 230 if (__sys_supports_schedgroups) { 231 const char *grp = ""; 232 233 if (policy == SP_BACKGROUND) { 234 grp = "bg_non_interactive"; 235 } 236 237 if (add_tid_to_cgroup(tid, grp)) { 238 if (errno != ESRCH && errno != ENOENT) 239 return -errno; 240 } 241 } else { 242 struct sched_param param; 243 244 param.sched_priority = 0; 245 sched_setscheduler(tid, 246 (policy == SP_BACKGROUND) ? 247 SCHED_BATCH : SCHED_NORMAL, 248 ¶m); 249 } 250 251 return 0; 252} 253 254#endif /* HAVE_SCHED_H */ 255