sched_policy.c revision d2e4e46ce4bc29c3328fccfbbbe0590eaa8713f7
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 1 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 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 68static inline void initialize() 69{ 70 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 } 77} 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(); 162 163#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 195 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 ¶m); 214 } 215 216 return 0; 217} 218 219#endif /* HAVE_SCHED_H */ 220