* @brief Get the priority of the current thread using the current platform's native API. This should work on Windows, Linux, and macOS. * * @return An `std::optional` object, optionally containing the priority of the current thread, as a member of the enum `BS::os_thread_priority`. If the returned object does not contain a value, then either the priority could not be determined, or it is
| 1141 | * @return An `std::optional` object, optionally containing the priority of the current thread, as a member of the enum `BS::os_thread_priority`. If the returned object does not contain a value, then either the priority could not be determined, or it is not one of the pre-defined values. |
| 1142 | */ |
| 1143 | [[nodiscard]] static std::optional<os_thread_priority> get_os_thread_priority() |
| 1144 | { |
| 1145 | #if defined(_WIN32) |
| 1146 | // On Windows, this is straightforward. |
| 1147 | const int priority = GetThreadPriority(GetCurrentThread()); |
| 1148 | if (priority == THREAD_PRIORITY_ERROR_RETURN) |
| 1149 | return std::nullopt; |
| 1150 | return static_cast<os_thread_priority>(priority); |
| 1151 | #elif defined(__linux__) |
| 1152 | // On Linux, we distill the choices of scheduling policy, priority, and "nice" value into 7 pre-defined levels, for simplicity and portability. The total number of possible combinations of policies and priorities is much larger, so if the value was set via any means other than `BS::this_thread::set_os_thread_priority()`, it may not match one of our pre-defined values. |
| 1153 | int policy = 0; |
| 1154 | struct sched_param param = {}; |
| 1155 | if (pthread_getschedparam(pthread_self(), &policy, ¶m) != 0) |
| 1156 | return std::nullopt; |
| 1157 | if (policy == SCHED_FIFO && param.sched_priority == sched_get_priority_max(SCHED_FIFO)) |
| 1158 | { |
| 1159 | // The only pre-defined priority that uses SCHED_FIFO and the maximum available priority value is the "realtime" priority. |
| 1160 | return os_thread_priority::realtime; |
| 1161 | } |
| 1162 | if (policy == SCHED_RR && param.sched_priority == sched_get_priority_min(SCHED_RR) + ((sched_get_priority_max(SCHED_RR) - sched_get_priority_min(SCHED_RR)) / 2)) |
| 1163 | { |
| 1164 | // The only pre-defined priority that uses SCHED_RR and a priority in the middle of the available range is the "highest" priority. |
| 1165 | return os_thread_priority::highest; |
| 1166 | } |
| 1167 | #ifdef __linux__ |
| 1168 | if (policy == SCHED_IDLE) |
| 1169 | { |
| 1170 | // The only pre-defined priority that uses SCHED_IDLE is the "idle" priority. Note that this scheduling policy is not available on macOS. |
| 1171 | return os_thread_priority::idle; |
| 1172 | } |
| 1173 | #endif |
| 1174 | if (policy == SCHED_OTHER) |
| 1175 | { |
| 1176 | // For SCHED_OTHER, the result depends on the "nice" value. The usual range is -20 to 19 or 20, with higher values corresponding to lower priorities. Note that `getpriority()` returns -1 on error, but since this does not correspond to any of our pre-defined values, this function will return `std::nullopt` anyway. |
| 1177 | const int nice_val = getpriority(PRIO_PROCESS, static_cast<id_t>(syscall(SYS_gettid))); |
| 1178 | switch (nice_val) |
| 1179 | { |
| 1180 | case PRIO_MIN + 2: |
| 1181 | return os_thread_priority::above_normal; |
| 1182 | case 0: |
| 1183 | return os_thread_priority::normal; |
| 1184 | case (PRIO_MAX / 2) + (PRIO_MAX % 2): |
| 1185 | return os_thread_priority::below_normal; |
| 1186 | case PRIO_MAX - 3: |
| 1187 | return os_thread_priority::lowest; |
| 1188 | #ifdef __APPLE__ |
| 1189 | // `SCHED_IDLE` doesn't exist on macOS, so we use the policy `SCHED_OTHER` with a "nice" value of `PRIO_MAX - 2`. |
| 1190 | case PRIO_MAX - 2: |
| 1191 | return os_thread_priority::idle; |
| 1192 | #endif |
| 1193 | default: |
| 1194 | return std::nullopt; |
| 1195 | } |
| 1196 | } |
| 1197 | return std::nullopt; |
| 1198 | #elif defined(__APPLE__) |
| 1199 | // On macOS, we distill the choices of scheduling policy and priority into 7 pre-defined levels, for simplicity and portability. The total number of possible combinations of policies and priorities is much larger, so if the value was set via any means other than `BS::this_thread::set_os_thread_priority()`, it may not match one of our pre-defined values. |
| 1200 | int policy = 0; |
nothing calls this directly
no outgoing calls
no test coverage detected