~mir-team/mir/in-process-egl+input-conglomeration

« back to all changes in this revision

Viewing changes to 3rd_party/android-input/android_pristine/system/core/libcutils/sched_policy.c

Merged trunk and fixed issues

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