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