1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #pragma once
18
19 #include <algorithm>
20 #include <sys/syscall.h> // SYS_gettid
21 #include <unistd.h> // bionic gettid
22 #include <utils/Errors.h> // status_t
23
24 namespace android::audio_utils {
25
26 /*
27 * Some basic priority definitions from linux,
28 * see MACROs in common/include/linux/sched/prio.h.
29 *
30 * On device limits may be found with the following command $ adb shell chrt -m
31 */
32 inline constexpr int kMaxNice = 19; // inclusive
33 inline constexpr int kMinNice = -20; // inclusive
34 inline constexpr int kNiceWidth = (kMaxNice - kMinNice + 1);
35 inline constexpr int kMinRtPrio = 1; // inclusive
36 inline constexpr int kMaxRtPrio = 100; // [sic] exclusive
37 inline constexpr int kMaxPrio = kMaxRtPrio + kNiceWidth; // [sic] exclusive
38 inline constexpr int kDefaultPrio = kMaxRtPrio + kNiceWidth / 2;
39
40 /*
41 * The following conversion routines follow the linux equivalent.
42 * Here we use the term "unified priority" as the linux normal_prio.
43 *
44 * See common/kernel/sched/core.c __normal_prio().
45 */
46
47 /**
48 * Convert CFS (SCHED_OTHER) nice to unified priority.
49 */
nice_to_unified_priority(int nice)50 inline int nice_to_unified_priority(int nice) {
51 return kDefaultPrio + nice;
52 }
53
54 /**
55 * Convert unified priority to CFS (SCHED_OTHER) nice.
56 *
57 * Some unified priorities are not CFS, they will be clamped in range.
58 * Use is_cfs_priority() to check if a CFS priority.
59 */
unified_priority_to_nice(int priority)60 inline int unified_priority_to_nice(int priority) {
61 return std::clamp(priority - kDefaultPrio, kMinNice, kMaxNice);
62 }
63
64 /**
65 * Convert SCHED_FIFO/SCHED_RR rtprio 1 - 99 to unified priority 98 to 0.
66 */
rtprio_to_unified_priority(int rtprio)67 inline int rtprio_to_unified_priority(int rtprio) {
68 return kMaxRtPrio - 1 - rtprio;
69 }
70
71 /**
72 * Convert unified priority 0 to 98 to SCHED_FIFO/SCHED_RR rtprio 99 to 1.
73 *
74 * Some unified priorities are not real time, they will be clamped in range.
75 * Use is_realtime_priority() to check if real time priority.
76 */
unified_priority_to_rtprio(int priority)77 inline int unified_priority_to_rtprio(int priority) {
78 return std::clamp(kMaxRtPrio - 1 - priority, kMinRtPrio, kMaxRtPrio - 1);
79 }
80
81 /**
82 * Returns whether the unified priority is realtime.
83 */
is_realtime_priority(int priority)84 inline bool is_realtime_priority(int priority) {
85 return priority >= 0 && priority < kMaxRtPrio; // note this allows the unified value 99.
86 }
87
88 /**
89 * Returns whether the unified priority is CFS.
90 */
is_cfs_priority(int priority)91 inline bool is_cfs_priority(int priority) {
92 return priority >= kMaxRtPrio && priority < kMaxPrio;
93 }
94
95 /**
96 * Returns the linux thread id.
97 *
98 * We use gettid() which is available on bionic libc and modern glibc;
99 * for other libc, we syscall directly.
100 *
101 * This is not the same as std::thread::get_id() which returns pthread_self().
102 */
gettid_wrapper()103 pid_t inline gettid_wrapper() {
104 #if defined(__BIONIC__)
105 return ::gettid();
106 #else
107 return syscall(SYS_gettid);
108 #endif
109 }
110
111 /*
112 * set_thread_priority() and get_thread_priority()
113 * both use the unified scheduler priority, where a lower value represents
114 * increasing priority.
115 *
116 * The linux kernel unified scheduler priority values are as follows:
117 * 0 - 98 (A real time priority rtprio between 99 and 1)
118 * 100 - 139 (A Completely Fair Scheduler niceness between -20 and 19)
119 *
120 * Real time schedulers (SCHED_FIFO and SCHED_RR) have rtprio between 1 and 99,
121 * where 1 is the lowest and 99 is the highest.
122 *
123 * The Completely Fair Scheduler (also known as SCHED_OTHER) has a
124 * nice value between 19 and -20, where 19 is the lowest and -20 the highest.
125 *
126 * Note: the unified priority is reported on /proc/<tid>/stat file as "prio".
127 *
128 * See common/kernel/sched/debug.c proc_sched_show_task().
129 */
130
131 /**
132 * Sets the priority of tid to a unified priority.
133 *
134 * The range of priority is 0 through 139, inclusive.
135 * A priority value of 99 is changed to 98.
136 */
137 status_t set_thread_priority(pid_t tid, int priority);
138
139 /**
140 * Returns the unified priority of the tid.
141 *
142 * A negative number represents error.
143 */
144 int get_thread_priority(int tid);
145
146 } // namespace android::audio_utils
147