NUMA++ 0.12.0
Loading...
Searching...
No Matches
scheduler.hpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup numapp_sched
4 * @brief Contains scheduler declarations
5 * @copyright
6 * SPDX-FileCopyrightText: 2020-2025 European Southern Observatory (ESO)
7 *
8 * SPDX-License-Identifier: LGPL-3.0-only
9 *
10 * @defgroup numapp_sched Scheduler APIs
11 * @ingroup numapp
12 * @brief NUMA++ scheduler APIs
13 *
14 *
15 * See @ref scheduler-api for an overview.
16 */
17#ifndef NUMAPP_SCHEDULER_HPP_
18#define NUMAPP_SCHEDULER_HPP_
19#include <iosfwd>
20#include <system_error>
21#include <variant>
22
23#include <sched.h>
24
25namespace numapp {
26class IdleScheduler;
28class StaticScheduler;
29class Scheduler;
30
31/**
32 * @name Apply Scheduler to Specified Thread
33 *
34 * Applies scheduler to specified thread.
35 */
36/// @{
37
38/**
39 * Apply idle scheduler to specified thread.
40 *
41 * @param thread thread id.
42 * @param scheduler parameters.
43 * @returns 0 on success.
44 * @returns on-zero on failure.
45 *
46 * @relatesalso ::numapp::IdleScheduler
47 * @ingroup numapp_sched
48 * @headerfile <> <numapp/scheduler.hpp>
49 */
50[[nodiscard]] std::error_code Apply(pid_t thread, IdleScheduler const& scheduler) noexcept;
51
52/**
53 * Apply dynamic scheduler to specified thread.
54 *
55 * @param thread thread id.
56 * @param scheduler scheduler parameters.
57 * @returns 0 on success.
58 * @returns on-zero on failure.
59 *
60 * @relatesalso DynamicScheduler
61 * @ingroup numapp_sched
62 * @headerfile <> <numapp/scheduler.hpp>
63 */
64[[nodiscard]] std::error_code Apply(pid_t thread, DynamicScheduler const& scheduler) noexcept;
65
66/**
67 * Apply static scheduler to specified thread.
68 *
69 * @param thread thread id.
70 * @param scheduler scheduler parameters.
71 * @returns 0 on success.
72 * @returns on-zero on failure.
73 *
74 * @relatesalso StaticScheduler
75 * @ingroup numapp_sched
76 * @headerfile <> <numapp/scheduler.hpp>
77 */
78[[nodiscard]] std::error_code Apply(pid_t thread, StaticScheduler const& scheduler) noexcept;
79
80/**
81 * Apply variadic scheduler to specified thread.
82 *
83 * @param thread thread id.
84 * @param scheduler parameters.
85 * @returns 0 on success.
86 * @returns on-zero on failure.
87 *
88 * @relatesalso Scheduler
89 * @ingroup numapp_sched
90 * @headerfile <> <numapp/scheduler.hpp>
91 */
92[[nodiscard]] std::error_code Apply(pid_t thread, Scheduler const& scheduler) noexcept;
93/// @}
94
95namespace thisThread {
96
97/**
98 * @name Apply Scheduler to Current Thread
99 *
100 * Applies specified scheduler to current thread.
101 * @ingroup numapp_sched
102 */
103/// @{
104/**
105 * Apply idle scheduler to @a this thread.
106 *
107 * @param scheduler parameters.
108 * @returns 0 on success.
109 * @returns on-zero on failure.
110 *
111 * @relatesalso numapp::IdleScheduler
112 * @ingroup numapp_sched
113 * @headerfile <> <numapp/scheduler.hpp>
114 */
115[[nodiscard]] std::error_code Apply(IdleScheduler const& scheduler) noexcept;
116
117/**
118 * Apply dynamic scheduler to @a this thread.
119 *
120 * @param scheduler parameters.
121 * @returns 0 on success.
122 * @returns on-zero on failure.
123 *
124 * @relatesalso ::numapp::DynamicScheduler
125 * @ingroup numapp_sched
126 * @headerfile <> <numapp/scheduler.hpp>
127 */
128[[nodiscard]] std::error_code Apply(DynamicScheduler const& scheduler) noexcept;
129
130/**
131 * Apply static scheduler to @a this thread.
132 *
133 * @param scheduler parameters.
134 * @returns 0 on success.
135 * @returns on-zero on failure.
136 *
137 * @relatesalso ::numapp::StaticScheduler
138 * @ingroup numapp_sched
139 * @headerfile <> <numapp/scheduler.hpp>
140 */
141[[nodiscard]] std::error_code Apply(StaticScheduler const& scheduler) noexcept;
142
143/**
144 * Apply variadic scheduler to @a this thread.
145 *
146 * @param scheduler parameters.
147 * @returns 0 on success.
148 * @returns on-zero on failure.
149 *
150 * @relatesalso ::numapp::Scheduler
151 * @ingroup numapp_sched
152 * @headerfile <> <numapp/scheduler.hpp>
153 */
154[[nodiscard]] std::error_code Apply(Scheduler const& scheduler) noexcept;
155/// @}
156}
157
158/**
159 * Represents @c SCHED_IDLE scheduler policy.
160 *
161 * It does not use either dynamic or static priority and is only scheduled to execute if no
162 * other task is ready to run.
163
164 * @manpages
165 * @manpage{sched,7}
166 * @ingroup numapp_sched
167 * @headerfile <> <numapp/scheduler.hpp>
168 */
169class IdleScheduler {
170public:
171 IdleScheduler() noexcept = default;
172 explicit constexpr IdleScheduler(IdleScheduler&&) noexcept = default;
173 explicit constexpr IdleScheduler(IdleScheduler const&) noexcept = default;
174 constexpr IdleScheduler& operator=(IdleScheduler&&) noexcept = default;
175 constexpr IdleScheduler& operator=(IdleScheduler const&) noexcept = default;
176
177 [[nodiscard]] constexpr bool operator==(IdleScheduler const& rhs) const {
178 return true;
179 }
180 [[nodiscard]] bool operator!=(IdleScheduler const& rhs) const {
181 return false;
182 }
183
184 /**
185 * Apply policy to calling thread
186 */
187 [[nodiscard]] std::error_code Apply() const noexcept;
188};
189
190/**
191 * Formats @a scheduler and inserts it to @a os.
192 *
193 * @param os output stream to insert into.
194 * @param scheduler IdleScheduler to format.
195 * @returns @a os
196 *
197 * @relates IdleScheduler
198 */
199std::ostream& operator<<(std::ostream& os, IdleScheduler const& scheduler);
200
201/**
202 * Static priority scheduler (real-time).
203 *
204 * Get and set scheduler for the calling thread.
205 *
206 * The implementation use the pthread API to query and apply policy.
207 *
208 * @par Permissions
209 *
210 * Real-time priority scheduler may require additional permissions provided by `CAP_SYS_NICE` unless
211 * allowed by resource limits (`RLIMIT_RTPRIO`). See also @ref permissions.
212 *
213 * @manpages
214 * @manpage{sched,7}
215 * @ingroup numapp_sched
216 * @headerfile <> <numapp/scheduler.hpp>
217 */
219public:
220 /**
221 * Scheduler policy.
222 */
223 enum class Policy : int {
224 /**
225 * A first-in, first-out "real-time" policy.
226 */
227 Fifo = SCHED_FIFO,
228 /**
229 * A roound-robin, "real-time" policy.
230 */
231 Rr = SCHED_RR
232 };
233
234 /**
235 * Create with provided policy and priority.
236 *
237 * @param policy Scheduler policy.
238 * @param priority Static priority with a valid range of 1 (low) to 99 (high).
239 *
240 * @throw std::system_error containing std::errc::invalid_argument if any argument is invalid.
241 */
242 explicit StaticScheduler(Policy policy, int priority);
243
244 constexpr StaticScheduler(StaticScheduler&&) noexcept = default;
245 constexpr StaticScheduler(StaticScheduler const&) noexcept = default;
246 StaticScheduler& operator=(StaticScheduler&&) noexcept = default;
247 StaticScheduler& operator=(StaticScheduler const&) noexcept = default;
248
249 [[nodiscard]] bool operator==(StaticScheduler const& rhs) const noexcept {
250 return m_policy == rhs.m_policy && m_prio == rhs.m_prio;
251 }
252 [[nodiscard]] bool operator!=(StaticScheduler const& rhs) const noexcept {
253 return !(*this == rhs);
254 }
255
256 /**
257 * Set static priority 0 - 99.
258 * @param priority The priority to use. Valid range is 0 - 99.
259 *
260 * @return std::errc::invalid_argument if @c priority is invalid.
261 */
262 std::error_code SetPriority(int priority);
263
264 /**
265 * Set policy.
266 *
267 * @return std::errc::invalid_argument if policy is invalid.
268 */
269 std::error_code SetPolicy(Policy policy) noexcept;
270
271 /**
272 * Get static priority.
273 */
274 constexpr int GetPriority() const noexcept {
275 return m_prio;
276 }
277
278 /**
279 * @returns policy.
280 */
281 constexpr Policy GetPolicy() const noexcept {
282 return m_policy;
283 }
284
285private:
286 Policy m_policy;
287 int m_prio;
288};
289
290/**
291 * Formats @a scheduler and inserts it to @a os.
292 *
293 * @param os output stream to insert into.
294 * @param scheduler StaticScheduler to format.
295 * @returns @a os
296 *
297 * @relates StaticScheduler
298 */
299std::ostream& operator<<(std::ostream& os, StaticScheduler const& scheduler);
300
301/**
302 * Formats @a policy and inserts it to @a os.
303 *
304 * @param os output stream to insert into.
305 * @param policy Policy to format.
306 * @returns @a os
307 *
308 * @ingroup StaticScheduler
309 * @headerfile <> <numapp/scheduler.hpp>
310 */
311std::ostream& operator<<(std::ostream& os, StaticScheduler::Policy const& policy);
312
313/**
314 * Normal non-realtime scheduler that use dynamic priority (nice value).
315 *
316 * @note The "nice" value is a type of inverse dynamic scheduling priority where lower values (less
317 * nice) have higher priority.
318 *
319 * To apply a lower value requires CAP_SYS_NICE privilege.
320 *
321 * @manpages
322 * @manpage{sched,7}
323 * @manpage{setpriority,2}
324 *
325 * @ingroup numapp_sched
326 * @headerfile <> <numapp/scheduler.hpp>
327 */
329public:
330 /**
331 * Sheduler policy.
332 */
333 enum class Policy : int {
334 /**
335 * The standard round-robin time-sharing policy.
336 *
337 * This is referred to as @c SCHED_NORMAL in the kernel.
338 */
339 Other = SCHED_OTHER,
340 /**
341 * For "batch" style execution of processes.
342 */
343 Batch = SCHED_BATCH,
344 };
345
346 /**
347 * @param policy Scheduling policy.
348 * @param nice Niceness value with range [-20 - 19], where -20 is the highest priority and 19
349 * lowest priority.
350 *
351 * @throws std::system_error with std::errc::invalid_argument on error.
352 */
353 explicit DynamicScheduler(Policy policy = Policy::Other, int nice = 0);
354 constexpr DynamicScheduler(DynamicScheduler const&) noexcept = default;
355 DynamicScheduler& operator=(DynamicScheduler const&) noexcept = default;
356
357 [[nodiscard]] bool operator==(DynamicScheduler rhs) const {
358 return m_policy == rhs.m_policy && m_priority == rhs.m_priority;
359 }
360
361 [[nodiscard]] bool operator!=(DynamicScheduler rhs) const {
362 return !(*this == rhs);
363 }
364
365 /**
366 * Set dynamic nice value (dynamic priority) of thread.
367 *
368 * Higher value means "more" nice and correspondingly lower scheduling priority.
369 *
370 * @param value the dynamic priority. Valid range is [-20 - 19].
371 *
372 * @return std::errc::invalid_argument if value is out of range.
373 */
374 std::error_code SetNice(int value) noexcept;
375
376 /**
377 * Set policy.
378 *
379 * @return std::errc::invalid_argument if policy is invalid.
380 */
381 std::error_code SetPolicy(Policy policy) noexcept;
382
383 /**
384 * Get dynamic nice value.
385 */
386 int GetNice() const noexcept;
387
388 /**
389 * @returns policy.
390 */
391 constexpr Policy GetPolicy() const noexcept {
392 return m_policy;
393 }
394
395private:
396 Policy m_policy;
397 int m_priority;
398};
399
400/**
401 * Formats @a scheduler and inserts it to @a os.
402 *
403 * @param os output stream to insert into.
404 * @param scheduler DynamicScheduler to format.
405 * @returns @a os
406 *
407 * @relates DynamicScheduler
408 */
409std::ostream& operator<<(std::ostream& os, DynamicScheduler const& scheduler);
410
411/**
412 * Formats @a policy and inserts it to @a os.
413 *
414 * @param os output stream to insert into.
415 * @param policy Policy to format.
416 * @returns @a os
417 *
418 * @relates DynamicScheduler
419 */
420std::ostream& operator<<(std::ostream& os, DynamicScheduler const& policy);
421
422/**
423 * Variant of possible schedulers.
424 *
425 * @ingroup numapp_sched
426 * @headerfile <> <numapp/scheduler.hpp>
427 */
428using SchedulerVariant = std::variant<DynamicScheduler, StaticScheduler, IdleScheduler>;
429
430/**
431 * Formats @a scheduler and inserts it to @a os.
432 *
433 * @param os output stream to insert into.
434 * @param scheduler Scheduler to format.
435 * @returns @a os
436 *
437 * @ingroup numapp_sched
438 * @headerfile <> <numapp/scheduler.hpp>
439 */
440std::ostream& operator<<(std::ostream& os, SchedulerVariant const& scheduler);
441
442/**
443 * A sum-type of all supported schedulers.
444 *
445 * @manpages
446 * @manpage{sched,7}
447 *
448 * @ingroup numapp_sched
449 * @headerfile <> <numapp/scheduler.hpp>
450 */
451class Scheduler {
452public:
453 explicit Scheduler(SchedulerVariant const& sched);
454 Scheduler(IdleScheduler sched) noexcept;
455 Scheduler(StaticScheduler sched) noexcept;
456 Scheduler(DynamicScheduler sched) noexcept;
457
458 explicit Scheduler(SchedulerVariant&& sched) noexcept;
459 Scheduler(Scheduler&&) noexcept = default;
460 Scheduler(Scheduler const&) = default;
461
462 Scheduler& operator=(Scheduler&& rhs) noexcept = default;
463 Scheduler& operator=(Scheduler const&) noexcept = default;
464
465 [[nodiscard]] bool operator==(Scheduler const& rhs) const noexcept {
466 return m_scheduler == rhs.m_scheduler;
467 }
468 [[nodiscard]] bool operator!=(Scheduler const& rhs) const noexcept {
469 return !(*this == rhs);
470 }
471
472 /**
473 * Query the held scheduler.
474 *
475 * if (scheduler.HoldsScheduler<IdleScheduler>()) {
476 * // ...
477 * }
478 */
479 template <class T>
480 [[nodiscard]] constexpr bool HoldsScheduler() const noexcept {
481 return std::holds_alternative<T>(m_scheduler);
482 }
483
484 /**
485 * Get the held scheduler.
486 *
487 * idle_scheduler = scheduler.GetScheduler<IdleScheduler>(); // may throw
488 *
489 * @throw std::bad_variant_access if @c T does not match held scheduler.
490 */
491 template <class T>
492 [[nodiscard]] constexpr T GetScheduler() const {
493 return std::get<T>(m_scheduler);
494 }
495
496 /**
497 * Return active scheduler policy for this thread.
498 *
499 * @throws std::system_error with std::errc::not_supported error if unknown policy is found..
500 */
501 [[nodiscard]] static Scheduler MakeFromActive();
502
503 /**
504 * Return active scheduler policy for thread with @a pid.
505 *
506 * @throws std::system_error with std::errc::not_supported error if unknown policy is found..
507 */
508 [[nodiscard]] static Scheduler MakeFromActive(pid_t pid);
509
510 /**
511 * Get the underlying scheduler.
512 */
513 SchedulerVariant const& Get() const noexcept {
514 return m_scheduler;
515 }
516
517 /**
518 * Enable implicit conversion to underlying SchedulerVariant.
519 */
520 operator SchedulerVariant() const noexcept;
521
522private:
523 SchedulerVariant m_scheduler;
524};
525
526/**
527 * Formats @a scheduler and inserts it to @a os.
528 *
529 * @param os output stream to insert into.
530 * @param scheduler Scheduler to format.
531 * @returns @a os
532 *
533 * @relates Scheduler
534 */
535std::ostream& operator<<(std::ostream& os, Scheduler const& scheduler);
536
537} // namespace numapp
538#endif //#ifndef NUMAPP_SCHEDULER_HPP_
Normal non-realtime scheduler that use dynamic priority (nice value).
Policy
Sheduler policy.
@ Batch
For "batch" style execution of processes.
@ Other
The standard round-robin time-sharing policy.
constexpr Policy GetPolicy() const noexcept
DynamicScheduler(Policy policy=Policy::Other, int nice=0)
std::error_code SetNice(int value) noexcept
Set dynamic nice value (dynamic priority) of thread.
std::error_code SetPolicy(Policy policy) noexcept
Set policy.
int GetNice() const noexcept
Get dynamic nice value.
std::ostream & operator<<(std::ostream &os, DynamicScheduler const &scheduler)
Formats scheduler and inserts it to os.
std::ostream & operator<<(std::ostream &os, DynamicScheduler const &policy)
Formats policy and inserts it to os.
Represents SCHED_IDLE scheduler policy.
std::error_code Apply() const noexcept
Apply policy to calling thread.
std::ostream & operator<<(std::ostream &os, IdleScheduler const &scheduler)
Formats scheduler and inserts it to os.
A sum-type of all supported schedulers.
SchedulerVariant const & Get() const noexcept
Get the underlying scheduler.
static Scheduler MakeFromActive()
Return active scheduler policy for this thread.
constexpr T GetScheduler() const
Get the held scheduler.
constexpr bool HoldsScheduler() const noexcept
Query the held scheduler.
static Scheduler MakeFromActive(pid_t pid)
Return active scheduler policy for thread with pid.
Static priority scheduler (real-time).
std::ostream & operator<<(std::ostream &os, StaticScheduler const &scheduler)
Formats scheduler and inserts it to os.
constexpr int GetPriority() const noexcept
Get static priority.
StaticScheduler(Policy policy, int priority)
Create with provided policy and priority.
Policy
Scheduler policy.
@ Fifo
A first-in, first-out "real-time" policy.
@ Rr
A roound-robin, "real-time" policy.
std::error_code SetPriority(int priority)
Set static priority 0 - 99.
constexpr Policy GetPolicy() const noexcept
std::error_code SetPolicy(Policy policy) noexcept
Set policy.
std::error_code Apply(pid_t thread, IdleScheduler const &scheduler) noexcept
Apply idle scheduler to specified thread.
std::variant< DynamicScheduler, StaticScheduler, IdleScheduler > SchedulerVariant
Variant of possible schedulers.
std::error_code Apply(StaticScheduler const &scheduler) noexcept
Apply static scheduler to this thread.
std::error_code Apply(pid_t thread, DynamicScheduler const &scheduler) noexcept
Apply dynamic scheduler to specified thread.
std::error_code Apply(Scheduler const &scheduler) noexcept
Apply variadic scheduler to this thread.
std::error_code Apply(DynamicScheduler const &scheduler) noexcept
Apply dynamic scheduler to this thread.
std::error_code Apply(IdleScheduler const &scheduler) noexcept
Apply idle scheduler to this thread.
std::error_code Apply(pid_t thread, Scheduler const &scheduler) noexcept
Apply variadic scheduler to specified thread.
std::error_code Apply(pid_t thread, StaticScheduler const &scheduler) noexcept
Apply static scheduler to specified thread.