~nexulockr-dev/nexulockr/android-tools

« back to all changes in this revision

Viewing changes to core/libcutils/sched_policy.c

  • Committer: Ian Santopietro
  • Date: 2014-05-30 17:55:06 UTC
  • Revision ID: isantop@gmail.com-20140530175506-7irb6lx626i8d2j8
Set up proper function for all nexus devices in the Udev rule.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#define LOG_TAG "SchedPolicy"
 
20
 
 
21
#include <stdio.h>
 
22
#include <stdlib.h>
 
23
#include <unistd.h>
 
24
#include <string.h>
 
25
#include <errno.h>
 
26
#include <fcntl.h>
 
27
#include <cutils/sched_policy.h>
 
28
#include <cutils/log.h>
 
29
 
 
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.
 
33
 */
 
34
static inline SchedPolicy _policy(SchedPolicy p)
 
35
{
 
36
   return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
 
37
}
 
38
 
 
39
#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
 
40
 
 
41
#include <sched.h>
 
42
#include <pthread.h>
 
43
 
 
44
#ifndef SCHED_NORMAL
 
45
  #define SCHED_NORMAL 0
 
46
#endif
 
47
 
 
48
#ifndef SCHED_BATCH
 
49
  #define SCHED_BATCH 3
 
50
#endif
 
51
 
 
52
#define POLICY_DEBUG 0
 
53
 
 
54
#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
 
55
 
 
56
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
57
 
 
58
static int __sys_supports_schedgroups = -1;
 
59
 
 
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;
 
63
#if CAN_SET_SP_SYSTEM
 
64
static int system_cgroup_fd = -1;
 
65
#endif
 
66
 
 
67
/* Add tid to the scheduling group defined by the policy */
 
68
static int add_tid_to_cgroup(int tid, SchedPolicy policy)
 
69
{
 
70
    int fd;
 
71
 
 
72
    switch (policy) {
 
73
    case SP_BACKGROUND:
 
74
        fd = bg_cgroup_fd;
 
75
        break;
 
76
    case SP_FOREGROUND:
 
77
    case SP_AUDIO_APP:
 
78
    case SP_AUDIO_SYS:
 
79
        fd = fg_cgroup_fd;
 
80
        break;
 
81
#if CAN_SET_SP_SYSTEM
 
82
    case SP_SYSTEM:
 
83
        fd = system_cgroup_fd;
 
84
        break;
 
85
#endif
 
86
    default:
 
87
        fd = -1;
 
88
        break;
 
89
    }
 
90
 
 
91
    if (fd < 0) {
 
92
        SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
 
93
        return -1;
 
94
    }
 
95
 
 
96
    // specialized itoa -- works for tid > 0
 
97
    char text[22];
 
98
    char *end = text + sizeof(text) - 1;
 
99
    char *ptr = end;
 
100
    *ptr = '\0';
 
101
    while (tid > 0) {
 
102
        *--ptr = '0' + (tid % 10);
 
103
        tid = tid / 10;
 
104
    }
 
105
 
 
106
    if (write(fd, ptr, end - ptr) < 0) {
 
107
        /*
 
108
         * If the thread is in the process of exiting,
 
109
         * don't flag an error
 
110
         */
 
111
        if (errno == ESRCH)
 
112
                return 0;
 
113
        SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
 
114
              ptr, strerror(errno), policy);
 
115
        return -1;
 
116
    }
 
117
 
 
118
    return 0;
 
119
}
 
120
 
 
121
static void __initialize(void) {
 
122
    char* filename;
 
123
    if (!access("/dev/cpuctl/tasks", F_OK)) {
 
124
        __sys_supports_schedgroups = 1;
 
125
 
 
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));
 
131
        }
 
132
#endif
 
133
 
 
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));
 
138
        }
 
139
 
 
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));
 
144
        }
 
145
    } else {
 
146
        __sys_supports_schedgroups = 0;
 
147
    }
 
148
}
 
149
 
 
150
/*
 
151
 * Try to get the scheduler group.
 
152
 *
 
153
 * The data from /proc/<pid>/cgroup looks (something) like:
 
154
 *  2:cpu:/bg_non_interactive
 
155
 *  1:cpuacct:/
 
156
 *
 
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
 
159
 * will be truncated.
 
160
 */
 
161
static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
 
162
{
 
163
#ifdef HAVE_ANDROID_OS
 
164
    char pathBuf[32];
 
165
    char lineBuf[256];
 
166
    FILE *fp;
 
167
 
 
168
    snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
 
169
    if (!(fp = fopen(pathBuf, "r"))) {
 
170
        return -1;
 
171
    }
 
172
 
 
173
    while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
 
174
        char *next = lineBuf;
 
175
        char *subsys;
 
176
        char *grp;
 
177
        size_t len;
 
178
 
 
179
        /* Junk the first field */
 
180
        if (!strsep(&next, ":")) {
 
181
            goto out_bad_data;
 
182
        }
 
183
 
 
184
        if (!(subsys = strsep(&next, ":"))) {
 
185
            goto out_bad_data;
 
186
        }
 
187
 
 
188
        if (strcmp(subsys, "cpu")) {
 
189
            /* Not the subsys we're looking for */
 
190
            continue;
 
191
        }
 
192
 
 
193
        if (!(grp = strsep(&next, ":"))) {
 
194
            goto out_bad_data;
 
195
        }
 
196
        grp++; /* Drop the leading '/' */
 
197
        len = strlen(grp);
 
198
        grp[len-1] = '\0'; /* Drop the trailing '\n' */
 
199
 
 
200
        if (bufLen <= len) {
 
201
            len = bufLen - 1;
 
202
        }
 
203
        strncpy(buf, grp, len);
 
204
        buf[len] = '\0';
 
205
        fclose(fp);
 
206
        return 0;
 
207
    }
 
208
 
 
209
    SLOGE("Failed to find cpu subsys");
 
210
    fclose(fp);
 
211
    return -1;
 
212
 out_bad_data:
 
213
    SLOGE("Bad cgroup data {%s}", lineBuf);
 
214
    fclose(fp);
 
215
    return -1;
 
216
#else
 
217
    errno = ENOSYS;
 
218
    return -1;
 
219
#endif
 
220
}
 
221
 
 
222
int get_sched_policy(int tid, SchedPolicy *policy)
 
223
{
 
224
#ifdef HAVE_GETTID
 
225
    if (tid == 0) {
 
226
        tid = gettid();
 
227
    }
 
228
#endif
 
229
    pthread_once(&the_once, __initialize);
 
230
 
 
231
    if (__sys_supports_schedgroups) {
 
232
        char grpBuf[32];
 
233
        if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
 
234
            return -1;
 
235
        if (grpBuf[0] == '\0') {
 
236
            *policy = SP_SYSTEM;
 
237
        } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
 
238
            *policy = SP_BACKGROUND;
 
239
        } else if (!strcmp(grpBuf, "apps")) {
 
240
            *policy = SP_FOREGROUND;
 
241
        } else {
 
242
            errno = ERANGE;
 
243
            return -1;
 
244
        }
 
245
    } else {
 
246
        int rc = sched_getscheduler(tid);
 
247
        if (rc < 0)
 
248
            return -1;
 
249
        else if (rc == SCHED_NORMAL)
 
250
            *policy = SP_FOREGROUND;
 
251
        else if (rc == SCHED_BATCH)
 
252
            *policy = SP_BACKGROUND;
 
253
        else {
 
254
            errno = ERANGE;
 
255
            return -1;
 
256
        }
 
257
    }
 
258
    return 0;
 
259
}
 
260
 
 
261
int set_sched_policy(int tid, SchedPolicy policy)
 
262
{
 
263
#ifdef HAVE_GETTID
 
264
    if (tid == 0) {
 
265
        tid = gettid();
 
266
    }
 
267
#endif
 
268
    policy = _policy(policy);
 
269
    pthread_once(&the_once, __initialize);
 
270
 
 
271
#if POLICY_DEBUG
 
272
    char statfile[64];
 
273
    char statline[1024];
 
274
    char thread_name[255];
 
275
    int fd;
 
276
 
 
277
    sprintf(statfile, "/proc/%d/stat", tid);
 
278
    memset(thread_name, 0, sizeof(thread_name));
 
279
 
 
280
    fd = open(statfile, O_RDONLY);
 
281
    if (fd >= 0) {
 
282
        int rc = read(fd, statline, 1023);
 
283
        close(fd);
 
284
        statline[rc] = 0;
 
285
        char *p = statline;
 
286
        char *q;
 
287
 
 
288
        for (p = statline; *p != '('; p++);
 
289
        p++;
 
290
        for (q = p; *q != ')'; q++);
 
291
 
 
292
        strncpy(thread_name, p, (q-p));
 
293
    }
 
294
    switch (policy) {
 
295
    case SP_BACKGROUND:
 
296
        SLOGD("vvv tid %d (%s)", tid, thread_name);
 
297
        break;
 
298
    case SP_FOREGROUND:
 
299
    case SP_AUDIO_APP:
 
300
    case SP_AUDIO_SYS:
 
301
        SLOGD("^^^ tid %d (%s)", tid, thread_name);
 
302
        break;
 
303
    case SP_SYSTEM:
 
304
        SLOGD("/// tid %d (%s)", tid, thread_name);
 
305
        break;
 
306
    default:
 
307
        SLOGD("??? tid %d (%s)", tid, thread_name);
 
308
        break;
 
309
    }
 
310
#endif
 
311
 
 
312
    if (__sys_supports_schedgroups) {
 
313
        if (add_tid_to_cgroup(tid, policy)) {
 
314
            if (errno != ESRCH && errno != ENOENT)
 
315
                return -errno;
 
316
        }
 
317
    } else {
 
318
        struct sched_param param;
 
319
 
 
320
        param.sched_priority = 0;
 
321
        sched_setscheduler(tid,
 
322
                           (policy == SP_BACKGROUND) ?
 
323
                            SCHED_BATCH : SCHED_NORMAL,
 
324
                           &param);
 
325
    }
 
326
 
 
327
    return 0;
 
328
}
 
329
 
 
330
#else
 
331
 
 
332
/* Stubs for non-Android targets. */
 
333
 
 
334
int set_sched_policy(int tid, SchedPolicy policy)
 
335
{
 
336
    return 0;
 
337
}
 
338
 
 
339
int get_sched_policy(int tid, SchedPolicy *policy)
 
340
{
 
341
    *policy = SP_SYSTEM_DEFAULT;
 
342
    return 0;
 
343
}
 
344
 
 
345
#endif
 
346
 
 
347
const char *get_sched_policy_name(SchedPolicy policy)
 
348
{
 
349
    policy = _policy(policy);
 
350
    static const char * const strings[SP_CNT] = {
 
351
       [SP_BACKGROUND] = "bg",
 
352
       [SP_FOREGROUND] = "fg",
 
353
       [SP_SYSTEM]     = "  ",
 
354
       [SP_AUDIO_APP]  = "aa",
 
355
       [SP_AUDIO_SYS]  = "as",
 
356
    };
 
357
    if ((policy < SP_CNT) && (strings[policy] != NULL))
 
358
        return strings[policy];
 
359
    else
 
360
        return "error";
 
361
}
 
362